Blame view

fs/coda/dir.c 14.2 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
  
  /*
   * Directory operations for Coda filesystem
   * Original version: (C) 1996 P. Braam and M. Callahan
   * Rewritten for Linux 2.1. (C) 1997 Carnegie Mellon University
   * 
   * Carnegie Mellon encourages users to contribute improvements to
   * the Coda project. Contact Peter Braam (coda@cs.cmu.edu).
   */
  
  #include <linux/types.h>
  #include <linux/kernel.h>
  #include <linux/time.h>
  #include <linux/fs.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
15
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
16
17
18
19
  #include <linux/file.h>
  #include <linux/stat.h>
  #include <linux/errno.h>
  #include <linux/string.h>
b5ce1d83a   Yoshihisa Abe   Coda: add spin lo...
20
  #include <linux/spinlock.h>
34286d666   Nick Piggin   fs: rcu-walk awar...
21
  #include <linux/namei.h>
834b46c37   Fabian Frederick   fs/coda: use linu...
22
  #include <linux/uaccess.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23
24
  
  #include <linux/coda.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
25
  #include <linux/coda_psdev.h>
31a203df9   Al Viro   take coda-private...
26
27
  #include "coda_linux.h"
  #include "coda_cache.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
28

c98d8cfbc   Adrian Bunk   [PATCH] fs/coda/:...
29
  #include "coda_int.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
30
31
32
33
34
35
  /* same as fs/bad_inode.c */
  static int coda_return_EIO(void)
  {
  	return -EIO;
  }
  #define CODA_EIO_ERROR ((void *) (coda_return_EIO))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
36
37
  /* inode operations for directories */
  /* access routines: lookup, readlink, permission */
