121 lines
2.9 KiB
C
121 lines
2.9 KiB
C
|
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||
|
|
/*
|
||
|
|
* Copyright (C) 2021. Huawei Technologies Co., Ltd. All rights reserved.
|
||
|
|
* This program is free software; you can redistribute it and/or modify
|
||
|
|
* it under the terms of the GNU General Public License version 2 and
|
||
|
|
* only version 2 as published by the Free Software Foundation.
|
||
|
|
*
|
||
|
|
* This program is distributed in the hope that it will be useful,
|
||
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
|
* GNU General Public License for more details.
|
||
|
|
*/
|
||
|
|
|
||
|
|
#ifndef EUFS_FILENAME_H
|
||
|
|
#define EUFS_FILENAME_H
|
||
|
|
|
||
|
|
#include "alloc_interface.h"
|
||
|
|
|
||
|
|
/* ========== filenames ========== */
|
||
|
|
static __always_inline void eufs_free_name(struct super_block *sb,
|
||
|
|
struct nv_dict_entry *de)
|
||
|
|
{
|
||
|
|
size_t len = HASHLEN_LEN(de->hv);
|
||
|
|
struct nv_name_ext *p;
|
||
|
|
struct nv_name_ext *next;
|
||
|
|
|
||
|
|
if (likely(len <= FIRST_LEN))
|
||
|
|
return;
|
||
|
|
p = s2p(sb, de->nextname);
|
||
|
|
len -= FIRST_LEN;
|
||
|
|
while (len > FOLLOW_LEN) {
|
||
|
|
next = s2p(sb, p->nextname);
|
||
|
|
nv_free(sb, p);
|
||
|
|
len -= FOLLOW_LEN;
|
||
|
|
p = next;
|
||
|
|
}
|
||
|
|
nv_free(sb, p);
|
||
|
|
}
|
||
|
|
|
||
|
|
/* precondition: ext != NULL */
|
||
|
|
/* Use with `eufs_free_page(page);` */
|
||
|
|
static __always_inline void *
|
||
|
|
eufs_alloc_name_copy(struct super_block *sb, const char *name, size_t namelen,
|
||
|
|
const struct nv_name_ext *ext)
|
||
|
|
{
|
||
|
|
char *page;
|
||
|
|
char *p;
|
||
|
|
size_t len;
|
||
|
|
|
||
|
|
NV_ASSERT(namelen > FIRST_LEN);
|
||
|
|
NV_ASSERT(namelen <= EUFS_MAX_NAME_LEN);
|
||
|
|
|
||
|
|
page = eufs_alloc_page();
|
||
|
|
p = page;
|
||
|
|
memcpy(p, name, FIRST_LEN);
|
||
|
|
len = namelen - FIRST_LEN;
|
||
|
|
p += FIRST_LEN;
|
||
|
|
name = ext->name;
|
||
|
|
while (len > FOLLOW_LEN) {
|
||
|
|
memcpy(p, name, FOLLOW_LEN);
|
||
|
|
ext = s2p(sb, ext->nextname);
|
||
|
|
name = ext->name;
|
||
|
|
p += FOLLOW_LEN;
|
||
|
|
len -= FOLLOW_LEN;
|
||
|
|
}
|
||
|
|
memcpy(p, name, len);
|
||
|
|
*(char *)(p + len) = 0;
|
||
|
|
return page;
|
||
|
|
}
|
||
|
|
/* TODO: Handle allocation failure */
|
||
|
|
static __always_inline int copy_filename(struct super_block *sb,
|
||
|
|
struct nv_dict_entry *de, hashlen_t hv,
|
||
|
|
const char *name)
|
||
|
|
{
|
||
|
|
void *ext_pages[6];
|
||
|
|
int n_ext_pages;
|
||
|
|
struct nv_name_ext *p;
|
||
|
|
struct nv_name_ext *new_p;
|
||
|
|
size_t len = HASHLEN_LEN(hv);
|
||
|
|
|
||
|
|
BUILD_BUG_ON(FIRST_LEN + FOLLOW_LEN * 6 < EUFS_MAX_NAME_LEN);
|
||
|
|
BUG_ON(len > EUFS_MAX_NAME_LEN);
|
||
|
|
|
||
|
|
de->hv = hv;
|
||
|
|
if (likely(len <= FIRST_LEN)) {
|
||
|
|
memcpy(de->name, name, len);
|
||
|
|
de->nextname = cpu_to_le64(EUFS_POISON_POINTER);
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
n_ext_pages = 0;
|
||
|
|
memcpy(de->name, name, FIRST_LEN);
|
||
|
|
p = eufs_malloc_name_ext(sb);
|
||
|
|
de->nextname = p2s(sb, p);
|
||
|
|
if (!p)
|
||
|
|
goto NO_SPC;
|
||
|
|
ext_pages[n_ext_pages++] = p;
|
||
|
|
name += FIRST_LEN;
|
||
|
|
len -= FIRST_LEN;
|
||
|
|
|
||
|
|
while (len > FOLLOW_LEN) {
|
||
|
|
memcpy(p->name, name, FOLLOW_LEN);
|
||
|
|
name += FOLLOW_LEN;
|
||
|
|
len -= FOLLOW_LEN;
|
||
|
|
new_p = eufs_malloc_name_ext(sb);
|
||
|
|
p->nextname = p2s(sb, new_p);
|
||
|
|
p = new_p;
|
||
|
|
if (!p)
|
||
|
|
goto NO_SPC;
|
||
|
|
ext_pages[n_ext_pages++] = p;
|
||
|
|
}
|
||
|
|
memcpy(p->name, name, len);
|
||
|
|
p->nextname = cpu_to_le64(EUFS_POISON_POINTER);
|
||
|
|
return 0;
|
||
|
|
NO_SPC:
|
||
|
|
while (n_ext_pages)
|
||
|
|
nv_free(sb, ext_pages[--n_ext_pages]);
|
||
|
|
return -ENOSPC;
|
||
|
|
}
|
||
|
|
|
||
|
|
#endif /* EUFS_FILENAME_H */
|