Blame view

fs/coda/dir.c 14.2 KB
b24413180   Greg Kroah-Hartman   License cleanup: ...
1
  // SPDX-License-Identifier: GPL-2.0
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  
  /*
   * 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: ...
16
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
17
18
19
20
  #include <linux/file.h>
  #include <linux/stat.h>
  #include <linux/errno.h>
  #include <linux/string.h>
b5ce1d83a   Yoshihisa Abe   Coda: add spin lo...
21
  #include <linux/spinlock.h>
34286d666   Nick Piggin   fs: rcu-walk awar...
22
  #include <linux/namei.h>
834b46c37   Fabian Frederick   fs/coda: use linu...
23
  #include <linux/uaccess.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
25
  
  #include <linux/coda.h>
8fc8b9df8   David Howells   coda: move intern...
26
  #include "coda_psdev.h"
31a203df9   Al Viro   take coda-private...
27
28
  #include "coda_linux.h"
  #include "coda_cache.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
29

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

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

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

f7cc02b87   Yoshihisa Abe   Coda: push BKL re...
85
  	error = venus_access(inode->i_sb, coda_i2f(inode), mask);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
86
87
88
      
  	if (!error)
  		coda_cache_enter(inode, mask);
d728900cd   Jan Harkes   coda: fix nlink u...
89
  	return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
90
  }
d728900cd   Jan Harkes   coda: fix nlink u...
91
  static inline void coda_dir_update_mtime(struct inode *dir)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
92
93
94
95
96
97
98
  {
  #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...
99
100
  	 * granularity of the mtime is coarse anyways so we might actually be
  	 * right most of the time. Note: we only do this for directories. */
02027d42c   Deepa Dinamani   fs: Replace CURRE...
101
  	dir->i_mtime = dir->i_ctime = current_time(dir);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
102
  #endif
d728900cd   Jan Harkes   coda: fix nlink u...
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
  }
  
  /* 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
120
121
122
  }
  
  /* creation routines: create, mknod, mkdir, link, symlink */
ebfc3b49a   Al Viro   don't pass nameid...
123
  static int coda_create(struct inode *dir, struct dentry *de, umode_t mode, bool excl)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
124
  {
f7cc02b87   Yoshihisa Abe   Coda: push BKL re...
125
  	int error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
126
127
128
129
130
  	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...
131
  	if (is_root_inode(dir) && coda_iscontrol(name, length))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
132
  		return -EPERM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
133
134
135
  
  	error = venus_create(dir->i_sb, coda_i2f(dir), name, length, 
  				0, mode, &newfid, &attrs);
f7cc02b87   Yoshihisa Abe   Coda: push BKL re...
136
137
  	if (error)
  		goto err_out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
138
139
  
  	inode = coda_iget(dir->i_sb, &newfid, &attrs);
f7cc02b87   Yoshihisa Abe   Coda: push BKL re...
140
141
142
  	if (IS_ERR(inode)) {
  		error = PTR_ERR(inode);
  		goto err_out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
143
144
145
  	}
  
  	/* invalidate the directory cnode's attributes */
d728900cd   Jan Harkes   coda: fix nlink u...
146
  	coda_dir_update_mtime(dir);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
147
  	d_instantiate(de, inode);
d728900cd   Jan Harkes   coda: fix nlink u...
148
  	return 0;
f7cc02b87   Yoshihisa Abe   Coda: push BKL re...
149
150
151
  err_out:
  	d_drop(de);
  	return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
152
  }
