/* 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 */