diff options
author | Steve French <sfrench@us.ibm.com> | 2011-05-26 23:50:55 -0400 |
---|---|---|
committer | Steve French <sfrench@us.ibm.com> | 2011-05-26 23:50:55 -0400 |
commit | f87d39d951329cd8f462bf9007d334122c0599d0 (patch) | |
tree | ba4c4d9dee6958c7d8ee87070a58d80389be2d2f /fs/cifs/cifsfs.c | |
parent | 641a58d66d086327042e9d73c6606fd02c8f067c (diff) |
[CIFS] Migrate from prefixpath logic
Now we point superblock to a server share root and set a root dentry
appropriately. This let us share superblock between mounts like
//server/sharename/foo/bar and //server/sharename/foo further.
Reviewed-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Pavel Shilovsky <piastry@etersoft.ru>
Signed-off-by: Steve French <sfrench@us.ibm.com>
Diffstat (limited to 'fs/cifs/cifsfs.c')
-rw-r--r-- | fs/cifs/cifsfs.c | 101 |
1 files changed, 98 insertions, 3 deletions
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 1d2a93c60e75..46fdd55cf427 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c | |||
@@ -415,8 +415,6 @@ cifs_show_options(struct seq_file *s, struct vfsmount *m) | |||
415 | seq_printf(s, ",nocase"); | 415 | seq_printf(s, ",nocase"); |
416 | if (tcon->retry) | 416 | if (tcon->retry) |
417 | seq_printf(s, ",hard"); | 417 | seq_printf(s, ",hard"); |
418 | if (cifs_sb->prepath) | ||
419 | seq_printf(s, ",prepath=%s", cifs_sb->prepath); | ||
420 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) | 418 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) |
421 | seq_printf(s, ",posixpaths"); | 419 | seq_printf(s, ",posixpaths"); |
422 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) | 420 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) |
@@ -530,6 +528,100 @@ static const struct super_operations cifs_super_ops = { | |||
530 | #endif | 528 | #endif |
531 | }; | 529 | }; |
532 | 530 | ||
531 | /* | ||
532 | * Get root dentry from superblock according to prefix path mount option. | ||
533 | * Return dentry with refcount + 1 on success and NULL otherwise. | ||
534 | */ | ||
535 | static struct dentry * | ||
536 | cifs_get_root(struct smb_vol *vol, struct super_block *sb) | ||
537 | { | ||
538 | int xid, rc; | ||
539 | struct inode *inode; | ||
540 | struct qstr name; | ||
541 | struct dentry *dparent = NULL, *dchild = NULL, *alias; | ||
542 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); | ||
543 | unsigned int i, full_len, len; | ||
544 | char *full_path = NULL, *pstart; | ||
545 | char sep; | ||
546 | |||
547 | full_path = cifs_build_path_to_root(vol, cifs_sb, | ||
548 | cifs_sb_master_tcon(cifs_sb)); | ||
549 | if (full_path == NULL) | ||
550 | return NULL; | ||
551 | |||
552 | cFYI(1, "Get root dentry for %s", full_path); | ||
553 | |||
554 | xid = GetXid(); | ||
555 | sep = CIFS_DIR_SEP(cifs_sb); | ||
556 | dparent = dget(sb->s_root); | ||
557 | full_len = strlen(full_path); | ||
558 | full_path[full_len] = sep; | ||
559 | pstart = full_path + 1; | ||
560 | |||
561 | for (i = 1, len = 0; i <= full_len; i++) { | ||
562 | if (full_path[i] != sep || !len) { | ||
563 | len++; | ||
564 | continue; | ||
565 | } | ||
566 | |||
567 | full_path[i] = 0; | ||
568 | cFYI(1, "get dentry for %s", pstart); | ||
569 | |||
570 | name.name = pstart; | ||
571 | name.len = len; | ||
572 | name.hash = full_name_hash(pstart, len); | ||
573 | dchild = d_lookup(dparent, &name); | ||
574 | if (dchild == NULL) { | ||
575 | cFYI(1, "not exists"); | ||
576 | dchild = d_alloc(dparent, &name); | ||
577 | if (dchild == NULL) { | ||
578 | dput(dparent); | ||
579 | dparent = NULL; | ||
580 | goto out; | ||
581 | } | ||
582 | } | ||
583 | |||
584 | cFYI(1, "get inode"); | ||
585 | if (dchild->d_inode == NULL) { | ||
586 | cFYI(1, "not exists"); | ||
587 | inode = NULL; | ||
588 | if (cifs_sb_master_tcon(CIFS_SB(sb))->unix_ext) | ||
589 | rc = cifs_get_inode_info_unix(&inode, full_path, | ||
590 | sb, xid); | ||
591 | else | ||
592 | rc = cifs_get_inode_info(&inode, full_path, | ||
593 | NULL, sb, xid, NULL); | ||
594 | if (rc) { | ||
595 | dput(dchild); | ||
596 | dput(dparent); | ||
597 | dparent = NULL; | ||
598 | goto out; | ||
599 | } | ||
600 | alias = d_materialise_unique(dchild, inode); | ||
601 | if (alias != NULL) { | ||
602 | dput(dchild); | ||
603 | if (IS_ERR(alias)) { | ||
604 | dput(dparent); | ||
605 | dparent = NULL; | ||
606 | goto out; | ||
607 | } | ||
608 | dchild = alias; | ||
609 | } | ||
610 | } | ||
611 | cFYI(1, "parent %p, child %p", dparent, dchild); | ||
612 | |||
613 | dput(dparent); | ||
614 | dparent = dchild; | ||
615 | len = 0; | ||
616 | pstart = full_path + i + 1; | ||
617 | full_path[i] = sep; | ||
618 | } | ||
619 | out: | ||
620 | _FreeXid(xid); | ||
621 | kfree(full_path); | ||
622 | return dparent; | ||
623 | } | ||
624 | |||
533 | static struct dentry * | 625 | static struct dentry * |
534 | cifs_do_mount(struct file_system_type *fs_type, | 626 | cifs_do_mount(struct file_system_type *fs_type, |
535 | int flags, const char *dev_name, void *data) | 627 | int flags, const char *dev_name, void *data) |
@@ -585,7 +677,10 @@ cifs_do_mount(struct file_system_type *fs_type, | |||
585 | 677 | ||
586 | sb->s_flags |= MS_ACTIVE; | 678 | sb->s_flags |= MS_ACTIVE; |
587 | 679 | ||
588 | root = dget(sb->s_root); | 680 | root = cifs_get_root(volume_info, sb); |
681 | if (root == NULL) | ||
682 | goto out_super; | ||
683 | cFYI(1, "dentry root is: %p", root); | ||
589 | goto out; | 684 | goto out; |
590 | 685 | ||
591 | out_super: | 686 | out_super: |