xref: /OK3568_Linux_fs/kernel/fs/omfs/dir.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * OMFS (as used by RIO Karma) directory operations.
4*4882a593Smuzhiyun  * Copyright (C) 2005 Bob Copeland <me@bobcopeland.com>
5*4882a593Smuzhiyun  */
6*4882a593Smuzhiyun 
7*4882a593Smuzhiyun #include <linux/fs.h>
8*4882a593Smuzhiyun #include <linux/ctype.h>
9*4882a593Smuzhiyun #include <linux/buffer_head.h>
10*4882a593Smuzhiyun #include "omfs.h"
11*4882a593Smuzhiyun 
omfs_hash(const char * name,int namelen,int mod)12*4882a593Smuzhiyun static int omfs_hash(const char *name, int namelen, int mod)
13*4882a593Smuzhiyun {
14*4882a593Smuzhiyun 	int i, hash = 0;
15*4882a593Smuzhiyun 	for (i = 0; i < namelen; i++)
16*4882a593Smuzhiyun 		hash ^= tolower(name[i]) << (i % 24);
17*4882a593Smuzhiyun 	return hash % mod;
18*4882a593Smuzhiyun }
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun /*
21*4882a593Smuzhiyun  * Finds the bucket for a given name and reads the containing block;
22*4882a593Smuzhiyun  * *ofs is set to the offset of the first list entry.
23*4882a593Smuzhiyun  */
omfs_get_bucket(struct inode * dir,const char * name,int namelen,int * ofs)24*4882a593Smuzhiyun static struct buffer_head *omfs_get_bucket(struct inode *dir,
25*4882a593Smuzhiyun 		const char *name, int namelen, int *ofs)
26*4882a593Smuzhiyun {
27*4882a593Smuzhiyun 	int nbuckets = (dir->i_size - OMFS_DIR_START)/8;
28*4882a593Smuzhiyun 	int bucket = omfs_hash(name, namelen, nbuckets);
29*4882a593Smuzhiyun 
30*4882a593Smuzhiyun 	*ofs = OMFS_DIR_START + bucket * 8;
31*4882a593Smuzhiyun 	return omfs_bread(dir->i_sb, dir->i_ino);
32*4882a593Smuzhiyun }
33*4882a593Smuzhiyun 
omfs_scan_list(struct inode * dir,u64 block,const char * name,int namelen,u64 * prev_block)34*4882a593Smuzhiyun static struct buffer_head *omfs_scan_list(struct inode *dir, u64 block,
35*4882a593Smuzhiyun 				const char *name, int namelen,
36*4882a593Smuzhiyun 				u64 *prev_block)
37*4882a593Smuzhiyun {
38*4882a593Smuzhiyun 	struct buffer_head *bh;
39*4882a593Smuzhiyun 	struct omfs_inode *oi;
40*4882a593Smuzhiyun 	int err = -ENOENT;
41*4882a593Smuzhiyun 	*prev_block = ~0;
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun 	while (block != ~0) {
44*4882a593Smuzhiyun 		bh = omfs_bread(dir->i_sb, block);
45*4882a593Smuzhiyun 		if (!bh) {
46*4882a593Smuzhiyun 			err = -EIO;
47*4882a593Smuzhiyun 			goto err;
48*4882a593Smuzhiyun 		}
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun 		oi = (struct omfs_inode *) bh->b_data;
51*4882a593Smuzhiyun 		if (omfs_is_bad(OMFS_SB(dir->i_sb), &oi->i_head, block)) {
52*4882a593Smuzhiyun 			brelse(bh);
53*4882a593Smuzhiyun 			goto err;
54*4882a593Smuzhiyun 		}
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun 		if (strncmp(oi->i_name, name, namelen) == 0)
57*4882a593Smuzhiyun 			return bh;
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun 		*prev_block = block;
60*4882a593Smuzhiyun 		block = be64_to_cpu(oi->i_sibling);
61*4882a593Smuzhiyun 		brelse(bh);
62*4882a593Smuzhiyun 	}
63*4882a593Smuzhiyun err:
64*4882a593Smuzhiyun 	return ERR_PTR(err);
65*4882a593Smuzhiyun }
66*4882a593Smuzhiyun 
omfs_find_entry(struct inode * dir,const char * name,int namelen)67*4882a593Smuzhiyun static struct buffer_head *omfs_find_entry(struct inode *dir,
68*4882a593Smuzhiyun 					   const char *name, int namelen)
69*4882a593Smuzhiyun {
70*4882a593Smuzhiyun 	struct buffer_head *bh;
71*4882a593Smuzhiyun 	int ofs;
72*4882a593Smuzhiyun 	u64 block, dummy;
73*4882a593Smuzhiyun 
74*4882a593Smuzhiyun 	bh = omfs_get_bucket(dir, name, namelen, &ofs);
75*4882a593Smuzhiyun 	if (!bh)
76*4882a593Smuzhiyun 		return ERR_PTR(-EIO);
77*4882a593Smuzhiyun 
78*4882a593Smuzhiyun 	block = be64_to_cpu(*((__be64 *) &bh->b_data[ofs]));
79*4882a593Smuzhiyun 	brelse(bh);
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun 	return omfs_scan_list(dir, block, name, namelen, &dummy);
82*4882a593Smuzhiyun }
83*4882a593Smuzhiyun 
omfs_make_empty(struct inode * inode,struct super_block * sb)84*4882a593Smuzhiyun int omfs_make_empty(struct inode *inode, struct super_block *sb)
85*4882a593Smuzhiyun {
86*4882a593Smuzhiyun 	struct omfs_sb_info *sbi = OMFS_SB(sb);
87*4882a593Smuzhiyun 	struct buffer_head *bh;
88*4882a593Smuzhiyun 	struct omfs_inode *oi;
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun 	bh = omfs_bread(sb, inode->i_ino);
91*4882a593Smuzhiyun 	if (!bh)
92*4882a593Smuzhiyun 		return -ENOMEM;
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun 	memset(bh->b_data, 0, sizeof(struct omfs_inode));
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun 	if (S_ISDIR(inode->i_mode)) {
97*4882a593Smuzhiyun 		memset(&bh->b_data[OMFS_DIR_START], 0xff,
98*4882a593Smuzhiyun 			sbi->s_sys_blocksize - OMFS_DIR_START);
99*4882a593Smuzhiyun 	} else
100*4882a593Smuzhiyun 		omfs_make_empty_table(bh, OMFS_EXTENT_START);
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun 	oi = (struct omfs_inode *) bh->b_data;
103*4882a593Smuzhiyun 	oi->i_head.h_self = cpu_to_be64(inode->i_ino);
104*4882a593Smuzhiyun 	oi->i_sibling = ~cpu_to_be64(0ULL);
105*4882a593Smuzhiyun 
106*4882a593Smuzhiyun 	mark_buffer_dirty(bh);
107*4882a593Smuzhiyun 	brelse(bh);
108*4882a593Smuzhiyun 	return 0;
109*4882a593Smuzhiyun }
110*4882a593Smuzhiyun 
omfs_add_link(struct dentry * dentry,struct inode * inode)111*4882a593Smuzhiyun static int omfs_add_link(struct dentry *dentry, struct inode *inode)
112*4882a593Smuzhiyun {
113*4882a593Smuzhiyun 	struct inode *dir = d_inode(dentry->d_parent);
114*4882a593Smuzhiyun 	const char *name = dentry->d_name.name;
115*4882a593Smuzhiyun 	int namelen = dentry->d_name.len;
116*4882a593Smuzhiyun 	struct omfs_inode *oi;
117*4882a593Smuzhiyun 	struct buffer_head *bh;
118*4882a593Smuzhiyun 	u64 block;
119*4882a593Smuzhiyun 	__be64 *entry;
120*4882a593Smuzhiyun 	int ofs;
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun 	/* just prepend to head of queue in proper bucket */
123*4882a593Smuzhiyun 	bh = omfs_get_bucket(dir, name, namelen, &ofs);
124*4882a593Smuzhiyun 	if (!bh)
125*4882a593Smuzhiyun 		goto out;
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun 	entry = (__be64 *) &bh->b_data[ofs];
128*4882a593Smuzhiyun 	block = be64_to_cpu(*entry);
129*4882a593Smuzhiyun 	*entry = cpu_to_be64(inode->i_ino);
130*4882a593Smuzhiyun 	mark_buffer_dirty(bh);
131*4882a593Smuzhiyun 	brelse(bh);
132*4882a593Smuzhiyun 
133*4882a593Smuzhiyun 	/* now set the sibling and parent pointers on the new inode */
134*4882a593Smuzhiyun 	bh = omfs_bread(dir->i_sb, inode->i_ino);
135*4882a593Smuzhiyun 	if (!bh)
136*4882a593Smuzhiyun 		goto out;
137*4882a593Smuzhiyun 
138*4882a593Smuzhiyun 	oi = (struct omfs_inode *) bh->b_data;
139*4882a593Smuzhiyun 	memcpy(oi->i_name, name, namelen);
140*4882a593Smuzhiyun 	memset(oi->i_name + namelen, 0, OMFS_NAMELEN - namelen);
141*4882a593Smuzhiyun 	oi->i_sibling = cpu_to_be64(block);
142*4882a593Smuzhiyun 	oi->i_parent = cpu_to_be64(dir->i_ino);
143*4882a593Smuzhiyun 	mark_buffer_dirty(bh);
144*4882a593Smuzhiyun 	brelse(bh);
145*4882a593Smuzhiyun 
146*4882a593Smuzhiyun 	dir->i_ctime = current_time(dir);
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun 	/* mark affected inodes dirty to rebuild checksums */
149*4882a593Smuzhiyun 	mark_inode_dirty(dir);
150*4882a593Smuzhiyun 	mark_inode_dirty(inode);
151*4882a593Smuzhiyun 	return 0;
152*4882a593Smuzhiyun out:
153*4882a593Smuzhiyun 	return -ENOMEM;
154*4882a593Smuzhiyun }
155*4882a593Smuzhiyun 
omfs_delete_entry(struct dentry * dentry)156*4882a593Smuzhiyun static int omfs_delete_entry(struct dentry *dentry)
157*4882a593Smuzhiyun {
158*4882a593Smuzhiyun 	struct inode *dir = d_inode(dentry->d_parent);
159*4882a593Smuzhiyun 	struct inode *dirty;
160*4882a593Smuzhiyun 	const char *name = dentry->d_name.name;
161*4882a593Smuzhiyun 	int namelen = dentry->d_name.len;
162*4882a593Smuzhiyun 	struct omfs_inode *oi;
163*4882a593Smuzhiyun 	struct buffer_head *bh, *bh2;
164*4882a593Smuzhiyun 	__be64 *entry, next;
165*4882a593Smuzhiyun 	u64 block, prev;
166*4882a593Smuzhiyun 	int ofs;
167*4882a593Smuzhiyun 	int err = -ENOMEM;
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun 	/* delete the proper node in the bucket's linked list */
170*4882a593Smuzhiyun 	bh = omfs_get_bucket(dir, name, namelen, &ofs);
171*4882a593Smuzhiyun 	if (!bh)
172*4882a593Smuzhiyun 		goto out;
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun 	entry = (__be64 *) &bh->b_data[ofs];
175*4882a593Smuzhiyun 	block = be64_to_cpu(*entry);
176*4882a593Smuzhiyun 
177*4882a593Smuzhiyun 	bh2 = omfs_scan_list(dir, block, name, namelen, &prev);
178*4882a593Smuzhiyun 	if (IS_ERR(bh2)) {
179*4882a593Smuzhiyun 		err = PTR_ERR(bh2);
180*4882a593Smuzhiyun 		goto out_free_bh;
181*4882a593Smuzhiyun 	}
182*4882a593Smuzhiyun 
183*4882a593Smuzhiyun 	oi = (struct omfs_inode *) bh2->b_data;
184*4882a593Smuzhiyun 	next = oi->i_sibling;
185*4882a593Smuzhiyun 	brelse(bh2);
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun 	if (prev != ~0) {
188*4882a593Smuzhiyun 		/* found in middle of list, get list ptr */
189*4882a593Smuzhiyun 		brelse(bh);
190*4882a593Smuzhiyun 		bh = omfs_bread(dir->i_sb, prev);
191*4882a593Smuzhiyun 		if (!bh)
192*4882a593Smuzhiyun 			goto out;
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun 		oi = (struct omfs_inode *) bh->b_data;
195*4882a593Smuzhiyun 		entry = &oi->i_sibling;
196*4882a593Smuzhiyun 	}
197*4882a593Smuzhiyun 
198*4882a593Smuzhiyun 	*entry = next;
199*4882a593Smuzhiyun 	mark_buffer_dirty(bh);
200*4882a593Smuzhiyun 
201*4882a593Smuzhiyun 	if (prev != ~0) {
202*4882a593Smuzhiyun 		dirty = omfs_iget(dir->i_sb, prev);
203*4882a593Smuzhiyun 		if (!IS_ERR(dirty)) {
204*4882a593Smuzhiyun 			mark_inode_dirty(dirty);
205*4882a593Smuzhiyun 			iput(dirty);
206*4882a593Smuzhiyun 		}
207*4882a593Smuzhiyun 	}
208*4882a593Smuzhiyun 
209*4882a593Smuzhiyun 	err = 0;
210*4882a593Smuzhiyun out_free_bh:
211*4882a593Smuzhiyun 	brelse(bh);
212*4882a593Smuzhiyun out:
213*4882a593Smuzhiyun 	return err;
214*4882a593Smuzhiyun }
215*4882a593Smuzhiyun 
omfs_dir_is_empty(struct inode * inode)216*4882a593Smuzhiyun static int omfs_dir_is_empty(struct inode *inode)
217*4882a593Smuzhiyun {
218*4882a593Smuzhiyun 	int nbuckets = (inode->i_size - OMFS_DIR_START) / 8;
219*4882a593Smuzhiyun 	struct buffer_head *bh;
220*4882a593Smuzhiyun 	u64 *ptr;
221*4882a593Smuzhiyun 	int i;
222*4882a593Smuzhiyun 
223*4882a593Smuzhiyun 	bh = omfs_bread(inode->i_sb, inode->i_ino);
224*4882a593Smuzhiyun 
225*4882a593Smuzhiyun 	if (!bh)
226*4882a593Smuzhiyun 		return 0;
227*4882a593Smuzhiyun 
228*4882a593Smuzhiyun 	ptr = (u64 *) &bh->b_data[OMFS_DIR_START];
229*4882a593Smuzhiyun 
230*4882a593Smuzhiyun 	for (i = 0; i < nbuckets; i++, ptr++)
231*4882a593Smuzhiyun 		if (*ptr != ~0)
232*4882a593Smuzhiyun 			break;
233*4882a593Smuzhiyun 
234*4882a593Smuzhiyun 	brelse(bh);
235*4882a593Smuzhiyun 	return *ptr != ~0;
236*4882a593Smuzhiyun }
237*4882a593Smuzhiyun 
omfs_remove(struct inode * dir,struct dentry * dentry)238*4882a593Smuzhiyun static int omfs_remove(struct inode *dir, struct dentry *dentry)
239*4882a593Smuzhiyun {
240*4882a593Smuzhiyun 	struct inode *inode = d_inode(dentry);
241*4882a593Smuzhiyun 	int ret;
242*4882a593Smuzhiyun 
243*4882a593Smuzhiyun 
244*4882a593Smuzhiyun 	if (S_ISDIR(inode->i_mode) &&
245*4882a593Smuzhiyun 	    !omfs_dir_is_empty(inode))
246*4882a593Smuzhiyun 		return -ENOTEMPTY;
247*4882a593Smuzhiyun 
248*4882a593Smuzhiyun 	ret = omfs_delete_entry(dentry);
249*4882a593Smuzhiyun 	if (ret)
250*4882a593Smuzhiyun 		return ret;
251*4882a593Smuzhiyun 
252*4882a593Smuzhiyun 	clear_nlink(inode);
253*4882a593Smuzhiyun 	mark_inode_dirty(inode);
254*4882a593Smuzhiyun 	mark_inode_dirty(dir);
255*4882a593Smuzhiyun 	return 0;
256*4882a593Smuzhiyun }
257*4882a593Smuzhiyun 
omfs_add_node(struct inode * dir,struct dentry * dentry,umode_t mode)258*4882a593Smuzhiyun static int omfs_add_node(struct inode *dir, struct dentry *dentry, umode_t mode)
259*4882a593Smuzhiyun {
260*4882a593Smuzhiyun 	int err;
261*4882a593Smuzhiyun 	struct inode *inode = omfs_new_inode(dir, mode);
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun 	if (IS_ERR(inode))
264*4882a593Smuzhiyun 		return PTR_ERR(inode);
265*4882a593Smuzhiyun 
266*4882a593Smuzhiyun 	err = omfs_make_empty(inode, dir->i_sb);
267*4882a593Smuzhiyun 	if (err)
268*4882a593Smuzhiyun 		goto out_free_inode;
269*4882a593Smuzhiyun 
270*4882a593Smuzhiyun 	err = omfs_add_link(dentry, inode);
271*4882a593Smuzhiyun 	if (err)
272*4882a593Smuzhiyun 		goto out_free_inode;
273*4882a593Smuzhiyun 
274*4882a593Smuzhiyun 	d_instantiate(dentry, inode);
275*4882a593Smuzhiyun 	return 0;
276*4882a593Smuzhiyun 
277*4882a593Smuzhiyun out_free_inode:
278*4882a593Smuzhiyun 	iput(inode);
279*4882a593Smuzhiyun 	return err;
280*4882a593Smuzhiyun }
281*4882a593Smuzhiyun 
omfs_mkdir(struct inode * dir,struct dentry * dentry,umode_t mode)282*4882a593Smuzhiyun static int omfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
283*4882a593Smuzhiyun {
284*4882a593Smuzhiyun 	return omfs_add_node(dir, dentry, mode | S_IFDIR);
285*4882a593Smuzhiyun }
286*4882a593Smuzhiyun 
omfs_create(struct inode * dir,struct dentry * dentry,umode_t mode,bool excl)287*4882a593Smuzhiyun static int omfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
288*4882a593Smuzhiyun 		bool excl)
289*4882a593Smuzhiyun {
290*4882a593Smuzhiyun 	return omfs_add_node(dir, dentry, mode | S_IFREG);
291*4882a593Smuzhiyun }
292*4882a593Smuzhiyun 
omfs_lookup(struct inode * dir,struct dentry * dentry,unsigned int flags)293*4882a593Smuzhiyun static struct dentry *omfs_lookup(struct inode *dir, struct dentry *dentry,
294*4882a593Smuzhiyun 				  unsigned int flags)
295*4882a593Smuzhiyun {
296*4882a593Smuzhiyun 	struct buffer_head *bh;
297*4882a593Smuzhiyun 	struct inode *inode = NULL;
298*4882a593Smuzhiyun 
299*4882a593Smuzhiyun 	if (dentry->d_name.len > OMFS_NAMELEN)
300*4882a593Smuzhiyun 		return ERR_PTR(-ENAMETOOLONG);
301*4882a593Smuzhiyun 
302*4882a593Smuzhiyun 	bh = omfs_find_entry(dir, dentry->d_name.name, dentry->d_name.len);
303*4882a593Smuzhiyun 	if (!IS_ERR(bh)) {
304*4882a593Smuzhiyun 		struct omfs_inode *oi = (struct omfs_inode *)bh->b_data;
305*4882a593Smuzhiyun 		ino_t ino = be64_to_cpu(oi->i_head.h_self);
306*4882a593Smuzhiyun 		brelse(bh);
307*4882a593Smuzhiyun 		inode = omfs_iget(dir->i_sb, ino);
308*4882a593Smuzhiyun 	} else if (bh != ERR_PTR(-ENOENT)) {
309*4882a593Smuzhiyun 		inode = ERR_CAST(bh);
310*4882a593Smuzhiyun 	}
311*4882a593Smuzhiyun 	return d_splice_alias(inode, dentry);
312*4882a593Smuzhiyun }
313*4882a593Smuzhiyun 
314*4882a593Smuzhiyun /* sanity check block's self pointer */
omfs_is_bad(struct omfs_sb_info * sbi,struct omfs_header * header,u64 fsblock)315*4882a593Smuzhiyun int omfs_is_bad(struct omfs_sb_info *sbi, struct omfs_header *header,
316*4882a593Smuzhiyun 	u64 fsblock)
317*4882a593Smuzhiyun {
318*4882a593Smuzhiyun 	int is_bad;
319*4882a593Smuzhiyun 	u64 ino = be64_to_cpu(header->h_self);
320*4882a593Smuzhiyun 	is_bad = ((ino != fsblock) || (ino < sbi->s_root_ino) ||
321*4882a593Smuzhiyun 		(ino > sbi->s_num_blocks));
322*4882a593Smuzhiyun 
323*4882a593Smuzhiyun 	if (is_bad)
324*4882a593Smuzhiyun 		printk(KERN_WARNING "omfs: bad hash chain detected\n");
325*4882a593Smuzhiyun 
326*4882a593Smuzhiyun 	return is_bad;
327*4882a593Smuzhiyun }
328*4882a593Smuzhiyun 
omfs_fill_chain(struct inode * dir,struct dir_context * ctx,u64 fsblock,int hindex)329*4882a593Smuzhiyun static bool omfs_fill_chain(struct inode *dir, struct dir_context *ctx,
330*4882a593Smuzhiyun 		u64 fsblock, int hindex)
331*4882a593Smuzhiyun {
332*4882a593Smuzhiyun 	/* follow chain in this bucket */
333*4882a593Smuzhiyun 	while (fsblock != ~0) {
334*4882a593Smuzhiyun 		struct buffer_head *bh = omfs_bread(dir->i_sb, fsblock);
335*4882a593Smuzhiyun 		struct omfs_inode *oi;
336*4882a593Smuzhiyun 		u64 self;
337*4882a593Smuzhiyun 		unsigned char d_type;
338*4882a593Smuzhiyun 
339*4882a593Smuzhiyun 		if (!bh)
340*4882a593Smuzhiyun 			return true;
341*4882a593Smuzhiyun 
342*4882a593Smuzhiyun 		oi = (struct omfs_inode *) bh->b_data;
343*4882a593Smuzhiyun 		if (omfs_is_bad(OMFS_SB(dir->i_sb), &oi->i_head, fsblock)) {
344*4882a593Smuzhiyun 			brelse(bh);
345*4882a593Smuzhiyun 			return true;
346*4882a593Smuzhiyun 		}
347*4882a593Smuzhiyun 
348*4882a593Smuzhiyun 		self = fsblock;
349*4882a593Smuzhiyun 		fsblock = be64_to_cpu(oi->i_sibling);
350*4882a593Smuzhiyun 
351*4882a593Smuzhiyun 		/* skip visited nodes */
352*4882a593Smuzhiyun 		if (hindex) {
353*4882a593Smuzhiyun 			hindex--;
354*4882a593Smuzhiyun 			brelse(bh);
355*4882a593Smuzhiyun 			continue;
356*4882a593Smuzhiyun 		}
357*4882a593Smuzhiyun 
358*4882a593Smuzhiyun 		d_type = (oi->i_type == OMFS_DIR) ? DT_DIR : DT_REG;
359*4882a593Smuzhiyun 
360*4882a593Smuzhiyun 		if (!dir_emit(ctx, oi->i_name,
361*4882a593Smuzhiyun 			      strnlen(oi->i_name, OMFS_NAMELEN),
362*4882a593Smuzhiyun 			      self, d_type)) {
363*4882a593Smuzhiyun 			brelse(bh);
364*4882a593Smuzhiyun 			return false;
365*4882a593Smuzhiyun 		}
366*4882a593Smuzhiyun 		brelse(bh);
367*4882a593Smuzhiyun 		ctx->pos++;
368*4882a593Smuzhiyun 	}
369*4882a593Smuzhiyun 	return true;
370*4882a593Smuzhiyun }
371*4882a593Smuzhiyun 
omfs_rename(struct inode * old_dir,struct dentry * old_dentry,struct inode * new_dir,struct dentry * new_dentry,unsigned int flags)372*4882a593Smuzhiyun static int omfs_rename(struct inode *old_dir, struct dentry *old_dentry,
373*4882a593Smuzhiyun 		       struct inode *new_dir, struct dentry *new_dentry,
374*4882a593Smuzhiyun 		       unsigned int flags)
375*4882a593Smuzhiyun {
376*4882a593Smuzhiyun 	struct inode *new_inode = d_inode(new_dentry);
377*4882a593Smuzhiyun 	struct inode *old_inode = d_inode(old_dentry);
378*4882a593Smuzhiyun 	int err;
379*4882a593Smuzhiyun 
380*4882a593Smuzhiyun 	if (flags & ~RENAME_NOREPLACE)
381*4882a593Smuzhiyun 		return -EINVAL;
382*4882a593Smuzhiyun 
383*4882a593Smuzhiyun 	if (new_inode) {
384*4882a593Smuzhiyun 		/* overwriting existing file/dir */
385*4882a593Smuzhiyun 		err = omfs_remove(new_dir, new_dentry);
386*4882a593Smuzhiyun 		if (err)
387*4882a593Smuzhiyun 			goto out;
388*4882a593Smuzhiyun 	}
389*4882a593Smuzhiyun 
390*4882a593Smuzhiyun 	/* since omfs locates files by name, we need to unlink _before_
391*4882a593Smuzhiyun 	 * adding the new link or we won't find the old one */
392*4882a593Smuzhiyun 	err = omfs_delete_entry(old_dentry);
393*4882a593Smuzhiyun 	if (err)
394*4882a593Smuzhiyun 		goto out;
395*4882a593Smuzhiyun 
396*4882a593Smuzhiyun 	mark_inode_dirty(old_dir);
397*4882a593Smuzhiyun 	err = omfs_add_link(new_dentry, old_inode);
398*4882a593Smuzhiyun 	if (err)
399*4882a593Smuzhiyun 		goto out;
400*4882a593Smuzhiyun 
401*4882a593Smuzhiyun 	old_inode->i_ctime = current_time(old_inode);
402*4882a593Smuzhiyun 	mark_inode_dirty(old_inode);
403*4882a593Smuzhiyun out:
404*4882a593Smuzhiyun 	return err;
405*4882a593Smuzhiyun }
406*4882a593Smuzhiyun 
omfs_readdir(struct file * file,struct dir_context * ctx)407*4882a593Smuzhiyun static int omfs_readdir(struct file *file, struct dir_context *ctx)
408*4882a593Smuzhiyun {
409*4882a593Smuzhiyun 	struct inode *dir = file_inode(file);
410*4882a593Smuzhiyun 	struct buffer_head *bh;
411*4882a593Smuzhiyun 	__be64 *p;
412*4882a593Smuzhiyun 	unsigned int hchain, hindex;
413*4882a593Smuzhiyun 	int nbuckets;
414*4882a593Smuzhiyun 
415*4882a593Smuzhiyun 	if (ctx->pos >> 32)
416*4882a593Smuzhiyun 		return -EINVAL;
417*4882a593Smuzhiyun 
418*4882a593Smuzhiyun 	if (ctx->pos < 1 << 20) {
419*4882a593Smuzhiyun 		if (!dir_emit_dots(file, ctx))
420*4882a593Smuzhiyun 			return 0;
421*4882a593Smuzhiyun 		ctx->pos = 1 << 20;
422*4882a593Smuzhiyun 	}
423*4882a593Smuzhiyun 
424*4882a593Smuzhiyun 	nbuckets = (dir->i_size - OMFS_DIR_START) / 8;
425*4882a593Smuzhiyun 
426*4882a593Smuzhiyun 	/* high 12 bits store bucket + 1 and low 20 bits store hash index */
427*4882a593Smuzhiyun 	hchain = (ctx->pos >> 20) - 1;
428*4882a593Smuzhiyun 	hindex = ctx->pos & 0xfffff;
429*4882a593Smuzhiyun 
430*4882a593Smuzhiyun 	bh = omfs_bread(dir->i_sb, dir->i_ino);
431*4882a593Smuzhiyun 	if (!bh)
432*4882a593Smuzhiyun 		return -EINVAL;
433*4882a593Smuzhiyun 
434*4882a593Smuzhiyun 	p = (__be64 *)(bh->b_data + OMFS_DIR_START) + hchain;
435*4882a593Smuzhiyun 
436*4882a593Smuzhiyun 	for (; hchain < nbuckets; hchain++) {
437*4882a593Smuzhiyun 		__u64 fsblock = be64_to_cpu(*p++);
438*4882a593Smuzhiyun 		if (!omfs_fill_chain(dir, ctx, fsblock, hindex))
439*4882a593Smuzhiyun 			break;
440*4882a593Smuzhiyun 		hindex = 0;
441*4882a593Smuzhiyun 		ctx->pos = (hchain+2) << 20;
442*4882a593Smuzhiyun 	}
443*4882a593Smuzhiyun 	brelse(bh);
444*4882a593Smuzhiyun 	return 0;
445*4882a593Smuzhiyun }
446*4882a593Smuzhiyun 
447*4882a593Smuzhiyun const struct inode_operations omfs_dir_inops = {
448*4882a593Smuzhiyun 	.lookup = omfs_lookup,
449*4882a593Smuzhiyun 	.mkdir = omfs_mkdir,
450*4882a593Smuzhiyun 	.rename = omfs_rename,
451*4882a593Smuzhiyun 	.create = omfs_create,
452*4882a593Smuzhiyun 	.unlink = omfs_remove,
453*4882a593Smuzhiyun 	.rmdir = omfs_remove,
454*4882a593Smuzhiyun };
455*4882a593Smuzhiyun 
456*4882a593Smuzhiyun const struct file_operations omfs_dir_operations = {
457*4882a593Smuzhiyun 	.read = generic_read_dir,
458*4882a593Smuzhiyun 	.iterate_shared = omfs_readdir,
459*4882a593Smuzhiyun 	.llseek = generic_file_llseek,
460*4882a593Smuzhiyun };
461