projects/linux·blob master · refs

578 lines · 14.0 KiB

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