18bb1db3e   Al Viro   switch vfs_mkdir(...
153
  static int coda_mkdir(struct inode *dir, struct dentry *de, umode_t mode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
154
155
156
157
158
159
160
  {
  	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...
161
  	if (is_root_inode(dir) && coda_iscontrol(name, len))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
162
  		return -EPERM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
163
164
165
166
  
  	attrs.va_mode = mode;
  	error = venus_mkdir(dir->i_sb, coda_i2f(dir), 
  			       name, len, &newfid, &attrs);
f7cc02b87   Yoshihisa Abe   Coda: push BKL re...
167
168
  	if (error)
  		goto err_out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
169
170
           
  	inode = coda_iget(dir->i_sb, &newfid, &attrs);
f7cc02b87   Yoshihisa Abe   Coda: push BKL re...
171
172
173
  	if (IS_ERR(inode)) {
  		error = PTR_ERR(inode);
  		goto err_out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
174
  	}
d728900cd   Jan Harkes   coda: fix nlink u...
175

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

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

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

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

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

8c6d21528   Jan Harkes   coda: allow remov...
267
268
269
  		/* fix the link count of the parent */
  		coda_dir_drop_nlink(dir);
  		coda_dir_update_mtime(dir);
d728900cd   Jan Harkes   coda: fix nlink u...
270
  	}
8c6d21528   Jan Harkes   coda: allow remov...
271
  	return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
272
273
274
  }
  
  /* rename */
d728900cd   Jan Harkes   coda: fix nlink u...
275
  static int coda_rename(struct inode *old_dir, struct dentry *old_dentry,
1cd66c93b   Miklos Szeredi   fs: make remainin...
276
277
  		       struct inode *new_dir, struct dentry *new_dentry,
  		       unsigned int flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
278
  {
d728900cd   Jan Harkes   coda: fix nlink u...
279
280
  	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
281
282
  	int old_length = old_dentry->d_name.len;
  	int new_length = new_dentry->d_name.len;
d728900cd   Jan Harkes   coda: fix nlink u...
283
  	int error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
284

1cd66c93b   Miklos Szeredi   fs: make remainin...
285
286
  	if (flags)
  		return -EINVAL;
d728900cd   Jan Harkes   coda: fix nlink u...
287
288
  	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
289
  			     (const char *) old_name, (const char *)new_name);
f7cc02b87   Yoshihisa Abe   Coda: push BKL re...
290
  	if (!error) {
2b0143b5c   David Howells   VFS: normal files...
291
  		if (d_really_is_positive(new_dentry)) {
e36cb0b89   David Howells   VFS: (Scripted) C...
292
  			if (d_is_dir(new_dentry)) {
d728900cd   Jan Harkes   coda: fix nlink u...
293
294
295
296
297
  				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...
298
  			coda_flag_inode(d_inode(new_dentry), C_VATTR);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
299
300
301
  		} else {
  			coda_flag_inode(old_dir, C_VATTR);
  			coda_flag_inode(new_dir, C_VATTR);
d728900cd   Jan Harkes   coda: fix nlink u...
302
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
303
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
304
305
  	return error;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
  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...
326
  static int coda_venus_readdir(struct file *coda_file, struct dir_context *ctx)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
327
  {
978752534   Jan Harkes   coda: avoid lockd...
328
329
330
  	struct coda_file_info *cfi;
  	struct coda_inode_info *cii;
  	struct file *host_file;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
331
  	struct venus_dirent *vdir;
ee60498f3   Al Viro   coda_venus_readdi...
332
  	unsigned long vdir_size = offsetof(struct venus_dirent, d_name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
333
334
335
  	unsigned int type;
  	struct qstr name;
  	ino_t ino;
978752534   Jan Harkes   coda: avoid lockd...
336
  	int ret;
5bb44810f   Fabian Frederick   coda: ftoc validi...
337
  	cfi = coda_ftoc(coda_file);
978752534   Jan Harkes   coda: avoid lockd...
338
  	host_file = cfi->cfi_container;
93fe74b2e   Al Viro   coda_venus_readdi...
339
  	cii = ITOC(file_inode(coda_file));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
340

f52720ca5   Panagiotis Issaris   [PATCH] fs: Remov...
341
  	vdir = kmalloc(sizeof(*vdir), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
342
  	if (!vdir) return -ENOMEM;
e924f2512   Al Viro   [readdir] convert...
343
344
  	if (!dir_emit_dots(coda_file, ctx))
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
345
  	while (1) {
bdd1d2d3d   Christoph Hellwig   fs: fix kernel_re...
346
  		loff_t pos = ctx->pos - 2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
347
  		/* read entries from the directory file */
bdd1d2d3d   Christoph Hellwig   fs: fix kernel_re...
348
  		ret = kernel_read(host_file, vdir, sizeof(*vdir), &pos);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
349
  		if (ret < 0) {
6d6bd94f4   Fabian Frederick   fs/coda: use __fu...
350
351
352
  			pr_err("%s: read dir %s failed %d
  ",
  			       __func__, coda_f2s(&cii->c_fid), ret);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
353
354
355
356
357
358
  			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...
359
360
361
  			pr_err("%s: short read on %s
  ",
  			       __func__, coda_f2s(&cii->c_fid));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
362
363
364
365
366
  			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...
367
368
369
  			pr_err("%s: invalid dir %s
  ",
  			       __func__, coda_f2s(&cii->c_fid));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
370
371
372
373
374
375
376
377
378
  			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...
379
  		    (name.name[1] == '.' && name.len == 2)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
380
381
382
383
  			vdir->d_fileno = name.len = 0;
  
  		/* skip null entries */
  		if (vdir->d_fileno && name.len) {
6b5e1223d   Al Viro   coda: don't bothe...
384
  			ino = vdir->d_fileno;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
385
  			type = CDT2DT(vdir->d_type);
e924f2512   Al Viro   [readdir] convert...
386
387
  			if (!dir_emit(ctx, name.name, name.len, ino, type))
  				break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
388
389
390
  		}
  		/* we'll always have progress because d_reclen is unsigned and
  		 * we've already established it is non-zero. */
e924f2512   Al Viro   [readdir] convert...
391
  		ctx->pos += vdir->d_reclen;
978752534   Jan Harkes   coda: avoid lockd...
392
  	}
5f47c7eac   Al Viro   coda breakage
393
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
394
  	kfree(vdir);
e924f2512   Al Viro   [readdir] convert...
395
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
396
  }
b625032b1   Fabian Frederick   fs/coda/dir.c: fo...
397
398
399
400
401
402
  /* 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;
5bb44810f   Fabian Frederick   coda: ftoc validi...
403
  	cfi = coda_ftoc(coda_file);
b625032b1   Fabian Frederick   fs/coda/dir.c: fo...
404
  	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,
  };