00cd8dd3b   Al Viro   stop passing name...
38
  static struct dentry *coda_lookup(struct inode *dir, struct dentry *entry, unsigned int flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
39
  {
f4947fbce   Al Viro   coda: switch coda...
40
  	struct super_block *sb = dir->i_sb;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
41
42
  	const char *name = entry->d_name.name;
  	size_t length = entry->d_name.len;
f4947fbce   Al Viro   coda: switch coda...
43
44
  	struct inode *inode;
  	int type = 0;
ed36f7236   Jan Harkes   coda: cleanup cod...
45
46
  
  	if (length > CODA_MAXNAMLEN) {
d9b4b3195   Fabian Frederick   fs/coda: replace ...
47
48
  		pr_err("name too long: lookup, %s (%*s)
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
49
50
51
  		       coda_i2s(dir), (int)length, name);
  		return ERR_PTR(-ENAMETOOLONG);
  	}
ed36f7236   Jan Harkes   coda: cleanup cod...
52
  	/* control object, create inode on the fly */
a7400222e   Al Viro   new helper: is_ro...
53
  	if (is_root_inode(dir) && coda_iscontrol(name, length)) {
f4947fbce   Al Viro   coda: switch coda...
54
  		inode = coda_cnode_makectl(sb);
ed36f7236   Jan Harkes   coda: cleanup cod...
55
  		type = CODA_NOCACHE;
f4947fbce   Al Viro   coda: switch coda...
56
57
58
59
60
  	} else {
  		struct CodaFid fid = { { 0, } };
  		int error = venus_lookup(sb, coda_i2f(dir), name, length,
  				     &type, &fid);
  		inode = !error ? coda_cnode_make(&fid, sb) : ERR_PTR(error);
ed36f7236   Jan Harkes   coda: cleanup cod...
61
  	}
f4947fbce   Al Viro   coda: switch coda...
62
  	if (!IS_ERR(inode) && (type & CODA_NOCACHE))
ed36f7236   Jan Harkes   coda: cleanup cod...
63
  		coda_flag_inode(inode, C_VATTR | C_PURGE);
f4947fbce   Al Viro   coda: switch coda...
64
65
  	if (inode == ERR_PTR(-ENOENT))
  		inode = NULL;
ed36f7236   Jan Harkes   coda: cleanup cod...
66
  	return d_splice_alias(inode, entry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
67
  }
10556cb21   Al Viro   ->permission() sa...
68
  int coda_permission(struct inode *inode, int mask)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
69
  {
f7cc02b87   Yoshihisa Abe   Coda: push BKL re...
70
  	int error;
e6305c43e   Al Viro   [PATCH] sanitize ...
71

10556cb21   Al Viro   ->permission() sa...
72
  	if (mask & MAY_NOT_BLOCK)
b74c79e99   Nick Piggin   fs: provide rcu-w...
73
  		return -ECHILD;
e6305c43e   Al Viro   [PATCH] sanitize ...
74
  	mask &= MAY_READ | MAY_WRITE | MAY_EXEC;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
75
76
   
  	if (!mask)
f7cc02b87   Yoshihisa Abe   Coda: push BKL re...
77
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
78

f696a3659   Miklos Szeredi   [PATCH] move exec...
79
80
  	if ((mask & MAY_EXEC) && !execute_ok(inode))
  		return -EACCES;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
81
  	if (coda_cache_check(inode, mask))
f7cc02b87   Yoshihisa Abe   Coda: push BKL re...
82
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
83

f7cc02b87   Yoshihisa Abe   Coda: push BKL re...
84
  	error = venus_access(inode->i_sb, coda_i2f(inode), mask);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
85
86
87
      
  	if (!error)
  		coda_cache_enter(inode, mask);
d728900cd   Jan Harkes   coda: fix nlink u...
88
  	return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
89
  }
d728900cd   Jan Harkes   coda: fix nlink u...
90
  static inline void coda_dir_update_mtime(struct inode *dir)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
91
92
93
94
95
96
97
  {
  #ifdef REQUERY_VENUS_FOR_MTIME
  	/* invalidate the directory cnode's attributes so we refetch the
  	 * attributes from venus next time the inode is referenced */
  	coda_flag_inode(dir, C_VATTR);
  #else
  	/* optimistically we can also act as if our nose bleeds. The
d728900cd   Jan Harkes   coda: fix nlink u...
98
99
  	 * granularity of the mtime is coarse anyways so we might actually be
  	 * right most of the time. Note: we only do this for directories. */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
100
101
  	dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
  #endif
d728900cd   Jan Harkes   coda: fix nlink u...
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
  }
  
  /* we have to wrap inc_nlink/drop_nlink because sometimes userspace uses a
   * trick to fool GNU find's optimizations. If we can't be sure of the link
   * (because of volume mount points) we set i_nlink to 1 which forces find
   * to consider every child as a possible directory. We should also never
   * see an increment or decrement for deleted directories where i_nlink == 0 */
  static inline void coda_dir_inc_nlink(struct inode *dir)
  {
  	if (dir->i_nlink >= 2)
  		inc_nlink(dir);
  }
  
  static inline void coda_dir_drop_nlink(struct inode *dir)
  {
  	if (dir->i_nlink > 2)
  		drop_nlink(dir);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
119
120
121
  }
  
  /* creation routines: create, mknod, mkdir, link, symlink */
ebfc3b49a   Al Viro   don't pass nameid...
122
  static int coda_create(struct inode *dir, struct dentry *de, umode_t mode, bool excl)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
123
  {
f7cc02b87   Yoshihisa Abe   Coda: push BKL re...
124
  	int error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
125
126
127
128
129
  	const char *name=de->d_name.name;
  	int length=de->d_name.len;
  	struct inode *inode;
  	struct CodaFid newfid;
  	struct coda_vattr attrs;
a7400222e   Al Viro   new helper: is_ro...
130
  	if (is_root_inode(dir) && coda_iscontrol(name, length))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
131
  		return -EPERM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
132
133
134
  
  	error = venus_create(dir->i_sb, coda_i2f(dir), name, length, 
  				0, mode, &newfid, &attrs);
f7cc02b87   Yoshihisa Abe   Coda: push BKL re...
135
136
  	if (error)
  		goto err_out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
137
138
  
  	inode = coda_iget(dir->i_sb, &newfid, &attrs);
f7cc02b87   Yoshihisa Abe   Coda: push BKL re...
139
140
141
  	if (IS_ERR(inode)) {
  		error = PTR_ERR(inode);
  		goto err_out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
142
143
144
  	}
  
  	/* invalidate the directory cnode's attributes */
d728900cd   Jan Harkes   coda: fix nlink u...
145
  	coda_dir_update_mtime(dir);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
146
  	d_instantiate(de, inode);
d728900cd   Jan Harkes   coda: fix nlink u...
147
  	return 0;
f7cc02b87   Yoshihisa Abe   Coda: push BKL re...
148
149
150
  err_out:
  	d_drop(de);
  	return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
151
  }
18bb1db3e   Al Viro   switch vfs_mkdir(...
152
  static int coda_mkdir(struct inode *dir, struct dentry *de, umode_t mode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
153
154
155
156
157
158
159
  {
  	struct inode *inode;
  	struct coda_vattr attrs;
  	const char *name = de->d_name.name;
  	int len = de->d_name.len;
  	int error;
  	struct CodaFid newfid;
a7400222e   Al Viro   new helper: is_ro...
160
  	if (is_root_inode(dir) && coda_iscontrol(name, len))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
161
  		return -EPERM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
162
163
164
165
  
  	attrs.va_mode = mode;
  	error = venus_mkdir(dir->i_sb, coda_i2f(dir), 
  			       name, len, &newfid, &attrs);
f7cc02b87   Yoshihisa Abe   Coda: push BKL re...
166
167
  	if (error)
  		goto err_out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
168
169
           
  	inode = coda_iget(dir->i_sb, &newfid, &attrs);
f7cc02b87   Yoshihisa Abe   Coda: push BKL re...
170
171
172
  	if (IS_ERR(inode)) {
  		error = PTR_ERR(inode);
  		goto err_out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
173
  	}
d728900cd   Jan Harkes   coda: fix nlink u...
174

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
175
  	/* invalidate the directory cnode's attributes */
d728900cd   Jan Harkes   coda: fix nlink u...
176
177
  	coda_dir_inc_nlink(dir);
  	coda_dir_update_mtime(dir);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
178
  	d_instantiate(de, inode);
d728900cd   Jan Harkes   coda: fix nlink u...
179
  	return 0;
f7cc02b87   Yoshihisa Abe   Coda: push BKL re...
180
181
182
  err_out:
  	d_drop(de);
  	return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
183
184
185
186
187
188
  }
  
  /* try to make de an entry in dir_inodde linked to source_de */ 
  static int coda_link(struct dentry *source_de, struct inode *dir_inode, 
  	  struct dentry *de)
  {
2b0143b5c   David Howells   VFS: normal files...
189
  	struct inode *inode = d_inode(source_de);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
190
191
192
          const char * name = de->d_name.name;
  	int len = de->d_name.len;
  	int error;
a7400222e   Al Viro   new helper: is_ro...
193
  	if (is_root_inode(dir_inode) && coda_iscontrol(name, len))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
194
  		return -EPERM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
195
196
197
  
  	error = venus_link(dir_inode->i_sb, coda_i2f(inode),
  			   coda_i2f(dir_inode), (const char *)name, len);
d728900cd   Jan Harkes   coda: fix nlink u...
198
  	if (error) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
199
  		d_drop(de);
f7cc02b87   Yoshihisa Abe   Coda: push BKL re...
200
  		return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
201
  	}
d728900cd   Jan Harkes   coda: fix nlink u...
202
  	coda_dir_update_mtime(dir_inode);
7de9c6ee3   Al Viro   new helper: ihold()
203
  	ihold(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
204
  	d_instantiate(de, inode);
d8c76e6f4   Dave Hansen   [PATCH] r/o bind ...
205
  	inc_nlink(inode);
f7cc02b87   Yoshihisa Abe   Coda: push BKL re...
206
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
207
208
209
210
211
212
  }
  
  
  static int coda_symlink(struct inode *dir_inode, struct dentry *de,
  			const char *symname)
  {
f7cc02b87   Yoshihisa Abe   Coda: push BKL re...
213
  	const char *name = de->d_name.name;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
214
215
  	int len = de->d_name.len;
  	int symlen;
f7cc02b87   Yoshihisa Abe   Coda: push BKL re...
216
  	int error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
217

a7400222e   Al Viro   new helper: is_ro...
218
  	if (is_root_inode(dir_inode) && coda_iscontrol(name, len))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
219
  		return -EPERM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
220
221
  
  	symlen = strlen(symname);
f7cc02b87   Yoshihisa Abe   Coda: push BKL re...
222
  	if (symlen > CODA_MAXPATHLEN)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
223
  		return -ENAMETOOLONG;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
224
225
226
  
  	/*
  	 * This entry is now negative. Since we do not create
d728900cd   Jan Harkes   coda: fix nlink u...
227
  	 * an inode for the entry we have to drop it.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
228
229
  	 */
  	d_drop(de);
d728900cd   Jan Harkes   coda: fix nlink u...
230
  	error = venus_symlink(dir_inode->i_sb, coda_i2f(dir_inode), name, len,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
231
232
233
  			      symname, symlen);
  
  	/* mtime is no good anymore */
f7cc02b87   Yoshihisa Abe   Coda: push BKL re...
234
  	if (!error)
d728900cd   Jan Harkes   coda: fix nlink u...
235
  		coda_dir_update_mtime(dir_inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
236

d728900cd   Jan Harkes   coda: fix nlink u...
237
  	return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
238
239
240
  }
  
  /* destruction routines: unlink, rmdir */
9fe76c763   Harvey Harrison   coda: add static ...
241
  static int coda_unlink(struct inode *dir, struct dentry *de)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
242
243
244
245
  {
          int error;
  	const char *name = de->d_name.name;
  	int len = de->d_name.len;
d728900cd   Jan Harkes   coda: fix nlink u...
246
  	error = venus_remove(dir->i_sb, coda_i2f(dir), name, len);
f7cc02b87   Yoshihisa Abe   Coda: push BKL re...
247
  	if (error)
d728900cd   Jan Harkes   coda: fix nlink u...
248
  		return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
249

d728900cd   Jan Harkes   coda: fix nlink u...
250
  	coda_dir_update_mtime(dir);
2b0143b5c   David Howells   VFS: normal files...
251
  	drop_nlink(d_inode(de));
d728900cd   Jan Harkes   coda: fix nlink u...
252
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
253
  }
9fe76c763   Harvey Harrison   coda: add static ...
254
  static int coda_rmdir(struct inode *dir, struct dentry *de)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
255
256
257
  {
  	const char *name = de->d_name.name;
  	int len = de->d_name.len;
8c6d21528   Jan Harkes   coda: allow remov...
258
  	int error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
259

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
260
  	error = venus_rmdir(dir->i_sb, coda_i2f(dir), name, len);
8c6d21528   Jan Harkes   coda: allow remov...
261
262
  	if (!error) {
  		/* VFS may delete the child */
2b0143b5c   David Howells   VFS: normal files...
263
264
  		if (d_really_is_positive(de))
  			clear_nlink(d_inode(de));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
265

8c6d21528   Jan Harkes   coda: allow remov...
266
267
268
  		/* fix the link count of the parent */
  		coda_dir_drop_nlink(dir);
  		coda_dir_update_mtime(dir);
d728900cd   Jan Harkes   coda: fix nlink u...
269
  	}
8c6d21528   Jan Harkes   coda: allow remov...
270
  	return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
271
272
273
  }
  
  /* rename */
d728900cd   Jan Harkes   coda: fix nlink u...
274
  static int coda_rename(struct inode *old_dir, struct dentry *old_dentry,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
275
276
  		       struct inode *new_dir, struct dentry *new_dentry)
  {
d728900cd   Jan Harkes   coda: fix nlink u...
277
278
  	const char *old_name = old_dentry->d_name.name;
  	const char *new_name = new_dentry->d_name.name;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
279
280
  	int old_length = old_dentry->d_name.len;
  	int new_length = new_dentry->d_name.len;
d728900cd   Jan Harkes   coda: fix nlink u...
281
  	int error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
282

d728900cd   Jan Harkes   coda: fix nlink u...
283
284
  	error = venus_rename(old_dir->i_sb, coda_i2f(old_dir),
  			     coda_i2f(new_dir), old_length, new_length,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
285
  			     (const char *) old_name, (const char *)new_name);
f7cc02b87   Yoshihisa Abe   Coda: push BKL re...
286
  	if (!error) {
2b0143b5c   David Howells   VFS: normal files...
287
  		if (d_really_is_positive(new_dentry)) {
e36cb0b89   David Howells   VFS: (Scripted) C...
288
  			if (d_is_dir(new_dentry)) {
d728900cd   Jan Harkes   coda: fix nlink u...
289
290
291
292
293
  				coda_dir_drop_nlink(old_dir);
  				coda_dir_inc_nlink(new_dir);
  			}
  			coda_dir_update_mtime(old_dir);
  			coda_dir_update_mtime(new_dir);
2b0143b5c   David Howells   VFS: normal files...
294
  			coda_flag_inode(d_inode(new_dentry), C_VATTR);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
295
296
297
  		} else {
  			coda_flag_inode(old_dir, C_VATTR);
  			coda_flag_inode(new_dir, C_VATTR);
d728900cd   Jan Harkes   coda: fix nlink u...
298
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
299
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
300
301
  	return error;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
  static inline unsigned int CDT2DT(unsigned char cdt)
  {
  	unsigned int dt;
  
  	switch(cdt) {
  	case CDT_UNKNOWN: dt = DT_UNKNOWN; break;
  	case CDT_FIFO:	  dt = DT_FIFO;    break;
  	case CDT_CHR:	  dt = DT_CHR;     break;
  	case CDT_DIR:	  dt = DT_DIR;     break;
  	case CDT_BLK:	  dt = DT_BLK;     break;
  	case CDT_REG:	  dt = DT_REG;     break;
  	case CDT_LNK:	  dt = DT_LNK;     break;
  	case CDT_SOCK:	  dt = DT_SOCK;    break;
  	case CDT_WHT:	  dt = DT_WHT;     break;
  	default:	  dt = DT_UNKNOWN; break;
  	}
  	return dt;
  }
  
  /* support routines */
e924f2512   Al Viro   [readdir] convert...
322
  static int coda_venus_readdir(struct file *coda_file, struct dir_context *ctx)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
323
  {
978752534   Jan Harkes   coda: avoid lockd...
324
325
326
  	struct coda_file_info *cfi;
  	struct coda_inode_info *cii;
  	struct file *host_file;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
327
  	struct venus_dirent *vdir;
ee60498f3   Al Viro   coda_venus_readdi...
328
  	unsigned long vdir_size = offsetof(struct venus_dirent, d_name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
329
330
331
  	unsigned int type;
  	struct qstr name;
  	ino_t ino;
978752534   Jan Harkes   coda: avoid lockd...
332
333
334
335
336
  	int ret;
  
  	cfi = CODA_FTOC(coda_file);
  	BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
  	host_file = cfi->cfi_container;
93fe74b2e   Al Viro   coda_venus_readdi...
337
  	cii = ITOC(file_inode(coda_file));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
338

f52720ca5   Panagiotis Issaris   [PATCH] fs: Remov...
339
  	vdir = kmalloc(sizeof(*vdir), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
340
  	if (!vdir) return -ENOMEM;
e924f2512   Al Viro   [readdir] convert...
341
342
  	if (!dir_emit_dots(coda_file, ctx))
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
343
344
  	while (1) {
  		/* read entries from the directory file */
e924f2512   Al Viro   [readdir] convert...
345
  		ret = kernel_read(host_file, ctx->pos - 2, (char *)vdir,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
346
347
  				  sizeof(*vdir));
  		if (ret < 0) {
6d6bd94f4   Fabian Frederick   fs/coda: use __fu...
348
349
350
  			pr_err("%s: read dir %s failed %d
  ",
  			       __func__, coda_f2s(&cii->c_fid), ret);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
351
352
353
354
355
356
  			break;
  		}
  		if (ret == 0) break; /* end of directory file reached */
  
  		/* catch truncated reads */
  		if (ret < vdir_size || ret < vdir_size + vdir->d_namlen) {
6d6bd94f4   Fabian Frederick   fs/coda: use __fu...
357
358
359
  			pr_err("%s: short read on %s
  ",
  			       __func__, coda_f2s(&cii->c_fid));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
360
361
362
363
364
  			ret = -EBADF;
  			break;
  		}
  		/* validate whether the directory file actually makes sense */
  		if (vdir->d_reclen < vdir_size + vdir->d_namlen) {
6d6bd94f4   Fabian Frederick   fs/coda: use __fu...
365
366
367
  			pr_err("%s: invalid dir %s
  ",
  			       __func__, coda_f2s(&cii->c_fid));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
368
369
370
371
372
373
374
375
376
  			ret = -EBADF;
  			break;
  		}
  
  		name.len = vdir->d_namlen;
  		name.name = vdir->d_name;
  
  		/* Make sure we skip '.' and '..', we already got those */
  		if (name.name[0] == '.' && (name.len == 1 ||
e924f2512   Al Viro   [readdir] convert...
377
  		    (name.name[1] == '.' && name.len == 2)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
378
379
380
381
  			vdir->d_fileno = name.len = 0;
  
  		/* skip null entries */
  		if (vdir->d_fileno && name.len) {
6b5e1223d   Al Viro   coda: don't bothe...
382
  			ino = vdir->d_fileno;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
383
  			type = CDT2DT(vdir->d_type);
e924f2512   Al Viro   [readdir] convert...
384
385
  			if (!dir_emit(ctx, name.name, name.len, ino, type))
  				break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
386
387
388
  		}
  		/* we'll always have progress because d_reclen is unsigned and
  		 * we've already established it is non-zero. */
e924f2512   Al Viro   [readdir] convert...
389
  		ctx->pos += vdir->d_reclen;
978752534   Jan Harkes   coda: avoid lockd...
390
  	}
5f47c7eac   Al Viro   coda breakage
391
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
392
  	kfree(vdir);
e924f2512   Al Viro   [readdir] convert...
393
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
394
  }
b625032b1   Fabian Frederick   fs/coda/dir.c: fo...
395
396
397
398
399
400
401
402
403
404
  /* file operations for directories */
  static int coda_readdir(struct file *coda_file, struct dir_context *ctx)
  {
  	struct coda_file_info *cfi;
  	struct file *host_file;
  	int ret;
  
  	cfi = CODA_FTOC(coda_file);
  	BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
  	host_file = cfi->cfi_container;
619226944   Al Viro   introduce a paral...
405
  	if (host_file->f_op->iterate || host_file->f_op->iterate_shared) {
b625032b1   Fabian Frederick   fs/coda/dir.c: fo...
406
  		struct inode *host_inode = file_inode(host_file);
b625032b1   Fabian Frederick   fs/coda/dir.c: fo...
407
408
  		ret = -ENOENT;
  		if (!IS_DEADDIR(host_inode)) {
619226944   Al Viro   introduce a paral...
409
410
411
412
413
414
415
416
417
418
419
  			if (host_file->f_op->iterate_shared) {
  				inode_lock_shared(host_inode);
  				ret = host_file->f_op->iterate_shared(host_file, ctx);
  				file_accessed(host_file);
  				inode_unlock_shared(host_inode);
  			} else {
  				inode_lock(host_inode);
  				ret = host_file->f_op->iterate(host_file, ctx);
  				file_accessed(host_file);
  				inode_unlock(host_inode);
  			}
b625032b1   Fabian Frederick   fs/coda/dir.c: fo...
420
  		}
b625032b1   Fabian Frederick   fs/coda/dir.c: fo...
421
422
423
424
425
  		return ret;
  	}
  	/* Venus: we must read Venus dirents from a file */
  	return coda_venus_readdir(coda_file, ctx);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
426
  /* called when a cache lookup succeeds */
0b728e191   Al Viro   stop passing name...
427
  static int coda_dentry_revalidate(struct dentry *de, unsigned int flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
428
  {
34286d666   Nick Piggin   fs: rcu-walk awar...
429
  	struct inode *inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
430
  	struct coda_inode_info *cii;
0b728e191   Al Viro   stop passing name...
431
  	if (flags & LOOKUP_RCU)
34286d666   Nick Piggin   fs: rcu-walk awar...
432
  		return -ECHILD;
2b0143b5c   David Howells   VFS: normal files...
433
  	inode = d_inode(de);
a7400222e   Al Viro   new helper: is_ro...
434
  	if (!inode || is_root_inode(inode))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
435
436
437
  		goto out;
  	if (is_bad_inode(inode))
  		goto bad;
2b0143b5c   David Howells   VFS: normal files...
438
  	cii = ITOC(d_inode(de));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
439
440
441
442
443
444
445
446
  	if (!(cii->c_flags & (C_PURGE | C_FLUSH)))
  		goto out;
  
  	shrink_dcache_parent(de);
  
  	/* propagate for a flush */
  	if (cii->c_flags & C_FLUSH) 
  		coda_flag_inode_children(inode, C_FLUSH);
84d08fa88   Al Viro   helper for readin...
447
  	if (d_count(de) > 1)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
448
449
450
451
  		/* pretend it's valid, but don't change the flags */
  		goto out;
  
  	/* clear the flags. */
b5ce1d83a   Yoshihisa Abe   Coda: add spin lo...
452
  	spin_lock(&cii->c_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
453
  	cii->c_flags &= ~(C_VATTR | C_PURGE | C_FLUSH);
b5ce1d83a   Yoshihisa Abe   Coda: add spin lo...
454
  	spin_unlock(&cii->c_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
455
  bad:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
456
457
  	return 0;
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
458
459
460
461
462
463
464
  	return 1;
  }
  
  /*
   * This is the callback from dput() when d_count is going to 0.
   * We use this to unhash dentries with bad inodes.
   */
fe15ce446   Nick Piggin   fs: change d_dele...
465
  static int coda_dentry_delete(const struct dentry * dentry)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
466
467
  {
  	int flags;
2b0143b5c   David Howells   VFS: normal files...
468
  	if (d_really_is_negative(dentry)) 
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
469
  		return 0;
2b0143b5c   David Howells   VFS: normal files...
470
471
  	flags = (ITOC(d_inode(dentry))->c_flags) & C_PURGE;
  	if (is_bad_inode(d_inode(dentry)) || flags) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
472
473
474
475
476
477
478
479
480
481
482
483
484
  		return 1;
  	}
  	return 0;
  }
  
  
  
  /*
   * This is called when we want to check if the inode has
   * changed on the server.  Coda makes this easy since the
   * cache manager Venus issues a downcall to the kernel when this 
   * happens 
   */
11d100d9a   Al Viro   coda_revalidate_i...
485
  int coda_revalidate_inode(struct inode *inode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
486
487
  {
  	struct coda_vattr attr;
f7cc02b87   Yoshihisa Abe   Coda: push BKL re...
488
  	int error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
489
490
  	int old_mode;
  	ino_t old_ino;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
491
  	struct coda_inode_info *cii = ITOC(inode);
f7cc02b87   Yoshihisa Abe   Coda: push BKL re...
492
493
  	if (!cii->c_flags)
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
494
495
496
  
  	if (cii->c_flags & (C_VATTR | C_PURGE | C_FLUSH)) {
  		error = venus_getattr(inode->i_sb, &(cii->c_fid), &attr);
f7cc02b87   Yoshihisa Abe   Coda: push BKL re...
497
498
  		if (error)
  			return -EIO;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
499
500
501
502
503
504
505
506
507
508
509
  
  		/* this inode may be lost if:
  		   - it's ino changed 
  		   - type changes must be permitted for repair and
  		   missing mount points.
  		*/
  		old_mode = inode->i_mode;
  		old_ino = inode->i_ino;
  		coda_vattr_to_iattr(inode, &attr);
  
  		if ((old_mode & S_IFMT) != (inode->i_mode & S_IFMT)) {
f38cfb256   Fabian Frederick   fs/coda: logging ...
510
511
  			pr_warn("inode %ld, fid %s changed type!
  ",
d9b4b3195   Fabian Frederick   fs/coda: replace ...
512
  				inode->i_ino, coda_f2s(&(cii->c_fid)));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
513
514
515
516
517
  		}
  
  		/* the following can happen when a local fid is replaced 
  		   with a global one, here we lose and declare the inode bad */
  		if (inode->i_ino != old_ino)
f7cc02b87   Yoshihisa Abe   Coda: push BKL re...
518
  			return -EIO;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
519
520
  		
  		coda_flag_inode_children(inode, C_FLUSH);
b5ce1d83a   Yoshihisa Abe   Coda: add spin lo...
521
522
  
  		spin_lock(&cii->c_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
523
  		cii->c_flags &= ~(C_VATTR | C_PURGE | C_FLUSH);
b5ce1d83a   Yoshihisa Abe   Coda: add spin lo...
524
  		spin_unlock(&cii->c_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
525
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
526
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
527
  }
b625032b1   Fabian Frederick   fs/coda/dir.c: fo...
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
  
  const struct dentry_operations coda_dentry_operations = {
  	.d_revalidate	= coda_dentry_revalidate,
  	.d_delete	= coda_dentry_delete,
  };
  
  const struct inode_operations coda_dir_inode_operations = {
  	.create		= coda_create,
  	.lookup		= coda_lookup,
  	.link		= coda_link,
  	.unlink		= coda_unlink,
  	.symlink	= coda_symlink,
  	.mkdir		= coda_mkdir,
  	.rmdir		= coda_rmdir,
  	.mknod		= CODA_EIO_ERROR,
  	.rename		= coda_rename,
  	.permission	= coda_permission,
  	.getattr	= coda_getattr,
  	.setattr	= coda_setattr,
  };
  
  const struct file_operations coda_dir_operations = {
  	.llseek		= generic_file_llseek,
  	.read		= generic_read_dir,
  	.iterate	= coda_readdir,
  	.open		= coda_open,
  	.release	= coda_release,
  	.fsync		= coda_fsync,
  };