~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/fs/afs/dir.c

Version: ~ [ linux-5.2 ] ~ [ linux-5.1.16 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.57 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.132 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.184 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.184 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.69 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.39.4 ] ~ [ linux-2.6.38.8 ] ~ [ linux-2.6.37.6 ] ~ [ linux-2.6.36.4 ] ~ [ linux-2.6.35.14 ] ~ [ linux-2.6.34.15 ] ~ [ linux-2.6.33.20 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /* dir.c: AFS filesystem directory handling
  2  *
  3  * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
  4  * Written by David Howells (dhowells@redhat.com)
  5  *
  6  * This program is free software; you can redistribute it and/or
  7  * modify it under the terms of the GNU General Public License
  8  * as published by the Free Software Foundation; either version
  9  * 2 of the License, or (at your option) any later version.
 10  */
 11 
 12 #include <linux/kernel.h>
 13 #include <linux/module.h>
 14 #include <linux/init.h>
 15 #include <linux/fs.h>
 16 #include <linux/namei.h>
 17 #include <linux/pagemap.h>
 18 #include <linux/ctype.h>
 19 #include <linux/sched.h>
 20 #include "internal.h"
 21 
 22 static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,
 23                                  unsigned int flags);
 24 static int afs_dir_open(struct inode *inode, struct file *file);
 25 static int afs_readdir(struct file *file, struct dir_context *ctx);
 26 static int afs_d_revalidate(struct dentry *dentry, unsigned int flags);
 27 static int afs_d_delete(const struct dentry *dentry);
 28 static void afs_d_release(struct dentry *dentry);
 29 static int afs_lookup_filldir(struct dir_context *ctx, const char *name, int nlen,
 30                                   loff_t fpos, u64 ino, unsigned dtype);
 31 static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
 32                       bool excl);
 33 static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode);
 34 static int afs_rmdir(struct inode *dir, struct dentry *dentry);
 35 static int afs_unlink(struct inode *dir, struct dentry *dentry);
 36 static int afs_link(struct dentry *from, struct inode *dir,
 37                     struct dentry *dentry);
 38 static int afs_symlink(struct inode *dir, struct dentry *dentry,
 39                        const char *content);
 40 static int afs_rename(struct inode *old_dir, struct dentry *old_dentry,
 41                       struct inode *new_dir, struct dentry *new_dentry,
 42                       unsigned int flags);
 43 
 44 const struct file_operations afs_dir_file_operations = {
 45         .open           = afs_dir_open,
 46         .release        = afs_release,
 47         .iterate_shared = afs_readdir,
 48         .lock           = afs_lock,
 49         .llseek         = generic_file_llseek,
 50 };
 51 
 52 const struct inode_operations afs_dir_inode_operations = {
 53         .create         = afs_create,
 54         .lookup         = afs_lookup,
 55         .link           = afs_link,
 56         .unlink         = afs_unlink,
 57         .symlink        = afs_symlink,
 58         .mkdir          = afs_mkdir,
 59         .rmdir          = afs_rmdir,
 60         .rename         = afs_rename,
 61         .permission     = afs_permission,
 62         .getattr        = afs_getattr,
 63         .setattr        = afs_setattr,
 64 };
 65 
 66 const struct dentry_operations afs_fs_dentry_operations = {
 67         .d_revalidate   = afs_d_revalidate,
 68         .d_delete       = afs_d_delete,
 69         .d_release      = afs_d_release,
 70         .d_automount    = afs_d_automount,
 71 };
 72 
 73 #define AFS_DIR_HASHTBL_SIZE    128
 74 #define AFS_DIR_DIRENT_SIZE     32
 75 #define AFS_DIRENT_PER_BLOCK    64
 76 
 77 union afs_dirent {
 78         struct {
 79                 uint8_t         valid;
 80                 uint8_t         unused[1];
 81                 __be16          hash_next;
 82                 __be32          vnode;
 83                 __be32          unique;
 84                 uint8_t         name[16];
 85                 uint8_t         overflow[4];    /* if any char of the name (inc
 86                                                  * NUL) reaches here, consume
 87                                                  * the next dirent too */
 88         } u;
 89         uint8_t extended_name[32];
 90 };
 91 
 92 /* AFS directory page header (one at the beginning of every 2048-byte chunk) */
 93 struct afs_dir_pagehdr {
 94         __be16          npages;
 95         __be16          magic;
 96 #define AFS_DIR_MAGIC htons(1234)
 97         uint8_t         nentries;
 98         uint8_t         bitmap[8];
 99         uint8_t         pad[19];
100 };
101 
102 /* directory block layout */
103 union afs_dir_block {
104 
105         struct afs_dir_pagehdr pagehdr;
106 
107         struct {
108                 struct afs_dir_pagehdr  pagehdr;
109                 uint8_t                 alloc_ctrs[128];
110                 /* dir hash table */
111                 uint16_t                hashtable[AFS_DIR_HASHTBL_SIZE];
112         } hdr;
113 
114         union afs_dirent dirents[AFS_DIRENT_PER_BLOCK];
115 };
116 
117 /* layout on a linux VM page */
118 struct afs_dir_page {
119         union afs_dir_block blocks[PAGE_SIZE / sizeof(union afs_dir_block)];
120 };
121 
122 struct afs_lookup_cookie {
123         struct dir_context ctx;
124         struct afs_fid  fid;
125         struct qstr name;
126         int             found;
127 };
128 
129 /*
130  * check that a directory page is valid
131  */
132 static inline bool afs_dir_check_page(struct inode *dir, struct page *page)
133 {
134         struct afs_dir_page *dbuf;
135         loff_t latter;
136         int tmp, qty;
137 
138 #if 0
139         /* check the page count */
140         qty = desc.size / sizeof(dbuf->blocks[0]);
141         if (qty == 0)
142                 goto error;
143 
144         if (page->index == 0 && qty != ntohs(dbuf->blocks[0].pagehdr.npages)) {
145                 printk("kAFS: %s(%lu): wrong number of dir blocks %d!=%hu\n",
146                        __func__, dir->i_ino, qty,
147                        ntohs(dbuf->blocks[0].pagehdr.npages));
148                 goto error;
149         }
150 #endif
151 
152         /* determine how many magic numbers there should be in this page */
153         latter = dir->i_size - page_offset(page);
154         if (latter >= PAGE_SIZE)
155                 qty = PAGE_SIZE;
156         else
157                 qty = latter;
158         qty /= sizeof(union afs_dir_block);
159 
160         /* check them */
161         dbuf = page_address(page);
162         for (tmp = 0; tmp < qty; tmp++) {
163                 if (dbuf->blocks[tmp].pagehdr.magic != AFS_DIR_MAGIC) {
164                         printk("kAFS: %s(%lu): bad magic %d/%d is %04hx\n",
165                                __func__, dir->i_ino, tmp, qty,
166                                ntohs(dbuf->blocks[tmp].pagehdr.magic));
167                         goto error;
168                 }
169         }
170 
171         SetPageChecked(page);
172         return true;
173 
174 error:
175         SetPageError(page);
176         return false;
177 }
178 
179 /*
180  * discard a page cached in the pagecache
181  */
182 static inline void afs_dir_put_page(struct page *page)
183 {
184         kunmap(page);
185         put_page(page);
186 }
187 
188 /*
189  * get a page into the pagecache
190  */
191 static struct page *afs_dir_get_page(struct inode *dir, unsigned long index,
192                                      struct key *key)
193 {
194         struct page *page;
195         _enter("{%lu},%lu", dir->i_ino, index);
196 
197         page = read_cache_page(dir->i_mapping, index, afs_page_filler, key);
198         if (!IS_ERR(page)) {
199                 kmap(page);
200                 if (unlikely(!PageChecked(page))) {
201                         if (PageError(page) || !afs_dir_check_page(dir, page))
202                                 goto fail;
203                 }
204         }
205         return page;
206 
207 fail:
208         afs_dir_put_page(page);
209         _leave(" = -EIO");
210         return ERR_PTR(-EIO);
211 }
212 
213 /*
214  * open an AFS directory file
215  */
216 static int afs_dir_open(struct inode *inode, struct file *file)
217 {
218         _enter("{%lu}", inode->i_ino);
219 
220         BUILD_BUG_ON(sizeof(union afs_dir_block) != 2048);
221         BUILD_BUG_ON(sizeof(union afs_dirent) != 32);
222 
223         if (test_bit(AFS_VNODE_DELETED, &AFS_FS_I(inode)->flags))
224                 return -ENOENT;
225 
226         return afs_open(inode, file);
227 }
228 
229 /*
230  * deal with one block in an AFS directory
231  */
232 static int afs_dir_iterate_block(struct dir_context *ctx,
233                                  union afs_dir_block *block,
234                                  unsigned blkoff)
235 {
236         union afs_dirent *dire;
237         unsigned offset, next, curr;
238         size_t nlen;
239         int tmp;
240 
241         _enter("%u,%x,%p,,",(unsigned)ctx->pos,blkoff,block);
242 
243         curr = (ctx->pos - blkoff) / sizeof(union afs_dirent);
244 
245         /* walk through the block, an entry at a time */
246         for (offset = AFS_DIRENT_PER_BLOCK - block->pagehdr.nentries;
247              offset < AFS_DIRENT_PER_BLOCK;
248              offset = next
249              ) {
250                 next = offset + 1;
251 
252                 /* skip entries marked unused in the bitmap */
253                 if (!(block->pagehdr.bitmap[offset / 8] &
254                       (1 << (offset % 8)))) {
255                         _debug("ENT[%Zu.%u]: unused",
256                                blkoff / sizeof(union afs_dir_block), offset);
257                         if (offset >= curr)
258                                 ctx->pos = blkoff +
259                                         next * sizeof(union afs_dirent);
260                         continue;
261                 }
262 
263                 /* got a valid entry */
264                 dire = &block->dirents[offset];
265                 nlen = strnlen(dire->u.name,
266                                sizeof(*block) -
267                                offset * sizeof(union afs_dirent));
268 
269                 _debug("ENT[%Zu.%u]: %s %Zu \"%s\"",
270                        blkoff / sizeof(union afs_dir_block), offset,
271                        (offset < curr ? "skip" : "fill"),
272                        nlen, dire->u.name);
273 
274                 /* work out where the next possible entry is */
275                 for (tmp = nlen; tmp > 15; tmp -= sizeof(union afs_dirent)) {
276                         if (next >= AFS_DIRENT_PER_BLOCK) {
277                                 _debug("ENT[%Zu.%u]:"
278                                        " %u travelled beyond end dir block"
279                                        " (len %u/%Zu)",
280                                        blkoff / sizeof(union afs_dir_block),
281                                        offset, next, tmp, nlen);
282                                 return -EIO;
283                         }
284                         if (!(block->pagehdr.bitmap[next / 8] &
285                               (1 << (next % 8)))) {
286                                 _debug("ENT[%Zu.%u]:"
287                                        " %u unmarked extension (len %u/%Zu)",
288                                        blkoff / sizeof(union afs_dir_block),
289                                        offset, next, tmp, nlen);
290                                 return -EIO;
291                         }
292 
293                         _debug("ENT[%Zu.%u]: ext %u/%Zu",
294                                blkoff / sizeof(union afs_dir_block),
295                                next, tmp, nlen);
296                         next++;
297                 }
298 
299                 /* skip if starts before the current position */
300                 if (offset < curr)
301                         continue;
302 
303                 /* found the next entry */
304                 if (!dir_emit(ctx, dire->u.name, nlen,
305                               ntohl(dire->u.vnode),
306                               ctx->actor == afs_lookup_filldir ?
307                               ntohl(dire->u.unique) : DT_UNKNOWN)) {
308                         _leave(" = 0 [full]");
309                         return 0;
310                 }
311 
312                 ctx->pos = blkoff + next * sizeof(union afs_dirent);
313         }
314 
315         _leave(" = 1 [more]");
316         return 1;
317 }
318 
319 /*
320  * iterate through the data blob that lists the contents of an AFS directory
321  */
322 static int afs_dir_iterate(struct inode *dir, struct dir_context *ctx,
323                            struct key *key)
324 {
325         union afs_dir_block *dblock;
326         struct afs_dir_page *dbuf;
327         struct page *page;
328         unsigned blkoff, limit;
329         int ret;
330 
331         _enter("{%lu},%u,,", dir->i_ino, (unsigned)ctx->pos);
332 
333         if (test_bit(AFS_VNODE_DELETED, &AFS_FS_I(dir)->flags)) {
334                 _leave(" = -ESTALE");
335                 return -ESTALE;
336         }
337 
338         /* round the file position up to the next entry boundary */
339         ctx->pos += sizeof(union afs_dirent) - 1;
340         ctx->pos &= ~(sizeof(union afs_dirent) - 1);
341 
342         /* walk through the blocks in sequence */
343         ret = 0;
344         while (ctx->pos < dir->i_size) {
345                 blkoff = ctx->pos & ~(sizeof(union afs_dir_block) - 1);
346 
347                 /* fetch the appropriate page from the directory */
348                 page = afs_dir_get_page(dir, blkoff / PAGE_SIZE, key);
349                 if (IS_ERR(page)) {
350                         ret = PTR_ERR(page);
351                         break;
352                 }
353 
354                 limit = blkoff & ~(PAGE_SIZE - 1);
355 
356                 dbuf = page_address(page);
357 
358                 /* deal with the individual blocks stashed on this page */
359                 do {
360                         dblock = &dbuf->blocks[(blkoff % PAGE_SIZE) /
361                                                sizeof(union afs_dir_block)];
362                         ret = afs_dir_iterate_block(ctx, dblock, blkoff);
363                         if (ret != 1) {
364                                 afs_dir_put_page(page);
365                                 goto out;
366                         }
367 
368                         blkoff += sizeof(union afs_dir_block);
369 
370                 } while (ctx->pos < dir->i_size && blkoff < limit);
371 
372                 afs_dir_put_page(page);
373                 ret = 0;
374         }
375 
376 out:
377         _leave(" = %d", ret);
378         return ret;
379 }
380 
381 /*
382  * read an AFS directory
383  */
384 static int afs_readdir(struct file *file, struct dir_context *ctx)
385 {
386         return afs_dir_iterate(file_inode(file), 
387                               ctx, file->private_data);
388 }
389 
390 /*
391  * search the directory for a name
392  * - if afs_dir_iterate_block() spots this function, it'll pass the FID
393  *   uniquifier through dtype
394  */
395 static int afs_lookup_filldir(struct dir_context *ctx, const char *name,
396                               int nlen, loff_t fpos, u64 ino, unsigned dtype)
397 {
398         struct afs_lookup_cookie *cookie =
399                 container_of(ctx, struct afs_lookup_cookie, ctx);
400 
401         _enter("{%s,%u},%s,%u,,%llu,%u",
402                cookie->name.name, cookie->name.len, name, nlen,
403                (unsigned long long) ino, dtype);
404 
405         /* insanity checks first */
406         BUILD_BUG_ON(sizeof(union afs_dir_block) != 2048);
407         BUILD_BUG_ON(sizeof(union afs_dirent) != 32);
408 
409         if (cookie->name.len != nlen ||
410             memcmp(cookie->name.name, name, nlen) != 0) {
411                 _leave(" = 0 [no]");
412                 return 0;
413         }
414 
415         cookie->fid.vnode = ino;
416         cookie->fid.unique = dtype;
417         cookie->found = 1;
418 
419         _leave(" = -1 [found]");
420         return -1;
421 }
422 
423 /*
424  * do a lookup in a directory
425  * - just returns the FID the dentry name maps to if found
426  */
427 static int afs_do_lookup(struct inode *dir, struct dentry *dentry,
428                          struct afs_fid *fid, struct key *key)
429 {
430         struct afs_super_info *as = dir->i_sb->s_fs_info;
431         struct afs_lookup_cookie cookie = {
432                 .ctx.actor = afs_lookup_filldir,
433                 .name = dentry->d_name,
434                 .fid.vid = as->volume->vid
435         };
436         int ret;
437 
438         _enter("{%lu},%p{%pd},", dir->i_ino, dentry, dentry);
439 
440         /* search the directory */
441         ret = afs_dir_iterate(dir, &cookie.ctx, key);
442         if (ret < 0) {
443                 _leave(" = %d [iter]", ret);
444                 return ret;
445         }
446 
447         ret = -ENOENT;
448         if (!cookie.found) {
449                 _leave(" = -ENOENT [not found]");
450                 return -ENOENT;
451         }
452 
453         *fid = cookie.fid;
454         _leave(" = 0 { vn=%u u=%u }", fid->vnode, fid->unique);
455         return 0;
456 }
457 
458 /*
459  * Try to auto mount the mountpoint with pseudo directory, if the autocell
460  * operation is setted.
461  */
462 static struct inode *afs_try_auto_mntpt(
463         int ret, struct dentry *dentry, struct inode *dir, struct key *key,
464         struct afs_fid *fid)
465 {
466         const char *devname = dentry->d_name.name;
467         struct afs_vnode *vnode = AFS_FS_I(dir);
468         struct inode *inode;
469 
470         _enter("%d, %p{%pd}, {%x:%u}, %p",
471                ret, dentry, dentry, vnode->fid.vid, vnode->fid.vnode, key);
472 
473         if (ret != -ENOENT ||
474             !test_bit(AFS_VNODE_AUTOCELL, &vnode->flags))
475                 goto out;
476 
477         inode = afs_iget_autocell(dir, devname, strlen(devname), key);
478         if (IS_ERR(inode)) {
479                 ret = PTR_ERR(inode);
480                 goto out;
481         }
482 
483         *fid = AFS_FS_I(inode)->fid;
484         _leave("= %p", inode);
485         return inode;
486 
487 out:
488         _leave("= %d", ret);
489         return ERR_PTR(ret);
490 }
491 
492 /*
493  * look up an entry in a directory
494  */
495 static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,
496                                  unsigned int flags)
497 {
498         struct afs_vnode *vnode;
499         struct afs_fid fid;
500         struct inode *inode;
501         struct key *key;
502         int ret;
503 
504         vnode = AFS_FS_I(dir);
505 
506         _enter("{%x:%u},%p{%pd},",
507                vnode->fid.vid, vnode->fid.vnode, dentry, dentry);
508 
509         ASSERTCMP(d_inode(dentry), ==, NULL);
510 
511         if (dentry->d_name.len >= AFSNAMEMAX) {
512                 _leave(" = -ENAMETOOLONG");
513                 return ERR_PTR(-ENAMETOOLONG);
514         }
515 
516         if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) {
517                 _leave(" = -ESTALE");
518                 return ERR_PTR(-ESTALE);
519         }
520 
521         key = afs_request_key(vnode->volume->cell);
522         if (IS_ERR(key)) {
523                 _leave(" = %ld [key]", PTR_ERR(key));
524                 return ERR_CAST(key);
525         }
526 
527         ret = afs_validate(vnode, key);
528         if (ret < 0) {
529                 key_put(key);
530                 _leave(" = %d [val]", ret);
531                 return ERR_PTR(ret);
532         }
533 
534         ret = afs_do_lookup(dir, dentry, &fid, key);
535         if (ret < 0) {
536                 inode = afs_try_auto_mntpt(ret, dentry, dir, key, &fid);
537                 if (!IS_ERR(inode)) {
538                         key_put(key);
539                         goto success;
540                 }
541 
542                 ret = PTR_ERR(inode);
543                 key_put(key);
544                 if (ret == -ENOENT) {
545                         d_add(dentry, NULL);
546                         _leave(" = NULL [negative]");
547                         return NULL;
548                 }
549                 _leave(" = %d [do]", ret);
550                 return ERR_PTR(ret);
551         }
552         dentry->d_fsdata = (void *)(unsigned long) vnode->status.data_version;
553 
554         /* instantiate the dentry */
555         inode = afs_iget(dir->i_sb, key, &fid, NULL, NULL);
556         key_put(key);
557         if (IS_ERR(inode)) {
558                 _leave(" = %ld", PTR_ERR(inode));
559                 return ERR_CAST(inode);
560         }
561 
562 success:
563         d_add(dentry, inode);
564         _leave(" = 0 { vn=%u u=%u } -> { ino=%lu v=%u }",
565                fid.vnode,
566                fid.unique,
567                d_inode(dentry)->i_ino,
568                d_inode(dentry)->i_generation);
569 
570         return NULL;
571 }
572 
573 /*
574  * check that a dentry lookup hit has found a valid entry
575  * - NOTE! the hit can be a negative hit too, so we can't assume we have an
576  *   inode
577  */
578 static int afs_d_revalidate(struct dentry *dentry, unsigned int flags)
579 {
580         struct afs_vnode *vnode, *dir;
581         struct afs_fid uninitialized_var(fid);
582         struct dentry *parent;
583         struct key *key;
584         void *dir_version;
585         int ret;
586 
587         if (flags & LOOKUP_RCU)
588                 return -ECHILD;
589 
590         vnode = AFS_FS_I(d_inode(dentry));
591 
592         if (d_really_is_positive(dentry))
593                 _enter("{v={%x:%u} n=%pd fl=%lx},",
594                        vnode->fid.vid, vnode->fid.vnode, dentry,
595                        vnode->flags);
596         else
597                 _enter("{neg n=%pd}", dentry);
598 
599         key = afs_request_key(AFS_FS_S(dentry->d_sb)->volume->cell);
600         if (IS_ERR(key))
601                 key = NULL;
602 
603         /* lock down the parent dentry so we can peer at it */
604         parent = dget_parent(dentry);
605         dir = AFS_FS_I(d_inode(parent));
606 
607         /* validate the parent directory */
608         if (test_bit(AFS_VNODE_MODIFIED, &dir->flags))
609                 afs_validate(dir, key);
610 
611         if (test_bit(AFS_VNODE_DELETED, &dir->flags)) {
612                 _debug("%pd: parent dir deleted", dentry);
613                 goto out_bad;
614         }
615 
616         dir_version = (void *) (unsigned long) dir->status.data_version;
617         if (dentry->d_fsdata == dir_version)
618                 goto out_valid; /* the dir contents are unchanged */
619 
620         _debug("dir modified");
621 
622         /* search the directory for this vnode */
623         ret = afs_do_lookup(&dir->vfs_inode, dentry, &fid, key);
624         switch (ret) {
625         case 0:
626                 /* the filename maps to something */
627                 if (d_really_is_negative(dentry))
628                         goto out_bad;
629                 if (is_bad_inode(d_inode(dentry))) {
630                         printk("kAFS: afs_d_revalidate: %pd2 has bad inode\n",
631                                dentry);
632                         goto out_bad;
633                 }
634 
635                 /* if the vnode ID has changed, then the dirent points to a
636                  * different file */
637                 if (fid.vnode != vnode->fid.vnode) {
638                         _debug("%pd: dirent changed [%u != %u]",
639                                dentry, fid.vnode,
640                                vnode->fid.vnode);
641                         goto not_found;
642                 }
643 
644                 /* if the vnode ID uniqifier has changed, then the file has
645                  * been deleted and replaced, and the original vnode ID has
646                  * been reused */
647                 if (fid.unique != vnode->fid.unique) {
648                         _debug("%pd: file deleted (uq %u -> %u I:%u)",
649                                dentry, fid.unique,
650                                vnode->fid.unique,
651                                d_inode(dentry)->i_generation);
652                         spin_lock(&vnode->lock);
653                         set_bit(AFS_VNODE_DELETED, &vnode->flags);
654                         spin_unlock(&vnode->lock);
655                         goto not_found;
656                 }
657                 goto out_valid;
658 
659         case -ENOENT:
660                 /* the filename is unknown */
661                 _debug("%pd: dirent not found", dentry);
662                 if (d_really_is_positive(dentry))
663                         goto not_found;
664                 goto out_valid;
665 
666         default:
667                 _debug("failed to iterate dir %pd: %d",
668                        parent, ret);
669                 goto out_bad;
670         }
671 
672 out_valid:
673         dentry->d_fsdata = dir_version;
674         dput(parent);
675         key_put(key);
676         _leave(" = 1 [valid]");
677         return 1;
678 
679         /* the dirent, if it exists, now points to a different vnode */
680 not_found:
681         spin_lock(&dentry->d_lock);
682         dentry->d_flags |= DCACHE_NFSFS_RENAMED;
683         spin_unlock(&dentry->d_lock);
684 
685 out_bad:
686         _debug("dropping dentry %pd2", dentry);
687         dput(parent);
688         key_put(key);
689 
690         _leave(" = 0 [bad]");
691         return 0;
692 }
693 
694 /*
695  * allow the VFS to enquire as to whether a dentry should be unhashed (mustn't
696  * sleep)
697  * - called from dput() when d_count is going to 0.
698  * - return 1 to request dentry be unhashed, 0 otherwise
699  */
700 static int afs_d_delete(const struct dentry *dentry)
701 {
702         _enter("%pd", dentry);
703 
704         if (dentry->d_flags & DCACHE_NFSFS_RENAMED)
705                 goto zap;
706 
707         if (d_really_is_positive(dentry) &&
708             (test_bit(AFS_VNODE_DELETED,   &AFS_FS_I(d_inode(dentry))->flags) ||
709              test_bit(AFS_VNODE_PSEUDODIR, &AFS_FS_I(d_inode(dentry))->flags)))
710                 goto zap;
711 
712         _leave(" = 0 [keep]");
713         return 0;
714 
715 zap:
716         _leave(" = 1 [zap]");
717         return 1;
718 }
719 
720 /*
721  * handle dentry release
722  */
723 static void afs_d_release(struct dentry *dentry)
724 {
725         _enter("%pd", dentry);
726 }
727 
728 /*
729  * create a directory on an AFS filesystem
730  */
731 static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
732 {
733         struct afs_file_status status;
734         struct afs_callback cb;
735         struct afs_server *server;
736         struct afs_vnode *dvnode, *vnode;
737         struct afs_fid fid;
738         struct inode *inode;
739         struct key *key;
740         int ret;
741 
742         dvnode = AFS_FS_I(dir);
743 
744         _enter("{%x:%u},{%pd},%ho",
745                dvnode->fid.vid, dvnode->fid.vnode, dentry, mode);
746 
747         key = afs_request_key(dvnode->volume->cell);
748         if (IS_ERR(key)) {
749                 ret = PTR_ERR(key);
750                 goto error;
751         }
752 
753         mode |= S_IFDIR;
754         ret = afs_vnode_create(dvnode, key, dentry->d_name.name,
755                                mode, &fid, &status, &cb, &server);
756         if (ret < 0)
757                 goto mkdir_error;
758 
759         inode = afs_iget(dir->i_sb, key, &fid, &status, &cb);
760         if (IS_ERR(inode)) {
761                 /* ENOMEM at a really inconvenient time - just abandon the new
762                  * directory on the server */
763                 ret = PTR_ERR(inode);
764                 goto iget_error;
765         }
766 
767         /* apply the status report we've got for the new vnode */
768         vnode = AFS_FS_I(inode);
769         spin_lock(&vnode->lock);
770         vnode->update_cnt++;
771         spin_unlock(&vnode->lock);
772         afs_vnode_finalise_status_update(vnode, server);
773         afs_put_server(server);
774 
775         d_instantiate(dentry, inode);
776         if (d_unhashed(dentry)) {
777                 _debug("not hashed");
778                 d_rehash(dentry);
779         }
780         key_put(key);
781         _leave(" = 0");
782         return 0;
783 
784 iget_error:
785         afs_put_server(server);
786 mkdir_error:
787         key_put(key);
788 error:
789         d_drop(dentry);
790         _leave(" = %d", ret);
791         return ret;
792 }
793 
794 /*
795  * remove a directory from an AFS filesystem
796  */
797 static int afs_rmdir(struct inode *dir, struct dentry *dentry)
798 {
799         struct afs_vnode *dvnode, *vnode;
800         struct key *key;
801         int ret;
802 
803         dvnode = AFS_FS_I(dir);
804 
805         _enter("{%x:%u},{%pd}",
806                dvnode->fid.vid, dvnode->fid.vnode, dentry);
807 
808         key = afs_request_key(dvnode->volume->cell);
809         if (IS_ERR(key)) {
810                 ret = PTR_ERR(key);
811                 goto error;
812         }
813 
814         ret = afs_vnode_remove(dvnode, key, dentry->d_name.name, true);
815         if (ret < 0)
816                 goto rmdir_error;
817 
818         if (d_really_is_positive(dentry)) {
819                 vnode = AFS_FS_I(d_inode(dentry));
820                 clear_nlink(&vnode->vfs_inode);
821                 set_bit(AFS_VNODE_DELETED, &vnode->flags);
822                 afs_discard_callback_on_delete(vnode);
823         }
824 
825         key_put(key);
826         _leave(" = 0");
827         return 0;
828 
829 rmdir_error:
830         key_put(key);
831 error:
832         _leave(" = %d", ret);
833         return ret;
834 }
835 
836 /*
837  * remove a file from an AFS filesystem
838  */
839 static int afs_unlink(struct inode *dir, struct dentry *dentry)
840 {
841         struct afs_vnode *dvnode, *vnode;
842         struct key *key;
843         int ret;
844 
845         dvnode = AFS_FS_I(dir);
846 
847         _enter("{%x:%u},{%pd}",
848                dvnode->fid.vid, dvnode->fid.vnode, dentry);
849 
850         ret = -ENAMETOOLONG;
851         if (dentry->d_name.len >= AFSNAMEMAX)
852                 goto error;
853 
854         key = afs_request_key(dvnode->volume->cell);
855         if (IS_ERR(key)) {
856                 ret = PTR_ERR(key);
857                 goto error;
858         }
859 
860         if (d_really_is_positive(dentry)) {
861                 vnode = AFS_FS_I(d_inode(dentry));
862 
863                 /* make sure we have a callback promise on the victim */
864                 ret = afs_validate(vnode, key);
865                 if (ret < 0)
866                         goto error;
867         }
868 
869         ret = afs_vnode_remove(dvnode, key, dentry->d_name.name, false);
870         if (ret < 0)
871                 goto remove_error;
872 
873         if (d_really_is_positive(dentry)) {
874                 /* if the file wasn't deleted due to excess hard links, the
875                  * fileserver will break the callback promise on the file - if
876                  * it had one - before it returns to us, and if it was deleted,
877                  * it won't
878                  *
879                  * however, if we didn't have a callback promise outstanding,
880                  * or it was outstanding on a different server, then it won't
881                  * break it either...
882                  */
883                 vnode = AFS_FS_I(d_inode(dentry));
884                 if (test_bit(AFS_VNODE_DELETED, &vnode->flags))
885                         _debug("AFS_VNODE_DELETED");
886                 if (test_bit(AFS_VNODE_CB_BROKEN, &vnode->flags))
887                         _debug("AFS_VNODE_CB_BROKEN");
888                 set_bit(AFS_VNODE_CB_BROKEN, &vnode->flags);
889                 ret = afs_validate(vnode, key);
890                 _debug("nlink %d [val %d]", vnode->vfs_inode.i_nlink, ret);
891         }
892 
893         key_put(key);
894         _leave(" = 0");
895         return 0;
896 
897 remove_error:
898         key_put(key);
899 error:
900         _leave(" = %d", ret);
901         return ret;
902 }
903 
904 /*
905  * create a regular file on an AFS filesystem
906  */
907 static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
908                       bool excl)
909 {
910         struct afs_file_status status;
911         struct afs_callback cb;
912         struct afs_server *server;
913         struct afs_vnode *dvnode, *vnode;
914         struct afs_fid fid;
915         struct inode *inode;
916         struct key *key;
917         int ret;
918 
919         dvnode = AFS_FS_I(dir);
920 
921         _enter("{%x:%u},{%pd},%ho,",
922                dvnode->fid.vid, dvnode->fid.vnode, dentry, mode);
923 
924         key = afs_request_key(dvnode->volume->cell);
925         if (IS_ERR(key)) {
926                 ret = PTR_ERR(key);
927                 goto error;
928         }
929 
930         mode |= S_IFREG;
931         ret = afs_vnode_create(dvnode, key, dentry->d_name.name,
932                                mode, &fid, &status, &cb, &server);
933         if (ret < 0)
934                 goto create_error;
935 
936         inode = afs_iget(dir->i_sb, key, &fid, &status, &cb);
937         if (IS_ERR(inode)) {
938                 /* ENOMEM at a really inconvenient time - just abandon the new
939                  * directory on the server */
940                 ret = PTR_ERR(inode);
941                 goto iget_error;
942         }
943 
944         /* apply the status report we've got for the new vnode */
945         vnode = AFS_FS_I(inode);
946         spin_lock(&vnode->lock);
947         vnode->update_cnt++;
948         spin_unlock(&vnode->lock);
949         afs_vnode_finalise_status_update(vnode, server);
950         afs_put_server(server);
951 
952         d_instantiate(dentry, inode);
953         if (d_unhashed(dentry)) {
954                 _debug("not hashed");
955                 d_rehash(dentry);
956         }
957         key_put(key);
958         _leave(" = 0");
959         return 0;
960 
961 iget_error:
962         afs_put_server(server);
963 create_error:
964         key_put(key);
965 error:
966         d_drop(dentry);
967         _leave(" = %d", ret);
968         return ret;
969 }
970 
971 /*
972  * create a hard link between files in an AFS filesystem
973  */
974 static int afs_link(struct dentry *from, struct inode *dir,
975                     struct dentry *dentry)
976 {
977         struct afs_vnode *dvnode, *vnode;
978         struct key *key;
979         int ret;
980 
981         vnode = AFS_FS_I(d_inode(from));
982         dvnode = AFS_FS_I(dir);
983 
984         _enter("{%x:%u},{%x:%u},{%pd}",
985                vnode->fid.vid, vnode->fid.vnode,
986                dvnode->fid.vid, dvnode->fid.vnode,
987                dentry);
988 
989         key = afs_request_key(dvnode->volume->cell);
990         if (IS_ERR(key)) {
991                 ret = PTR_ERR(key);
992                 goto error;
993         }
994 
995         ret = afs_vnode_link(dvnode, vnode, key, dentry->d_name.name);
996         if (ret < 0)
997                 goto link_error;
998 
999         ihold(&vnode->vfs_inode);
1000         d_instantiate(dentry, &vnode->vfs_inode);
1001         key_put(key);
1002         _leave(" = 0");
1003         return 0;
1004 
1005 link_error:
1006         key_put(key);
1007 error:
1008         d_drop(dentry);
1009         _leave(" = %d", ret);
1010         return ret;
1011 }
1012 
1013 /*
1014  * create a symlink in an AFS filesystem
1015  */
1016 static int afs_symlink(struct inode *dir, struct dentry *dentry,
1017                        const char *content)
1018 {
1019         struct afs_file_status status;
1020         struct afs_server *server;
1021         struct afs_vnode *dvnode, *vnode;
1022         struct afs_fid fid;
1023         struct inode *inode;
1024         struct key *key;
1025         int ret;
1026 
1027         dvnode = AFS_FS_I(dir);
1028 
1029         _enter("{%x:%u},{%pd},%s",
1030                dvnode->fid.vid, dvnode->fid.vnode, dentry,
1031                content);
1032 
1033         ret = -EINVAL;
1034         if (strlen(content) >= AFSPATHMAX)
1035                 goto error;
1036 
1037         key = afs_request_key(dvnode->volume->cell);
1038         if (IS_ERR(key)) {
1039                 ret = PTR_ERR(key);
1040                 goto error;
1041         }
1042 
1043         ret = afs_vnode_symlink(dvnode, key, dentry->d_name.name, content,
1044                                 &fid, &status, &server);
1045         if (ret < 0)
1046                 goto create_error;
1047 
1048         inode = afs_iget(dir->i_sb, key, &fid, &status, NULL);
1049         if (IS_ERR(inode)) {
1050                 /* ENOMEM at a really inconvenient time - just abandon the new
1051                  * directory on the server */
1052                 ret = PTR_ERR(inode);
1053                 goto iget_error;
1054         }
1055 
1056         /* apply the status report we've got for the new vnode */
1057         vnode = AFS_FS_I(inode);
1058         spin_lock(&vnode->lock);
1059         vnode->update_cnt++;
1060         spin_unlock(&vnode->lock);
1061         afs_vnode_finalise_status_update(vnode, server);
1062         afs_put_server(server);
1063 
1064         d_instantiate(dentry, inode);
1065         if (d_unhashed(dentry)) {
1066                 _debug("not hashed");
1067                 d_rehash(dentry);
1068         }
1069         key_put(key);
1070         _leave(" = 0");
1071         return 0;
1072 
1073 iget_error:
1074         afs_put_server(server);
1075 create_error:
1076         key_put(key);
1077 error:
1078         d_drop(dentry);
1079         _leave(" = %d", ret);
1080         return ret;
1081 }
1082 
1083 /*
1084  * rename a file in an AFS filesystem and/or move it between directories
1085  */
1086 static int afs_rename(struct inode *old_dir, struct dentry *old_dentry,
1087                       struct inode *new_dir, struct dentry *new_dentry,
1088                       unsigned int flags)
1089 {
1090         struct afs_vnode *orig_dvnode, *new_dvnode, *vnode;
1091         struct key *key;
1092         int ret;
1093 
1094         if (flags)
1095                 return -EINVAL;
1096 
1097         vnode = AFS_FS_I(d_inode(old_dentry));
1098         orig_dvnode = AFS_FS_I(old_dir);
1099         new_dvnode = AFS_FS_I(new_dir);
1100 
1101         _enter("{%x:%u},{%x:%u},{%x:%u},{%pd}",
1102                orig_dvnode->fid.vid, orig_dvnode->fid.vnode,
1103                vnode->fid.vid, vnode->fid.vnode,
1104                new_dvnode->fid.vid, new_dvnode->fid.vnode,
1105                new_dentry);
1106 
1107         key = afs_request_key(orig_dvnode->volume->cell);
1108         if (IS_ERR(key)) {
1109                 ret = PTR_ERR(key);
1110                 goto error;
1111         }
1112 
1113         ret = afs_vnode_rename(orig_dvnode, new_dvnode, key,
1114                                old_dentry->d_name.name,
1115                                new_dentry->d_name.name);
1116         if (ret < 0)
1117                 goto rename_error;
1118         key_put(key);
1119         _leave(" = 0");
1120         return 0;
1121 
1122 rename_error:
1123         key_put(key);
1124 error:
1125         d_drop(new_dentry);
1126         _leave(" = %d", ret);
1127         return ret;
1128 }
1129 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp