1// SPDX-License-Identifier: GPL-2.0 2/* 3 * fs/hmdfs/hmdfs_dentryfile_cloud.c 4 * 5 * Copyright (c) 2023-2023 Huawei Device Co., Ltd. 6 */ 7 8#include "hmdfs_dentryfile_cloud.h" 9 10#include <linux/slab.h> 11 12void hmdfs_init_dcache_lookup_ctx_cloud( 13 struct hmdfs_dcache_lookup_ctx_cloud *ctx, struct hmdfs_sb_info *sbi, 14 const struct qstr *qstr, struct file *filp) 15{ 16 ctx->sbi = sbi; 17 ctx->name = qstr; 18 ctx->filp = filp; 19 ctx->bidx = 0; 20 ctx->page = NULL; 21 ctx->insense_de = NULL; 22 ctx->insense_bidx = 0; 23 ctx->insense_page = NULL; 24} 25 26static struct hmdfs_dentry_group_cloud *find_dentry_page(struct hmdfs_sb_info *sbi, 27 pgoff_t index, struct file *filp) 28{ 29 int size; 30 struct hmdfs_dentry_group_cloud *dentry_blk = NULL; 31 loff_t pos = get_dentry_group_pos(index); 32 int err; 33 34 dentry_blk = kmalloc(sizeof(*dentry_blk), GFP_KERNEL); 35 if (!dentry_blk) 36 return NULL; 37 38 err = hmdfs_wlock_file(filp, pos, DENTRYGROUP_SIZE); 39 if (err) { 40 hmdfs_err("lock file pos %lld failed %d", pos, err); 41 kfree(dentry_blk); 42 return NULL; 43 } 44 45 size = kernel_read(filp, dentry_blk, (size_t)DENTRYGROUP_SIZE, 46 &pos); 47 if (size != DENTRYGROUP_SIZE) { 48 hmdfs_err("read pos %lld failed %d", pos, size); 49 hmdfs_unlock_file(filp, pos, DENTRYGROUP_SIZE); 50 kfree(dentry_blk); 51 dentry_blk = NULL; 52 } 53 54 return dentry_blk; 55} 56 57static struct hmdfs_dentry_cloud * 58find_in_block(struct hmdfs_dentry_group_cloud *dentry_blk, __u32 namehash, 59 const struct qstr *qstr, struct hmdfs_dentry_cloud **insense_de, 60 bool case_sense) 61{ 62 struct hmdfs_dentry_cloud *de; 63 unsigned long bit_pos = 0; 64 int max_len = 0; 65 66 while (bit_pos < DENTRY_PER_GROUP_CLOUD) { 67 if (!test_bit_le(bit_pos, dentry_blk->bitmap)) { 68 bit_pos++; 69 max_len++; 70 continue; 71 } 72 de = &dentry_blk->nsl[bit_pos]; 73 if (unlikely(!de->namelen)) { 74 bit_pos++; 75 continue; 76 } 77 78 if (le32_to_cpu(de->hash) == namehash && 79 le16_to_cpu(de->namelen) == qstr->len && 80 !memcmp(qstr->name, dentry_blk->filename[bit_pos], 81 le16_to_cpu(de->namelen))) 82 goto found; 83 if (!(*insense_de) && !case_sense && 84 le32_to_cpu(de->hash) == namehash && 85 le16_to_cpu(de->namelen) == qstr->len && 86 str_n_case_eq(qstr->name, dentry_blk->filename[bit_pos], 87 le16_to_cpu(de->namelen))) 88 *insense_de = de; 89 max_len = 0; 90 bit_pos += get_dentry_slots(le16_to_cpu(de->namelen)); 91 } 92 de = NULL; 93found: 94 return de; 95} 96 97static struct hmdfs_dentry_cloud * 98hmdfs_in_level(struct dentry *child_dentry, unsigned int level, 99 struct hmdfs_dcache_lookup_ctx_cloud *ctx) 100{ 101 unsigned long nbucket; 102 unsigned long bidx, end_block; 103 struct hmdfs_dentry_cloud *de = NULL; 104 struct hmdfs_dentry_cloud *tmp_insense_de = NULL; 105 struct hmdfs_dentry_group_cloud *dentry_blk; 106 107 nbucket = get_bucket_by_level(level); 108 if (!nbucket) 109 return de; 110 111 bidx = get_bucketaddr(level, ctx->hash % nbucket) * BUCKET_BLOCKS; 112 end_block = bidx + BUCKET_BLOCKS; 113 114 for (; bidx < end_block; bidx++) { 115 dentry_blk = find_dentry_page(ctx->sbi, bidx, ctx->filp); 116 if (!dentry_blk) 117 break; 118 119 de = find_in_block(dentry_blk, ctx->hash, ctx->name, 120 &tmp_insense_de, ctx->sbi->s_case_sensitive); 121 if (!de && !(ctx->insense_de) && tmp_insense_de) { 122 ctx->insense_de = tmp_insense_de; 123 ctx->insense_page = dentry_blk; 124 ctx->insense_bidx = bidx; 125 } else if (!de) { 126 hmdfs_unlock_file(ctx->filp, get_dentry_group_pos(bidx), 127 DENTRYGROUP_SIZE); 128 kfree(dentry_blk); 129 } else { 130 ctx->page = dentry_blk; 131 break; 132 } 133 } 134 ctx->bidx = bidx; 135 return de; 136} 137 138struct hmdfs_dentry_cloud * 139hmdfs_find_dentry_cloud(struct dentry *child_dentry, 140 struct hmdfs_dcache_lookup_ctx_cloud *ctx) 141{ 142 struct hmdfs_dentry_cloud *de = NULL; 143 unsigned int max_depth; 144 unsigned int level; 145 146 if (!ctx->filp) 147 return NULL; 148 149 ctx->hash = hmdfs_dentry_hash(ctx->name, ctx->sbi->s_case_sensitive); 150 max_depth = get_max_depth(ctx->filp); 151 for (level = 0; level < max_depth; level++) { 152 de = hmdfs_in_level(child_dentry, level, ctx); 153 if (de) { 154 if (ctx->insense_page) { 155 hmdfs_unlock_file(ctx->filp, 156 get_dentry_group_pos(ctx->insense_bidx), 157 DENTRYGROUP_SIZE); 158 kfree(ctx->insense_page); 159 ctx->insense_page = NULL; 160 } 161 return de; 162 } 163 } 164 if (ctx->insense_de) { 165 ctx->bidx = ctx->insense_bidx; 166 ctx->page = ctx->insense_page; 167 ctx->insense_bidx = 0; 168 ctx->insense_page = NULL; 169 } 170 return ctx->insense_de; 171} 172