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
hmdfs_init_dcache_lookup_ctx_cloud(struct hmdfs_dcache_lookup_ctx_cloud * ctx,struct hmdfs_sb_info * sbi,const struct qstr * qstr,struct file * filp)12 void 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
find_dentry_page(struct hmdfs_sb_info * sbi,pgoff_t index,struct file * filp)26 static 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", pos);
41 kfree(dentry_blk);
42 return NULL;
43 }
44
45 size = cache_file_read(sbi, filp, dentry_blk, (size_t)DENTRYGROUP_SIZE,
46 &pos);
47 if (size != DENTRYGROUP_SIZE) {
48 kfree(dentry_blk);
49 dentry_blk = NULL;
50 }
51
52 return dentry_blk;
53 }
54
55 static struct hmdfs_dentry_cloud *
find_in_block(struct hmdfs_dentry_group_cloud * dentry_blk,__u32 namehash,const struct qstr * qstr,struct hmdfs_dentry_cloud ** insense_de,bool case_sense)56 find_in_block(struct hmdfs_dentry_group_cloud *dentry_blk, __u32 namehash,
57 const struct qstr *qstr, struct hmdfs_dentry_cloud **insense_de,
58 bool case_sense)
59 {
60 struct hmdfs_dentry_cloud *de;
61 unsigned long bit_pos = 0;
62 int max_len = 0;
63
64 while (bit_pos < DENTRY_PER_GROUP_CLOUD) {
65 if (!test_bit_le(bit_pos, dentry_blk->bitmap)) {
66 bit_pos++;
67 max_len++;
68 }
69 de = &dentry_blk->nsl[bit_pos];
70 if (unlikely(!de->namelen)) {
71 bit_pos++;
72 continue;
73 }
74
75 if (le32_to_cpu(de->hash) == namehash &&
76 le16_to_cpu(de->namelen) == qstr->len &&
77 !memcmp(qstr->name, dentry_blk->filename[bit_pos],
78 le16_to_cpu(de->namelen)))
79 goto found;
80 if (!(*insense_de) && !case_sense &&
81 le32_to_cpu(de->hash) == namehash &&
82 le16_to_cpu(de->namelen) == qstr->len &&
83 str_n_case_eq(qstr->name, dentry_blk->filename[bit_pos],
84 le16_to_cpu(de->namelen)))
85 *insense_de = de;
86 max_len = 0;
87 bit_pos += get_dentry_slots(le16_to_cpu(de->namelen));
88 }
89 de = NULL;
90 found:
91 return de;
92 }
93
94 static struct hmdfs_dentry_cloud *
hmdfs_in_level(struct dentry * child_dentry,unsigned int level,struct hmdfs_dcache_lookup_ctx_cloud * ctx)95 hmdfs_in_level(struct dentry *child_dentry, unsigned int level,
96 struct hmdfs_dcache_lookup_ctx_cloud *ctx)
97 {
98 unsigned long nbucket;
99 unsigned long bidx, end_block;
100 struct hmdfs_dentry_cloud *de = NULL;
101 struct hmdfs_dentry_cloud *tmp_insense_de = NULL;
102 struct hmdfs_dentry_group_cloud *dentry_blk;
103
104 nbucket = get_bucket_by_level(level);
105 if (!nbucket)
106 return de;
107
108 bidx = get_bucketaddr(level, ctx->hash % nbucket) * BUCKET_BLOCKS;
109 end_block = bidx + BUCKET_BLOCKS;
110
111 for (; bidx < end_block; bidx++) {
112 dentry_blk = find_dentry_page(ctx->sbi, bidx, ctx->filp);
113 if (!dentry_blk)
114 break;
115
116 de = find_in_block(dentry_blk, ctx->hash, ctx->name,
117 &tmp_insense_de, ctx->sbi->s_case_sensitive);
118 if (!de && !(ctx->insense_de) && tmp_insense_de) {
119 ctx->insense_de = tmp_insense_de;
120 ctx->insense_page = dentry_blk;
121 ctx->insense_bidx = bidx;
122 } else if (!de) {
123 hmdfs_unlock_file(ctx->filp, get_dentry_group_pos(bidx),
124 DENTRYGROUP_SIZE);
125 kfree(dentry_blk);
126 } else {
127 ctx->page = dentry_blk;
128 break;
129 }
130 }
131 ctx->bidx = bidx;
132 return de;
133 }
134
135 struct hmdfs_dentry_cloud *
hmdfs_find_dentry_cloud(struct dentry * child_dentry,struct hmdfs_dcache_lookup_ctx_cloud * ctx)136 hmdfs_find_dentry_cloud(struct dentry *child_dentry,
137 struct hmdfs_dcache_lookup_ctx_cloud *ctx)
138 {
139 struct hmdfs_dentry_cloud *de = NULL;
140 unsigned int max_depth;
141 unsigned int level;
142
143 if (!ctx->filp)
144 return NULL;
145
146 ctx->hash = hmdfs_dentry_hash(ctx->name, ctx->sbi->s_case_sensitive);
147 max_depth = get_max_depth(ctx->filp);
148 for (level = 0; level < max_depth; level++) {
149 de = hmdfs_in_level(child_dentry, level, ctx);
150 if (de) {
151 if (ctx->insense_page) {
152 hmdfs_unlock_file(ctx->filp,
153 get_dentry_group_pos(ctx->insense_bidx),
154 DENTRYGROUP_SIZE);
155 kfree(ctx->insense_page);
156 ctx->insense_page = NULL;
157 }
158 return de;
159 }
160 }
161 if (ctx->insense_de) {
162 ctx->bidx = ctx->insense_bidx;
163 ctx->page = ctx->insense_page;
164 ctx->insense_bidx = 0;
165 ctx->insense_page = NULL;
166 }
167 return ctx->insense_de;
168 }
169