162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * fs/hmdfs/hmdfs_dentryfile_cloud.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2023-2023 Huawei Device Co., Ltd. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include "hmdfs_dentryfile_cloud.h" 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/slab.h> 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_civoid hmdfs_init_dcache_lookup_ctx_cloud( 1362306a36Sopenharmony_ci struct hmdfs_dcache_lookup_ctx_cloud *ctx, struct hmdfs_sb_info *sbi, 1462306a36Sopenharmony_ci const struct qstr *qstr, struct file *filp) 1562306a36Sopenharmony_ci{ 1662306a36Sopenharmony_ci ctx->sbi = sbi; 1762306a36Sopenharmony_ci ctx->name = qstr; 1862306a36Sopenharmony_ci ctx->filp = filp; 1962306a36Sopenharmony_ci ctx->bidx = 0; 2062306a36Sopenharmony_ci ctx->page = NULL; 2162306a36Sopenharmony_ci ctx->insense_de = NULL; 2262306a36Sopenharmony_ci ctx->insense_bidx = 0; 2362306a36Sopenharmony_ci ctx->insense_page = NULL; 2462306a36Sopenharmony_ci} 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_cistatic struct hmdfs_dentry_group_cloud *find_dentry_page(struct hmdfs_sb_info *sbi, 2762306a36Sopenharmony_ci pgoff_t index, struct file *filp) 2862306a36Sopenharmony_ci{ 2962306a36Sopenharmony_ci int size; 3062306a36Sopenharmony_ci struct hmdfs_dentry_group_cloud *dentry_blk = NULL; 3162306a36Sopenharmony_ci loff_t pos = get_dentry_group_pos(index); 3262306a36Sopenharmony_ci int err; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci dentry_blk = kmalloc(sizeof(*dentry_blk), GFP_KERNEL); 3562306a36Sopenharmony_ci if (!dentry_blk) 3662306a36Sopenharmony_ci return NULL; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci err = hmdfs_wlock_file(filp, pos, DENTRYGROUP_SIZE); 3962306a36Sopenharmony_ci if (err) { 4062306a36Sopenharmony_ci hmdfs_err("lock file pos %lld failed %d", pos, err); 4162306a36Sopenharmony_ci kfree(dentry_blk); 4262306a36Sopenharmony_ci return NULL; 4362306a36Sopenharmony_ci } 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci size = kernel_read(filp, dentry_blk, (size_t)DENTRYGROUP_SIZE, 4662306a36Sopenharmony_ci &pos); 4762306a36Sopenharmony_ci if (size != DENTRYGROUP_SIZE) { 4862306a36Sopenharmony_ci hmdfs_err("read pos %lld failed %d", pos, size); 4962306a36Sopenharmony_ci hmdfs_unlock_file(filp, pos, DENTRYGROUP_SIZE); 5062306a36Sopenharmony_ci kfree(dentry_blk); 5162306a36Sopenharmony_ci dentry_blk = NULL; 5262306a36Sopenharmony_ci } 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci return dentry_blk; 5562306a36Sopenharmony_ci} 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_cistatic struct hmdfs_dentry_cloud * 5862306a36Sopenharmony_cifind_in_block(struct hmdfs_dentry_group_cloud *dentry_blk, __u32 namehash, 5962306a36Sopenharmony_ci const struct qstr *qstr, struct hmdfs_dentry_cloud **insense_de, 6062306a36Sopenharmony_ci bool case_sense) 6162306a36Sopenharmony_ci{ 6262306a36Sopenharmony_ci struct hmdfs_dentry_cloud *de; 6362306a36Sopenharmony_ci unsigned long bit_pos = 0; 6462306a36Sopenharmony_ci int max_len = 0; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci while (bit_pos < DENTRY_PER_GROUP_CLOUD) { 6762306a36Sopenharmony_ci if (!test_bit_le(bit_pos, dentry_blk->bitmap)) { 6862306a36Sopenharmony_ci bit_pos++; 6962306a36Sopenharmony_ci max_len++; 7062306a36Sopenharmony_ci continue; 7162306a36Sopenharmony_ci } 7262306a36Sopenharmony_ci de = &dentry_blk->nsl[bit_pos]; 7362306a36Sopenharmony_ci if (unlikely(!de->namelen)) { 7462306a36Sopenharmony_ci bit_pos++; 7562306a36Sopenharmony_ci continue; 7662306a36Sopenharmony_ci } 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci if (le32_to_cpu(de->hash) == namehash && 7962306a36Sopenharmony_ci le16_to_cpu(de->namelen) == qstr->len && 8062306a36Sopenharmony_ci !memcmp(qstr->name, dentry_blk->filename[bit_pos], 8162306a36Sopenharmony_ci le16_to_cpu(de->namelen))) 8262306a36Sopenharmony_ci goto found; 8362306a36Sopenharmony_ci if (!(*insense_de) && !case_sense && 8462306a36Sopenharmony_ci le32_to_cpu(de->hash) == namehash && 8562306a36Sopenharmony_ci le16_to_cpu(de->namelen) == qstr->len && 8662306a36Sopenharmony_ci str_n_case_eq(qstr->name, dentry_blk->filename[bit_pos], 8762306a36Sopenharmony_ci le16_to_cpu(de->namelen))) 8862306a36Sopenharmony_ci *insense_de = de; 8962306a36Sopenharmony_ci max_len = 0; 9062306a36Sopenharmony_ci bit_pos += get_dentry_slots(le16_to_cpu(de->namelen)); 9162306a36Sopenharmony_ci } 9262306a36Sopenharmony_ci de = NULL; 9362306a36Sopenharmony_cifound: 9462306a36Sopenharmony_ci return de; 9562306a36Sopenharmony_ci} 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_cistatic struct hmdfs_dentry_cloud * 9862306a36Sopenharmony_cihmdfs_in_level(struct dentry *child_dentry, unsigned int level, 9962306a36Sopenharmony_ci struct hmdfs_dcache_lookup_ctx_cloud *ctx) 10062306a36Sopenharmony_ci{ 10162306a36Sopenharmony_ci unsigned long nbucket; 10262306a36Sopenharmony_ci unsigned long bidx, end_block; 10362306a36Sopenharmony_ci struct hmdfs_dentry_cloud *de = NULL; 10462306a36Sopenharmony_ci struct hmdfs_dentry_cloud *tmp_insense_de = NULL; 10562306a36Sopenharmony_ci struct hmdfs_dentry_group_cloud *dentry_blk; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci nbucket = get_bucket_by_level(level); 10862306a36Sopenharmony_ci if (!nbucket) 10962306a36Sopenharmony_ci return de; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci bidx = get_bucketaddr(level, ctx->hash % nbucket) * BUCKET_BLOCKS; 11262306a36Sopenharmony_ci end_block = bidx + BUCKET_BLOCKS; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci for (; bidx < end_block; bidx++) { 11562306a36Sopenharmony_ci dentry_blk = find_dentry_page(ctx->sbi, bidx, ctx->filp); 11662306a36Sopenharmony_ci if (!dentry_blk) 11762306a36Sopenharmony_ci break; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci de = find_in_block(dentry_blk, ctx->hash, ctx->name, 12062306a36Sopenharmony_ci &tmp_insense_de, ctx->sbi->s_case_sensitive); 12162306a36Sopenharmony_ci if (!de && !(ctx->insense_de) && tmp_insense_de) { 12262306a36Sopenharmony_ci ctx->insense_de = tmp_insense_de; 12362306a36Sopenharmony_ci ctx->insense_page = dentry_blk; 12462306a36Sopenharmony_ci ctx->insense_bidx = bidx; 12562306a36Sopenharmony_ci } else if (!de) { 12662306a36Sopenharmony_ci hmdfs_unlock_file(ctx->filp, get_dentry_group_pos(bidx), 12762306a36Sopenharmony_ci DENTRYGROUP_SIZE); 12862306a36Sopenharmony_ci kfree(dentry_blk); 12962306a36Sopenharmony_ci } else { 13062306a36Sopenharmony_ci ctx->page = dentry_blk; 13162306a36Sopenharmony_ci break; 13262306a36Sopenharmony_ci } 13362306a36Sopenharmony_ci } 13462306a36Sopenharmony_ci ctx->bidx = bidx; 13562306a36Sopenharmony_ci return de; 13662306a36Sopenharmony_ci} 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_cistruct hmdfs_dentry_cloud * 13962306a36Sopenharmony_cihmdfs_find_dentry_cloud(struct dentry *child_dentry, 14062306a36Sopenharmony_ci struct hmdfs_dcache_lookup_ctx_cloud *ctx) 14162306a36Sopenharmony_ci{ 14262306a36Sopenharmony_ci struct hmdfs_dentry_cloud *de = NULL; 14362306a36Sopenharmony_ci unsigned int max_depth; 14462306a36Sopenharmony_ci unsigned int level; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci if (!ctx->filp) 14762306a36Sopenharmony_ci return NULL; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci ctx->hash = hmdfs_dentry_hash(ctx->name, ctx->sbi->s_case_sensitive); 15062306a36Sopenharmony_ci max_depth = get_max_depth(ctx->filp); 15162306a36Sopenharmony_ci for (level = 0; level < max_depth; level++) { 15262306a36Sopenharmony_ci de = hmdfs_in_level(child_dentry, level, ctx); 15362306a36Sopenharmony_ci if (de) { 15462306a36Sopenharmony_ci if (ctx->insense_page) { 15562306a36Sopenharmony_ci hmdfs_unlock_file(ctx->filp, 15662306a36Sopenharmony_ci get_dentry_group_pos(ctx->insense_bidx), 15762306a36Sopenharmony_ci DENTRYGROUP_SIZE); 15862306a36Sopenharmony_ci kfree(ctx->insense_page); 15962306a36Sopenharmony_ci ctx->insense_page = NULL; 16062306a36Sopenharmony_ci } 16162306a36Sopenharmony_ci return de; 16262306a36Sopenharmony_ci } 16362306a36Sopenharmony_ci } 16462306a36Sopenharmony_ci if (ctx->insense_de) { 16562306a36Sopenharmony_ci ctx->bidx = ctx->insense_bidx; 16662306a36Sopenharmony_ci ctx->page = ctx->insense_page; 16762306a36Sopenharmony_ci ctx->insense_bidx = 0; 16862306a36Sopenharmony_ci ctx->insense_page = NULL; 16962306a36Sopenharmony_ci } 17062306a36Sopenharmony_ci return ctx->insense_de; 17162306a36Sopenharmony_ci} 172