diff options
Diffstat (limited to 'fs/nilfs2/namei.c')
| -rw-r--r-- | fs/nilfs2/namei.c | 139 |
1 files changed, 122 insertions, 17 deletions
diff --git a/fs/nilfs2/namei.c b/fs/nilfs2/namei.c index ad6ed2cf19b4..185d1607cb00 100644 --- a/fs/nilfs2/namei.c +++ b/fs/nilfs2/namei.c | |||
| @@ -40,7 +40,11 @@ | |||
| 40 | 40 | ||
| 41 | #include <linux/pagemap.h> | 41 | #include <linux/pagemap.h> |
| 42 | #include "nilfs.h" | 42 | #include "nilfs.h" |
| 43 | #include "export.h" | ||
| 43 | 44 | ||
| 45 | #define NILFS_FID_SIZE_NON_CONNECTABLE \ | ||
| 46 | (offsetof(struct nilfs_fid, parent_gen) / 4) | ||
| 47 | #define NILFS_FID_SIZE_CONNECTABLE (sizeof(struct nilfs_fid) / 4) | ||
| 44 | 48 | ||
| 45 | static inline int nilfs_add_nondir(struct dentry *dentry, struct inode *inode) | 49 | static inline int nilfs_add_nondir(struct dentry *dentry, struct inode *inode) |
| 46 | { | 50 | { |
| @@ -70,29 +74,13 @@ nilfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) | |||
| 70 | ino = nilfs_inode_by_name(dir, &dentry->d_name); | 74 | ino = nilfs_inode_by_name(dir, &dentry->d_name); |
| 71 | inode = NULL; | 75 | inode = NULL; |
| 72 | if (ino) { | 76 | if (ino) { |
| 73 | inode = nilfs_iget(dir->i_sb, ino); | 77 | inode = nilfs_iget(dir->i_sb, NILFS_I(dir)->i_root, ino); |
| 74 | if (IS_ERR(inode)) | 78 | if (IS_ERR(inode)) |
| 75 | return ERR_CAST(inode); | 79 | return ERR_CAST(inode); |
| 76 | } | 80 | } |
| 77 | return d_splice_alias(inode, dentry); | 81 | return d_splice_alias(inode, dentry); |
| 78 | } | 82 | } |
| 79 | 83 | ||
| 80 | struct dentry *nilfs_get_parent(struct dentry *child) | ||
| 81 | { | ||
| 82 | unsigned long ino; | ||
| 83 | struct inode *inode; | ||
| 84 | struct qstr dotdot = {.name = "..", .len = 2}; | ||
| 85 | |||
| 86 | ino = nilfs_inode_by_name(child->d_inode, &dotdot); | ||
| 87 | if (!ino) | ||
| 88 | return ERR_PTR(-ENOENT); | ||
| 89 | |||
| 90 | inode = nilfs_iget(child->d_inode->i_sb, ino); | ||
| 91 | if (IS_ERR(inode)) | ||
| 92 | return ERR_CAST(inode); | ||
| 93 | return d_obtain_alias(inode); | ||
| 94 | } | ||
| 95 | |||
| 96 | /* | 84 | /* |
| 97 | * By the time this is called, we already have created | 85 | * By the time this is called, we already have created |
| 98 | * the directory cache entry for the new file, but it | 86 | * the directory cache entry for the new file, but it |
| @@ -468,6 +456,115 @@ out: | |||
| 468 | return err; | 456 | return err; |
| 469 | } | 457 | } |
| 470 | 458 | ||
| 459 | /* | ||
| 460 | * Export operations | ||
| 461 | */ | ||
| 462 | static struct dentry *nilfs_get_parent(struct dentry *child) | ||
| 463 | { | ||
| 464 | unsigned long ino; | ||
| 465 | struct inode *inode; | ||
| 466 | struct qstr dotdot = {.name = "..", .len = 2}; | ||
| 467 | struct nilfs_root *root; | ||
| 468 | |||
| 469 | ino = nilfs_inode_by_name(child->d_inode, &dotdot); | ||
| 470 | if (!ino) | ||
| 471 | return ERR_PTR(-ENOENT); | ||
| 472 | |||
| 473 | root = NILFS_I(child->d_inode)->i_root; | ||
| 474 | |||
| 475 | inode = nilfs_iget(child->d_inode->i_sb, root, ino); | ||
| 476 | if (IS_ERR(inode)) | ||
| 477 | return ERR_CAST(inode); | ||
| 478 | |||
| 479 | return d_obtain_alias(inode); | ||
| 480 | } | ||
| 481 | |||
| 482 | static struct dentry *nilfs_get_dentry(struct super_block *sb, u64 cno, | ||
| 483 | u64 ino, u32 gen) | ||
| 484 | { | ||
| 485 | struct nilfs_root *root; | ||
| 486 | struct inode *inode; | ||
| 487 | |||
| 488 | if (ino < NILFS_FIRST_INO(sb) && ino != NILFS_ROOT_INO) | ||
| 489 | return ERR_PTR(-ESTALE); | ||
| 490 | |||
| 491 | root = nilfs_lookup_root(NILFS_SB(sb)->s_nilfs, cno); | ||
| 492 | if (!root) | ||
| 493 | return ERR_PTR(-ESTALE); | ||
| 494 | |||
| 495 | inode = nilfs_iget(sb, root, ino); | ||
| 496 | nilfs_put_root(root); | ||
| 497 | |||
| 498 | if (IS_ERR(inode)) | ||
| 499 | return ERR_CAST(inode); | ||
| 500 | if (gen && inode->i_generation != gen) { | ||
| 501 | iput(inode); | ||
| 502 | return ERR_PTR(-ESTALE); | ||
| 503 | } | ||
| 504 | return d_obtain_alias(inode); | ||
| 505 | } | ||
| 506 | |||
| 507 | static struct dentry *nilfs_fh_to_dentry(struct super_block *sb, struct fid *fh, | ||
| 508 | int fh_len, int fh_type) | ||
| 509 | { | ||
| 510 | struct nilfs_fid *fid = (struct nilfs_fid *)fh; | ||
| 511 | |||
| 512 | if ((fh_len != NILFS_FID_SIZE_NON_CONNECTABLE && | ||
| 513 | fh_len != NILFS_FID_SIZE_CONNECTABLE) || | ||
| 514 | (fh_type != FILEID_NILFS_WITH_PARENT && | ||
| 515 | fh_type != FILEID_NILFS_WITHOUT_PARENT)) | ||
| 516 | return NULL; | ||
| 517 | |||
| 518 | return nilfs_get_dentry(sb, fid->cno, fid->ino, fid->gen); | ||
| 519 | } | ||
| 520 | |||
| 521 | static struct dentry *nilfs_fh_to_parent(struct super_block *sb, struct fid *fh, | ||
| 522 | int fh_len, int fh_type) | ||
| 523 | { | ||
| 524 | struct nilfs_fid *fid = (struct nilfs_fid *)fh; | ||
| 525 | |||
| 526 | if (fh_len != NILFS_FID_SIZE_CONNECTABLE || | ||
| 527 | fh_type != FILEID_NILFS_WITH_PARENT) | ||
| 528 | return NULL; | ||
| 529 | |||
| 530 | return nilfs_get_dentry(sb, fid->cno, fid->parent_ino, fid->parent_gen); | ||
| 531 | } | ||
| 532 | |||
| 533 | static int nilfs_encode_fh(struct dentry *dentry, __u32 *fh, int *lenp, | ||
| 534 | int connectable) | ||
| 535 | { | ||
| 536 | struct nilfs_fid *fid = (struct nilfs_fid *)fh; | ||
| 537 | struct inode *inode = dentry->d_inode; | ||
| 538 | struct nilfs_root *root = NILFS_I(inode)->i_root; | ||
| 539 | int type; | ||
| 540 | |||
| 541 | if (*lenp < NILFS_FID_SIZE_NON_CONNECTABLE || | ||
| 542 | (connectable && *lenp < NILFS_FID_SIZE_CONNECTABLE)) | ||
| 543 | return 255; | ||
| 544 | |||
| 545 | fid->cno = root->cno; | ||
| 546 | fid->ino = inode->i_ino; | ||
| 547 | fid->gen = inode->i_generation; | ||
| 548 | |||
| 549 | if (connectable && !S_ISDIR(inode->i_mode)) { | ||
| 550 | struct inode *parent; | ||
| 551 | |||
| 552 | spin_lock(&dentry->d_lock); | ||
| 553 | parent = dentry->d_parent->d_inode; | ||
| 554 | fid->parent_ino = parent->i_ino; | ||
| 555 | fid->parent_gen = parent->i_generation; | ||
| 556 | spin_unlock(&dentry->d_lock); | ||
| 557 | |||
| 558 | type = FILEID_NILFS_WITH_PARENT; | ||
| 559 | *lenp = NILFS_FID_SIZE_CONNECTABLE; | ||
| 560 | } else { | ||
| 561 | type = FILEID_NILFS_WITHOUT_PARENT; | ||
| 562 | *lenp = NILFS_FID_SIZE_NON_CONNECTABLE; | ||
| 563 | } | ||
| 564 | |||
| 565 | return type; | ||
| 566 | } | ||
| 567 | |||
| 471 | const struct inode_operations nilfs_dir_inode_operations = { | 568 | const struct inode_operations nilfs_dir_inode_operations = { |
| 472 | .create = nilfs_create, | 569 | .create = nilfs_create, |
| 473 | .lookup = nilfs_lookup, | 570 | .lookup = nilfs_lookup, |
| @@ -491,4 +588,12 @@ const struct inode_operations nilfs_symlink_inode_operations = { | |||
| 491 | .readlink = generic_readlink, | 588 | .readlink = generic_readlink, |
| 492 | .follow_link = page_follow_link_light, | 589 | .follow_link = page_follow_link_light, |
| 493 | .put_link = page_put_link, | 590 | .put_link = page_put_link, |
| 591 | .permission = nilfs_permission, | ||
| 592 | }; | ||
| 593 | |||
| 594 | const struct export_operations nilfs_export_ops = { | ||
| 595 | .encode_fh = nilfs_encode_fh, | ||
| 596 | .fh_to_dentry = nilfs_fh_to_dentry, | ||
| 597 | .fh_to_parent = nilfs_fh_to_parent, | ||
| 598 | .get_parent = nilfs_get_parent, | ||
| 494 | }; | 599 | }; |
