xref: /OK3568_Linux_fs/kernel/fs/coda/dir.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun 
3*4882a593Smuzhiyun /*
4*4882a593Smuzhiyun  * Directory operations for Coda filesystem
5*4882a593Smuzhiyun  * Original version: (C) 1996 P. Braam and M. Callahan
6*4882a593Smuzhiyun  * Rewritten for Linux 2.1. (C) 1997 Carnegie Mellon University
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  * Carnegie Mellon encourages users to contribute improvements to
9*4882a593Smuzhiyun  * the Coda project. Contact Peter Braam (coda@cs.cmu.edu).
10*4882a593Smuzhiyun  */
11*4882a593Smuzhiyun 
12*4882a593Smuzhiyun #include <linux/types.h>
13*4882a593Smuzhiyun #include <linux/kernel.h>
14*4882a593Smuzhiyun #include <linux/time.h>
15*4882a593Smuzhiyun #include <linux/fs.h>
16*4882a593Smuzhiyun #include <linux/slab.h>
17*4882a593Smuzhiyun #include <linux/file.h>
18*4882a593Smuzhiyun #include <linux/stat.h>
19*4882a593Smuzhiyun #include <linux/errno.h>
20*4882a593Smuzhiyun #include <linux/string.h>
21*4882a593Smuzhiyun #include <linux/spinlock.h>
22*4882a593Smuzhiyun #include <linux/namei.h>
23*4882a593Smuzhiyun #include <linux/uaccess.h>
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun #include <linux/coda.h>
26*4882a593Smuzhiyun #include "coda_psdev.h"
27*4882a593Smuzhiyun #include "coda_linux.h"
28*4882a593Smuzhiyun #include "coda_cache.h"
29*4882a593Smuzhiyun 
30*4882a593Smuzhiyun #include "coda_int.h"
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun /* same as fs/bad_inode.c */
coda_return_EIO(void)33*4882a593Smuzhiyun static int coda_return_EIO(void)
34*4882a593Smuzhiyun {
35*4882a593Smuzhiyun 	return -EIO;
36*4882a593Smuzhiyun }
37*4882a593Smuzhiyun #define CODA_EIO_ERROR ((void *) (coda_return_EIO))
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun /* inode operations for directories */
40*4882a593Smuzhiyun /* access routines: lookup, readlink, permission */
coda_lookup(struct inode * dir,struct dentry * entry,unsigned int flags)41*4882a593Smuzhiyun static struct dentry *coda_lookup(struct inode *dir, struct dentry *entry, unsigned int flags)
42*4882a593Smuzhiyun {
43*4882a593Smuzhiyun 	struct super_block *sb = dir->i_sb;
44*4882a593Smuzhiyun 	const char *name = entry->d_name.name;
45*4882a593Smuzhiyun 	size_t length = entry->d_name.len;
46*4882a593Smuzhiyun 	struct inode *inode;
47*4882a593Smuzhiyun 	int type = 0;
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun 	if (length > CODA_MAXNAMLEN) {
50*4882a593Smuzhiyun 		pr_err("name too long: lookup, %s %zu\n",
51*4882a593Smuzhiyun 		       coda_i2s(dir), length);
52*4882a593Smuzhiyun 		return ERR_PTR(-ENAMETOOLONG);
53*4882a593Smuzhiyun 	}
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun 	/* control object, create inode on the fly */
56*4882a593Smuzhiyun 	if (is_root_inode(dir) && coda_iscontrol(name, length)) {
57*4882a593Smuzhiyun 		inode = coda_cnode_makectl(sb);
58*4882a593Smuzhiyun 		type = CODA_NOCACHE;
59*4882a593Smuzhiyun 	} else {
60*4882a593Smuzhiyun 		struct CodaFid fid = { { 0, } };
61*4882a593Smuzhiyun 		int error = venus_lookup(sb, coda_i2f(dir), name, length,
62*4882a593Smuzhiyun 				     &type, &fid);
63*4882a593Smuzhiyun 		inode = !error ? coda_cnode_make(&fid, sb) : ERR_PTR(error);
64*4882a593Smuzhiyun 	}
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun 	if (!IS_ERR(inode) && (type & CODA_NOCACHE))
67*4882a593Smuzhiyun 		coda_flag_inode(inode, C_VATTR | C_PURGE);
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun 	if (inode == ERR_PTR(-ENOENT))
70*4882a593Smuzhiyun 		inode = NULL;
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun 	return d_splice_alias(inode, entry);
73*4882a593Smuzhiyun }
74*4882a593Smuzhiyun 
75*4882a593Smuzhiyun 
coda_permission(struct inode * inode,int mask)76*4882a593Smuzhiyun int coda_permission(struct inode *inode, int mask)
77*4882a593Smuzhiyun {
78*4882a593Smuzhiyun 	int error;
79*4882a593Smuzhiyun 
80*4882a593Smuzhiyun 	if (mask & MAY_NOT_BLOCK)
81*4882a593Smuzhiyun 		return -ECHILD;
82*4882a593Smuzhiyun 
83*4882a593Smuzhiyun 	mask &= MAY_READ | MAY_WRITE | MAY_EXEC;
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun 	if (!mask)
86*4882a593Smuzhiyun 		return 0;
87*4882a593Smuzhiyun 
88*4882a593Smuzhiyun 	if ((mask & MAY_EXEC) && !execute_ok(inode))
89*4882a593Smuzhiyun 		return -EACCES;
90*4882a593Smuzhiyun 
91*4882a593Smuzhiyun 	if (coda_cache_check(inode, mask))
92*4882a593Smuzhiyun 		return 0;
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun 	error = venus_access(inode->i_sb, coda_i2f(inode), mask);
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun 	if (!error)
97*4882a593Smuzhiyun 		coda_cache_enter(inode, mask);
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun 	return error;
100*4882a593Smuzhiyun }
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun 
coda_dir_update_mtime(struct inode * dir)103*4882a593Smuzhiyun static inline void coda_dir_update_mtime(struct inode *dir)
104*4882a593Smuzhiyun {
105*4882a593Smuzhiyun #ifdef REQUERY_VENUS_FOR_MTIME
106*4882a593Smuzhiyun 	/* invalidate the directory cnode's attributes so we refetch the
107*4882a593Smuzhiyun 	 * attributes from venus next time the inode is referenced */
108*4882a593Smuzhiyun 	coda_flag_inode(dir, C_VATTR);
109*4882a593Smuzhiyun #else
110*4882a593Smuzhiyun 	/* optimistically we can also act as if our nose bleeds. The
111*4882a593Smuzhiyun 	 * granularity of the mtime is coarse anyways so we might actually be
112*4882a593Smuzhiyun 	 * right most of the time. Note: we only do this for directories. */
113*4882a593Smuzhiyun 	dir->i_mtime = dir->i_ctime = current_time(dir);
114*4882a593Smuzhiyun #endif
115*4882a593Smuzhiyun }
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun /* we have to wrap inc_nlink/drop_nlink because sometimes userspace uses a
118*4882a593Smuzhiyun  * trick to fool GNU find's optimizations. If we can't be sure of the link
119*4882a593Smuzhiyun  * (because of volume mount points) we set i_nlink to 1 which forces find
120*4882a593Smuzhiyun  * to consider every child as a possible directory. We should also never
121*4882a593Smuzhiyun  * see an increment or decrement for deleted directories where i_nlink == 0 */
coda_dir_inc_nlink(struct inode * dir)122*4882a593Smuzhiyun static inline void coda_dir_inc_nlink(struct inode *dir)
123*4882a593Smuzhiyun {
124*4882a593Smuzhiyun 	if (dir->i_nlink >= 2)
125*4882a593Smuzhiyun 		inc_nlink(dir);
126*4882a593Smuzhiyun }
127*4882a593Smuzhiyun 
coda_dir_drop_nlink(struct inode * dir)128*4882a593Smuzhiyun static inline void coda_dir_drop_nlink(struct inode *dir)
129*4882a593Smuzhiyun {
130*4882a593Smuzhiyun 	if (dir->i_nlink > 2)
131*4882a593Smuzhiyun 		drop_nlink(dir);
132*4882a593Smuzhiyun }
133*4882a593Smuzhiyun 
134*4882a593Smuzhiyun /* creation routines: create, mknod, mkdir, link, symlink */
coda_create(struct inode * dir,struct dentry * de,umode_t mode,bool excl)135*4882a593Smuzhiyun static int coda_create(struct inode *dir, struct dentry *de, umode_t mode, bool excl)
136*4882a593Smuzhiyun {
137*4882a593Smuzhiyun 	int error;
138*4882a593Smuzhiyun 	const char *name=de->d_name.name;
139*4882a593Smuzhiyun 	int length=de->d_name.len;
140*4882a593Smuzhiyun 	struct inode *inode;
141*4882a593Smuzhiyun 	struct CodaFid newfid;
142*4882a593Smuzhiyun 	struct coda_vattr attrs;
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun 	if (is_root_inode(dir) && coda_iscontrol(name, length))
145*4882a593Smuzhiyun 		return -EPERM;
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun 	error = venus_create(dir->i_sb, coda_i2f(dir), name, length,
148*4882a593Smuzhiyun 				0, mode, &newfid, &attrs);
149*4882a593Smuzhiyun 	if (error)
150*4882a593Smuzhiyun 		goto err_out;
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun 	inode = coda_iget(dir->i_sb, &newfid, &attrs);
153*4882a593Smuzhiyun 	if (IS_ERR(inode)) {
154*4882a593Smuzhiyun 		error = PTR_ERR(inode);
155*4882a593Smuzhiyun 		goto err_out;
156*4882a593Smuzhiyun 	}
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun 	/* invalidate the directory cnode's attributes */
159*4882a593Smuzhiyun 	coda_dir_update_mtime(dir);
160*4882a593Smuzhiyun 	d_instantiate(de, inode);
161*4882a593Smuzhiyun 	return 0;
162*4882a593Smuzhiyun err_out:
163*4882a593Smuzhiyun 	d_drop(de);
164*4882a593Smuzhiyun 	return error;
165*4882a593Smuzhiyun }
166*4882a593Smuzhiyun 
coda_mkdir(struct inode * dir,struct dentry * de,umode_t mode)167*4882a593Smuzhiyun static int coda_mkdir(struct inode *dir, struct dentry *de, umode_t mode)
168*4882a593Smuzhiyun {
169*4882a593Smuzhiyun 	struct inode *inode;
170*4882a593Smuzhiyun 	struct coda_vattr attrs;
171*4882a593Smuzhiyun 	const char *name = de->d_name.name;
172*4882a593Smuzhiyun 	int len = de->d_name.len;
173*4882a593Smuzhiyun 	int error;
174*4882a593Smuzhiyun 	struct CodaFid newfid;
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun 	if (is_root_inode(dir) && coda_iscontrol(name, len))
177*4882a593Smuzhiyun 		return -EPERM;
178*4882a593Smuzhiyun 
179*4882a593Smuzhiyun 	attrs.va_mode = mode;
180*4882a593Smuzhiyun 	error = venus_mkdir(dir->i_sb, coda_i2f(dir),
181*4882a593Smuzhiyun 			       name, len, &newfid, &attrs);
182*4882a593Smuzhiyun 	if (error)
183*4882a593Smuzhiyun 		goto err_out;
184*4882a593Smuzhiyun 
185*4882a593Smuzhiyun 	inode = coda_iget(dir->i_sb, &newfid, &attrs);
186*4882a593Smuzhiyun 	if (IS_ERR(inode)) {
187*4882a593Smuzhiyun 		error = PTR_ERR(inode);
188*4882a593Smuzhiyun 		goto err_out;
189*4882a593Smuzhiyun 	}
190*4882a593Smuzhiyun 
191*4882a593Smuzhiyun 	/* invalidate the directory cnode's attributes */
192*4882a593Smuzhiyun 	coda_dir_inc_nlink(dir);
193*4882a593Smuzhiyun 	coda_dir_update_mtime(dir);
194*4882a593Smuzhiyun 	d_instantiate(de, inode);
195*4882a593Smuzhiyun 	return 0;
196*4882a593Smuzhiyun err_out:
197*4882a593Smuzhiyun 	d_drop(de);
198*4882a593Smuzhiyun 	return error;
199*4882a593Smuzhiyun }
200*4882a593Smuzhiyun 
201*4882a593Smuzhiyun /* try to make de an entry in dir_inodde linked to source_de */
coda_link(struct dentry * source_de,struct inode * dir_inode,struct dentry * de)202*4882a593Smuzhiyun static int coda_link(struct dentry *source_de, struct inode *dir_inode,
203*4882a593Smuzhiyun 	  struct dentry *de)
204*4882a593Smuzhiyun {
205*4882a593Smuzhiyun 	struct inode *inode = d_inode(source_de);
206*4882a593Smuzhiyun         const char * name = de->d_name.name;
207*4882a593Smuzhiyun 	int len = de->d_name.len;
208*4882a593Smuzhiyun 	int error;
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun 	if (is_root_inode(dir_inode) && coda_iscontrol(name, len))
211*4882a593Smuzhiyun 		return -EPERM;
212*4882a593Smuzhiyun 
213*4882a593Smuzhiyun 	error = venus_link(dir_inode->i_sb, coda_i2f(inode),
214*4882a593Smuzhiyun 			   coda_i2f(dir_inode), (const char *)name, len);
215*4882a593Smuzhiyun 	if (error) {
216*4882a593Smuzhiyun 		d_drop(de);
217*4882a593Smuzhiyun 		return error;
218*4882a593Smuzhiyun 	}
219*4882a593Smuzhiyun 
220*4882a593Smuzhiyun 	coda_dir_update_mtime(dir_inode);
221*4882a593Smuzhiyun 	ihold(inode);
222*4882a593Smuzhiyun 	d_instantiate(de, inode);
223*4882a593Smuzhiyun 	inc_nlink(inode);
224*4882a593Smuzhiyun 	return 0;
225*4882a593Smuzhiyun }
226*4882a593Smuzhiyun 
227*4882a593Smuzhiyun 
coda_symlink(struct inode * dir_inode,struct dentry * de,const char * symname)228*4882a593Smuzhiyun static int coda_symlink(struct inode *dir_inode, struct dentry *de,
229*4882a593Smuzhiyun 			const char *symname)
230*4882a593Smuzhiyun {
231*4882a593Smuzhiyun 	const char *name = de->d_name.name;
232*4882a593Smuzhiyun 	int len = de->d_name.len;
233*4882a593Smuzhiyun 	int symlen;
234*4882a593Smuzhiyun 	int error;
235*4882a593Smuzhiyun 
236*4882a593Smuzhiyun 	if (is_root_inode(dir_inode) && coda_iscontrol(name, len))
237*4882a593Smuzhiyun 		return -EPERM;
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun 	symlen = strlen(symname);
240*4882a593Smuzhiyun 	if (symlen > CODA_MAXPATHLEN)
241*4882a593Smuzhiyun 		return -ENAMETOOLONG;
242*4882a593Smuzhiyun 
243*4882a593Smuzhiyun 	/*
244*4882a593Smuzhiyun 	 * This entry is now negative. Since we do not create
245*4882a593Smuzhiyun 	 * an inode for the entry we have to drop it.
246*4882a593Smuzhiyun 	 */
247*4882a593Smuzhiyun 	d_drop(de);
248*4882a593Smuzhiyun 	error = venus_symlink(dir_inode->i_sb, coda_i2f(dir_inode), name, len,
249*4882a593Smuzhiyun 			      symname, symlen);
250*4882a593Smuzhiyun 
251*4882a593Smuzhiyun 	/* mtime is no good anymore */
252*4882a593Smuzhiyun 	if (!error)
253*4882a593Smuzhiyun 		coda_dir_update_mtime(dir_inode);
254*4882a593Smuzhiyun 
255*4882a593Smuzhiyun 	return error;
256*4882a593Smuzhiyun }
257*4882a593Smuzhiyun 
258*4882a593Smuzhiyun /* destruction routines: unlink, rmdir */
coda_unlink(struct inode * dir,struct dentry * de)259*4882a593Smuzhiyun static int coda_unlink(struct inode *dir, struct dentry *de)
260*4882a593Smuzhiyun {
261*4882a593Smuzhiyun         int error;
262*4882a593Smuzhiyun 	const char *name = de->d_name.name;
263*4882a593Smuzhiyun 	int len = de->d_name.len;
264*4882a593Smuzhiyun 
265*4882a593Smuzhiyun 	error = venus_remove(dir->i_sb, coda_i2f(dir), name, len);
266*4882a593Smuzhiyun 	if (error)
267*4882a593Smuzhiyun 		return error;
268*4882a593Smuzhiyun 
269*4882a593Smuzhiyun 	coda_dir_update_mtime(dir);
270*4882a593Smuzhiyun 	drop_nlink(d_inode(de));
271*4882a593Smuzhiyun 	return 0;
272*4882a593Smuzhiyun }
273*4882a593Smuzhiyun 
coda_rmdir(struct inode * dir,struct dentry * de)274*4882a593Smuzhiyun static int coda_rmdir(struct inode *dir, struct dentry *de)
275*4882a593Smuzhiyun {
276*4882a593Smuzhiyun 	const char *name = de->d_name.name;
277*4882a593Smuzhiyun 	int len = de->d_name.len;
278*4882a593Smuzhiyun 	int error;
279*4882a593Smuzhiyun 
280*4882a593Smuzhiyun 	error = venus_rmdir(dir->i_sb, coda_i2f(dir), name, len);
281*4882a593Smuzhiyun 	if (!error) {
282*4882a593Smuzhiyun 		/* VFS may delete the child */
283*4882a593Smuzhiyun 		if (d_really_is_positive(de))
284*4882a593Smuzhiyun 			clear_nlink(d_inode(de));
285*4882a593Smuzhiyun 
286*4882a593Smuzhiyun 		/* fix the link count of the parent */
287*4882a593Smuzhiyun 		coda_dir_drop_nlink(dir);
288*4882a593Smuzhiyun 		coda_dir_update_mtime(dir);
289*4882a593Smuzhiyun 	}
290*4882a593Smuzhiyun 	return error;
291*4882a593Smuzhiyun }
292*4882a593Smuzhiyun 
293*4882a593Smuzhiyun /* rename */
coda_rename(struct inode * old_dir,struct dentry * old_dentry,struct inode * new_dir,struct dentry * new_dentry,unsigned int flags)294*4882a593Smuzhiyun static int coda_rename(struct inode *old_dir, struct dentry *old_dentry,
295*4882a593Smuzhiyun 		       struct inode *new_dir, struct dentry *new_dentry,
296*4882a593Smuzhiyun 		       unsigned int flags)
297*4882a593Smuzhiyun {
298*4882a593Smuzhiyun 	const char *old_name = old_dentry->d_name.name;
299*4882a593Smuzhiyun 	const char *new_name = new_dentry->d_name.name;
300*4882a593Smuzhiyun 	int old_length = old_dentry->d_name.len;
301*4882a593Smuzhiyun 	int new_length = new_dentry->d_name.len;
302*4882a593Smuzhiyun 	int error;
303*4882a593Smuzhiyun 
304*4882a593Smuzhiyun 	if (flags)
305*4882a593Smuzhiyun 		return -EINVAL;
306*4882a593Smuzhiyun 
307*4882a593Smuzhiyun 	error = venus_rename(old_dir->i_sb, coda_i2f(old_dir),
308*4882a593Smuzhiyun 			     coda_i2f(new_dir), old_length, new_length,
309*4882a593Smuzhiyun 			     (const char *) old_name, (const char *)new_name);
310*4882a593Smuzhiyun 	if (!error) {
311*4882a593Smuzhiyun 		if (d_really_is_positive(new_dentry)) {
312*4882a593Smuzhiyun 			if (d_is_dir(new_dentry)) {
313*4882a593Smuzhiyun 				coda_dir_drop_nlink(old_dir);
314*4882a593Smuzhiyun 				coda_dir_inc_nlink(new_dir);
315*4882a593Smuzhiyun 			}
316*4882a593Smuzhiyun 			coda_dir_update_mtime(old_dir);
317*4882a593Smuzhiyun 			coda_dir_update_mtime(new_dir);
318*4882a593Smuzhiyun 			coda_flag_inode(d_inode(new_dentry), C_VATTR);
319*4882a593Smuzhiyun 		} else {
320*4882a593Smuzhiyun 			coda_flag_inode(old_dir, C_VATTR);
321*4882a593Smuzhiyun 			coda_flag_inode(new_dir, C_VATTR);
322*4882a593Smuzhiyun 		}
323*4882a593Smuzhiyun 	}
324*4882a593Smuzhiyun 	return error;
325*4882a593Smuzhiyun }
326*4882a593Smuzhiyun 
CDT2DT(unsigned char cdt)327*4882a593Smuzhiyun static inline unsigned int CDT2DT(unsigned char cdt)
328*4882a593Smuzhiyun {
329*4882a593Smuzhiyun 	unsigned int dt;
330*4882a593Smuzhiyun 
331*4882a593Smuzhiyun 	switch(cdt) {
332*4882a593Smuzhiyun 	case CDT_UNKNOWN: dt = DT_UNKNOWN; break;
333*4882a593Smuzhiyun 	case CDT_FIFO:	  dt = DT_FIFO;    break;
334*4882a593Smuzhiyun 	case CDT_CHR:	  dt = DT_CHR;     break;
335*4882a593Smuzhiyun 	case CDT_DIR:	  dt = DT_DIR;     break;
336*4882a593Smuzhiyun 	case CDT_BLK:	  dt = DT_BLK;     break;
337*4882a593Smuzhiyun 	case CDT_REG:	  dt = DT_REG;     break;
338*4882a593Smuzhiyun 	case CDT_LNK:	  dt = DT_LNK;     break;
339*4882a593Smuzhiyun 	case CDT_SOCK:	  dt = DT_SOCK;    break;
340*4882a593Smuzhiyun 	case CDT_WHT:	  dt = DT_WHT;     break;
341*4882a593Smuzhiyun 	default:	  dt = DT_UNKNOWN; break;
342*4882a593Smuzhiyun 	}
343*4882a593Smuzhiyun 	return dt;
344*4882a593Smuzhiyun }
345*4882a593Smuzhiyun 
346*4882a593Smuzhiyun /* support routines */
coda_venus_readdir(struct file * coda_file,struct dir_context * ctx)347*4882a593Smuzhiyun static int coda_venus_readdir(struct file *coda_file, struct dir_context *ctx)
348*4882a593Smuzhiyun {
349*4882a593Smuzhiyun 	struct coda_file_info *cfi;
350*4882a593Smuzhiyun 	struct coda_inode_info *cii;
351*4882a593Smuzhiyun 	struct file *host_file;
352*4882a593Smuzhiyun 	struct venus_dirent *vdir;
353*4882a593Smuzhiyun 	unsigned long vdir_size = offsetof(struct venus_dirent, d_name);
354*4882a593Smuzhiyun 	unsigned int type;
355*4882a593Smuzhiyun 	struct qstr name;
356*4882a593Smuzhiyun 	ino_t ino;
357*4882a593Smuzhiyun 	int ret;
358*4882a593Smuzhiyun 
359*4882a593Smuzhiyun 	cfi = coda_ftoc(coda_file);
360*4882a593Smuzhiyun 	host_file = cfi->cfi_container;
361*4882a593Smuzhiyun 
362*4882a593Smuzhiyun 	cii = ITOC(file_inode(coda_file));
363*4882a593Smuzhiyun 
364*4882a593Smuzhiyun 	vdir = kmalloc(sizeof(*vdir), GFP_KERNEL);
365*4882a593Smuzhiyun 	if (!vdir) return -ENOMEM;
366*4882a593Smuzhiyun 
367*4882a593Smuzhiyun 	if (!dir_emit_dots(coda_file, ctx))
368*4882a593Smuzhiyun 		goto out;
369*4882a593Smuzhiyun 
370*4882a593Smuzhiyun 	while (1) {
371*4882a593Smuzhiyun 		loff_t pos = ctx->pos - 2;
372*4882a593Smuzhiyun 
373*4882a593Smuzhiyun 		/* read entries from the directory file */
374*4882a593Smuzhiyun 		ret = kernel_read(host_file, vdir, sizeof(*vdir), &pos);
375*4882a593Smuzhiyun 		if (ret < 0) {
376*4882a593Smuzhiyun 			pr_err("%s: read dir %s failed %d\n",
377*4882a593Smuzhiyun 			       __func__, coda_f2s(&cii->c_fid), ret);
378*4882a593Smuzhiyun 			break;
379*4882a593Smuzhiyun 		}
380*4882a593Smuzhiyun 		if (ret == 0) break; /* end of directory file reached */
381*4882a593Smuzhiyun 
382*4882a593Smuzhiyun 		/* catch truncated reads */
383*4882a593Smuzhiyun 		if (ret < vdir_size || ret < vdir_size + vdir->d_namlen) {
384*4882a593Smuzhiyun 			pr_err("%s: short read on %s\n",
385*4882a593Smuzhiyun 			       __func__, coda_f2s(&cii->c_fid));
386*4882a593Smuzhiyun 			ret = -EBADF;
387*4882a593Smuzhiyun 			break;
388*4882a593Smuzhiyun 		}
389*4882a593Smuzhiyun 		/* validate whether the directory file actually makes sense */
390*4882a593Smuzhiyun 		if (vdir->d_reclen < vdir_size + vdir->d_namlen) {
391*4882a593Smuzhiyun 			pr_err("%s: invalid dir %s\n",
392*4882a593Smuzhiyun 			       __func__, coda_f2s(&cii->c_fid));
393*4882a593Smuzhiyun 			ret = -EBADF;
394*4882a593Smuzhiyun 			break;
395*4882a593Smuzhiyun 		}
396*4882a593Smuzhiyun 
397*4882a593Smuzhiyun 		name.len = vdir->d_namlen;
398*4882a593Smuzhiyun 		name.name = vdir->d_name;
399*4882a593Smuzhiyun 
400*4882a593Smuzhiyun 		/* Make sure we skip '.' and '..', we already got those */
401*4882a593Smuzhiyun 		if (name.name[0] == '.' && (name.len == 1 ||
402*4882a593Smuzhiyun 		    (name.name[1] == '.' && name.len == 2)))
403*4882a593Smuzhiyun 			vdir->d_fileno = name.len = 0;
404*4882a593Smuzhiyun 
405*4882a593Smuzhiyun 		/* skip null entries */
406*4882a593Smuzhiyun 		if (vdir->d_fileno && name.len) {
407*4882a593Smuzhiyun 			ino = vdir->d_fileno;
408*4882a593Smuzhiyun 			type = CDT2DT(vdir->d_type);
409*4882a593Smuzhiyun 			if (!dir_emit(ctx, name.name, name.len, ino, type))
410*4882a593Smuzhiyun 				break;
411*4882a593Smuzhiyun 		}
412*4882a593Smuzhiyun 		/* we'll always have progress because d_reclen is unsigned and
413*4882a593Smuzhiyun 		 * we've already established it is non-zero. */
414*4882a593Smuzhiyun 		ctx->pos += vdir->d_reclen;
415*4882a593Smuzhiyun 	}
416*4882a593Smuzhiyun out:
417*4882a593Smuzhiyun 	kfree(vdir);
418*4882a593Smuzhiyun 	return 0;
419*4882a593Smuzhiyun }
420*4882a593Smuzhiyun 
421*4882a593Smuzhiyun /* file operations for directories */
coda_readdir(struct file * coda_file,struct dir_context * ctx)422*4882a593Smuzhiyun static int coda_readdir(struct file *coda_file, struct dir_context *ctx)
423*4882a593Smuzhiyun {
424*4882a593Smuzhiyun 	struct coda_file_info *cfi;
425*4882a593Smuzhiyun 	struct file *host_file;
426*4882a593Smuzhiyun 	int ret;
427*4882a593Smuzhiyun 
428*4882a593Smuzhiyun 	cfi = coda_ftoc(coda_file);
429*4882a593Smuzhiyun 	host_file = cfi->cfi_container;
430*4882a593Smuzhiyun 
431*4882a593Smuzhiyun 	if (host_file->f_op->iterate || host_file->f_op->iterate_shared) {
432*4882a593Smuzhiyun 		struct inode *host_inode = file_inode(host_file);
433*4882a593Smuzhiyun 		ret = -ENOENT;
434*4882a593Smuzhiyun 		if (!IS_DEADDIR(host_inode)) {
435*4882a593Smuzhiyun 			if (host_file->f_op->iterate_shared) {
436*4882a593Smuzhiyun 				inode_lock_shared(host_inode);
437*4882a593Smuzhiyun 				ret = host_file->f_op->iterate_shared(host_file, ctx);
438*4882a593Smuzhiyun 				file_accessed(host_file);
439*4882a593Smuzhiyun 				inode_unlock_shared(host_inode);
440*4882a593Smuzhiyun 			} else {
441*4882a593Smuzhiyun 				inode_lock(host_inode);
442*4882a593Smuzhiyun 				ret = host_file->f_op->iterate(host_file, ctx);
443*4882a593Smuzhiyun 				file_accessed(host_file);
444*4882a593Smuzhiyun 				inode_unlock(host_inode);
445*4882a593Smuzhiyun 			}
446*4882a593Smuzhiyun 		}
447*4882a593Smuzhiyun 		return ret;
448*4882a593Smuzhiyun 	}
449*4882a593Smuzhiyun 	/* Venus: we must read Venus dirents from a file */
450*4882a593Smuzhiyun 	return coda_venus_readdir(coda_file, ctx);
451*4882a593Smuzhiyun }
452*4882a593Smuzhiyun 
453*4882a593Smuzhiyun /* called when a cache lookup succeeds */
coda_dentry_revalidate(struct dentry * de,unsigned int flags)454*4882a593Smuzhiyun static int coda_dentry_revalidate(struct dentry *de, unsigned int flags)
455*4882a593Smuzhiyun {
456*4882a593Smuzhiyun 	struct inode *inode;
457*4882a593Smuzhiyun 	struct coda_inode_info *cii;
458*4882a593Smuzhiyun 
459*4882a593Smuzhiyun 	if (flags & LOOKUP_RCU)
460*4882a593Smuzhiyun 		return -ECHILD;
461*4882a593Smuzhiyun 
462*4882a593Smuzhiyun 	inode = d_inode(de);
463*4882a593Smuzhiyun 	if (!inode || is_root_inode(inode))
464*4882a593Smuzhiyun 		goto out;
465*4882a593Smuzhiyun 	if (is_bad_inode(inode))
466*4882a593Smuzhiyun 		goto bad;
467*4882a593Smuzhiyun 
468*4882a593Smuzhiyun 	cii = ITOC(d_inode(de));
469*4882a593Smuzhiyun 	if (!(cii->c_flags & (C_PURGE | C_FLUSH)))
470*4882a593Smuzhiyun 		goto out;
471*4882a593Smuzhiyun 
472*4882a593Smuzhiyun 	shrink_dcache_parent(de);
473*4882a593Smuzhiyun 
474*4882a593Smuzhiyun 	/* propagate for a flush */
475*4882a593Smuzhiyun 	if (cii->c_flags & C_FLUSH)
476*4882a593Smuzhiyun 		coda_flag_inode_children(inode, C_FLUSH);
477*4882a593Smuzhiyun 
478*4882a593Smuzhiyun 	if (d_count(de) > 1)
479*4882a593Smuzhiyun 		/* pretend it's valid, but don't change the flags */
480*4882a593Smuzhiyun 		goto out;
481*4882a593Smuzhiyun 
482*4882a593Smuzhiyun 	/* clear the flags. */
483*4882a593Smuzhiyun 	spin_lock(&cii->c_lock);
484*4882a593Smuzhiyun 	cii->c_flags &= ~(C_VATTR | C_PURGE | C_FLUSH);
485*4882a593Smuzhiyun 	spin_unlock(&cii->c_lock);
486*4882a593Smuzhiyun bad:
487*4882a593Smuzhiyun 	return 0;
488*4882a593Smuzhiyun out:
489*4882a593Smuzhiyun 	return 1;
490*4882a593Smuzhiyun }
491*4882a593Smuzhiyun 
492*4882a593Smuzhiyun /*
493*4882a593Smuzhiyun  * This is the callback from dput() when d_count is going to 0.
494*4882a593Smuzhiyun  * We use this to unhash dentries with bad inodes.
495*4882a593Smuzhiyun  */
coda_dentry_delete(const struct dentry * dentry)496*4882a593Smuzhiyun static int coda_dentry_delete(const struct dentry * dentry)
497*4882a593Smuzhiyun {
498*4882a593Smuzhiyun 	int flags;
499*4882a593Smuzhiyun 
500*4882a593Smuzhiyun 	if (d_really_is_negative(dentry))
501*4882a593Smuzhiyun 		return 0;
502*4882a593Smuzhiyun 
503*4882a593Smuzhiyun 	flags = (ITOC(d_inode(dentry))->c_flags) & C_PURGE;
504*4882a593Smuzhiyun 	if (is_bad_inode(d_inode(dentry)) || flags) {
505*4882a593Smuzhiyun 		return 1;
506*4882a593Smuzhiyun 	}
507*4882a593Smuzhiyun 	return 0;
508*4882a593Smuzhiyun }
509*4882a593Smuzhiyun 
510*4882a593Smuzhiyun 
511*4882a593Smuzhiyun 
512*4882a593Smuzhiyun /*
513*4882a593Smuzhiyun  * This is called when we want to check if the inode has
514*4882a593Smuzhiyun  * changed on the server.  Coda makes this easy since the
515*4882a593Smuzhiyun  * cache manager Venus issues a downcall to the kernel when this
516*4882a593Smuzhiyun  * happens
517*4882a593Smuzhiyun  */
coda_revalidate_inode(struct inode * inode)518*4882a593Smuzhiyun int coda_revalidate_inode(struct inode *inode)
519*4882a593Smuzhiyun {
520*4882a593Smuzhiyun 	struct coda_vattr attr;
521*4882a593Smuzhiyun 	int error;
522*4882a593Smuzhiyun 	int old_mode;
523*4882a593Smuzhiyun 	ino_t old_ino;
524*4882a593Smuzhiyun 	struct coda_inode_info *cii = ITOC(inode);
525*4882a593Smuzhiyun 
526*4882a593Smuzhiyun 	if (!cii->c_flags)
527*4882a593Smuzhiyun 		return 0;
528*4882a593Smuzhiyun 
529*4882a593Smuzhiyun 	if (cii->c_flags & (C_VATTR | C_PURGE | C_FLUSH)) {
530*4882a593Smuzhiyun 		error = venus_getattr(inode->i_sb, &(cii->c_fid), &attr);
531*4882a593Smuzhiyun 		if (error)
532*4882a593Smuzhiyun 			return -EIO;
533*4882a593Smuzhiyun 
534*4882a593Smuzhiyun 		/* this inode may be lost if:
535*4882a593Smuzhiyun 		   - it's ino changed
536*4882a593Smuzhiyun 		   - type changes must be permitted for repair and
537*4882a593Smuzhiyun 		   missing mount points.
538*4882a593Smuzhiyun 		*/
539*4882a593Smuzhiyun 		old_mode = inode->i_mode;
540*4882a593Smuzhiyun 		old_ino = inode->i_ino;
541*4882a593Smuzhiyun 		coda_vattr_to_iattr(inode, &attr);
542*4882a593Smuzhiyun 
543*4882a593Smuzhiyun 		if ((old_mode & S_IFMT) != (inode->i_mode & S_IFMT)) {
544*4882a593Smuzhiyun 			pr_warn("inode %ld, fid %s changed type!\n",
545*4882a593Smuzhiyun 				inode->i_ino, coda_f2s(&(cii->c_fid)));
546*4882a593Smuzhiyun 		}
547*4882a593Smuzhiyun 
548*4882a593Smuzhiyun 		/* the following can happen when a local fid is replaced
549*4882a593Smuzhiyun 		   with a global one, here we lose and declare the inode bad */
550*4882a593Smuzhiyun 		if (inode->i_ino != old_ino)
551*4882a593Smuzhiyun 			return -EIO;
552*4882a593Smuzhiyun 
553*4882a593Smuzhiyun 		coda_flag_inode_children(inode, C_FLUSH);
554*4882a593Smuzhiyun 
555*4882a593Smuzhiyun 		spin_lock(&cii->c_lock);
556*4882a593Smuzhiyun 		cii->c_flags &= ~(C_VATTR | C_PURGE | C_FLUSH);
557*4882a593Smuzhiyun 		spin_unlock(&cii->c_lock);
558*4882a593Smuzhiyun 	}
559*4882a593Smuzhiyun 	return 0;
560*4882a593Smuzhiyun }
561*4882a593Smuzhiyun 
562*4882a593Smuzhiyun const struct dentry_operations coda_dentry_operations = {
563*4882a593Smuzhiyun 	.d_revalidate	= coda_dentry_revalidate,
564*4882a593Smuzhiyun 	.d_delete	= coda_dentry_delete,
565*4882a593Smuzhiyun };
566*4882a593Smuzhiyun 
567*4882a593Smuzhiyun const struct inode_operations coda_dir_inode_operations = {
568*4882a593Smuzhiyun 	.create		= coda_create,
569*4882a593Smuzhiyun 	.lookup		= coda_lookup,
570*4882a593Smuzhiyun 	.link		= coda_link,
571*4882a593Smuzhiyun 	.unlink		= coda_unlink,
572*4882a593Smuzhiyun 	.symlink	= coda_symlink,
573*4882a593Smuzhiyun 	.mkdir		= coda_mkdir,
574*4882a593Smuzhiyun 	.rmdir		= coda_rmdir,
575*4882a593Smuzhiyun 	.mknod		= CODA_EIO_ERROR,
576*4882a593Smuzhiyun 	.rename		= coda_rename,
577*4882a593Smuzhiyun 	.permission	= coda_permission,
578*4882a593Smuzhiyun 	.getattr	= coda_getattr,
579*4882a593Smuzhiyun 	.setattr	= coda_setattr,
580*4882a593Smuzhiyun };
581*4882a593Smuzhiyun 
582*4882a593Smuzhiyun const struct file_operations coda_dir_operations = {
583*4882a593Smuzhiyun 	.llseek		= generic_file_llseek,
584*4882a593Smuzhiyun 	.read		= generic_read_dir,
585*4882a593Smuzhiyun 	.iterate	= coda_readdir,
586*4882a593Smuzhiyun 	.open		= coda_open,
587*4882a593Smuzhiyun 	.release	= coda_release,
588*4882a593Smuzhiyun 	.fsync		= coda_fsync,
589*4882a593Smuzhiyun };
590