diff options
| author | Al Viro <viro@zeniv.linux.org.uk> | 2011-07-18 13:50:40 -0400 |
|---|---|---|
| committer | Al Viro <viro@zeniv.linux.org.uk> | 2011-07-18 13:51:58 -0400 |
| commit | fec11dd9a0109fe52fd631e5c510778d6cbff6cc (patch) | |
| tree | 2a59d8e2cb0325862740fc24ecb246aa02c8413f | |
| parent | 0916a5e45fbd2604a303c8cc18e6b2b7c815e4c9 (diff) | |
Fix cifs_get_root()
Add missing ->i_mutex, convert to lookup_one_len() instead of
(broken) open-coded analog, cope with getting something like
a//b as relative pathname. Simplify the hell out of it, while
we are there...
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Reviewed-by: Jeff Layton <jlayton@redhat.com>
| -rw-r--r-- | fs/cifs/cifsfs.c | 100 |
1 files changed, 29 insertions, 71 deletions
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 3e2989976297..bc4b12ca537b 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c | |||
| @@ -35,6 +35,7 @@ | |||
| 35 | #include <linux/delay.h> | 35 | #include <linux/delay.h> |
| 36 | #include <linux/kthread.h> | 36 | #include <linux/kthread.h> |
| 37 | #include <linux/freezer.h> | 37 | #include <linux/freezer.h> |
| 38 | #include <linux/namei.h> | ||
| 38 | #include <net/ipv6.h> | 39 | #include <net/ipv6.h> |
| 39 | #include "cifsfs.h" | 40 | #include "cifsfs.h" |
| 40 | #include "cifspdu.h" | 41 | #include "cifspdu.h" |
| @@ -542,14 +543,12 @@ static const struct super_operations cifs_super_ops = { | |||
| 542 | static struct dentry * | 543 | static struct dentry * |
| 543 | cifs_get_root(struct smb_vol *vol, struct super_block *sb) | 544 | cifs_get_root(struct smb_vol *vol, struct super_block *sb) |
| 544 | { | 545 | { |
| 545 | int xid, rc; | 546 | struct dentry *dentry; |
| 546 | struct inode *inode; | ||
| 547 | struct qstr name; | ||
| 548 | struct dentry *dparent = NULL, *dchild = NULL, *alias; | ||
| 549 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); | 547 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); |
| 550 | unsigned int i, full_len, len; | 548 | char *full_path = NULL; |
| 551 | char *full_path = NULL, *pstart; | 549 | char *s, *p; |
| 552 | char sep; | 550 | char sep; |
| 551 | int xid; | ||
| 553 | 552 | ||
| 554 | full_path = cifs_build_path_to_root(vol, cifs_sb, | 553 | full_path = cifs_build_path_to_root(vol, cifs_sb, |
| 555 | cifs_sb_master_tcon(cifs_sb)); | 554 | cifs_sb_master_tcon(cifs_sb)); |
| @@ -560,73 +559,32 @@ cifs_get_root(struct smb_vol *vol, struct super_block *sb) | |||
| 560 | 559 | ||
| 561 | xid = GetXid(); | 560 | xid = GetXid(); |
| 562 | sep = CIFS_DIR_SEP(cifs_sb); | 561 | sep = CIFS_DIR_SEP(cifs_sb); |
| 563 | dparent = dget(sb->s_root); | 562 | dentry = dget(sb->s_root); |
| 564 | full_len = strlen(full_path); | 563 | p = s = full_path; |
| 565 | full_path[full_len] = sep; | 564 | |
| 566 | pstart = full_path + 1; | 565 | do { |
| 567 | 566 | struct inode *dir = dentry->d_inode; | |
| 568 | for (i = 1, len = 0; i <= full_len; i++) { | 567 | struct dentry *child; |
| 569 | if (full_path[i] != sep || !len) { | 568 | |
| 570 | len++; | 569 | /* skip separators */ |
| 571 | continue; | 570 | while (*s == sep) |
| 572 | } | 571 | s++; |
| 573 | 572 | if (!*s) | |
| 574 | full_path[i] = 0; | 573 | break; |
| 575 | cFYI(1, "get dentry for %s", pstart); | 574 | p = s++; |
| 576 | 575 | /* next separator */ | |
| 577 | name.name = pstart; | 576 | while (*s && *s != sep) |
| 578 | name.len = len; | 577 | s++; |
| 579 | name.hash = full_name_hash(pstart, len); | 578 | |
| 580 | dchild = d_lookup(dparent, &name); | 579 | mutex_lock(&dir->i_mutex); |
| 581 | if (dchild == NULL) { | 580 | child = lookup_one_len(p, dentry, s - p); |
| 582 | cFYI(1, "not exists"); | 581 | mutex_unlock(&dir->i_mutex); |
| 583 | dchild = d_alloc(dparent, &name); | 582 | dput(dentry); |
| 584 | if (dchild == NULL) { | 583 | dentry = child; |
| 585 | dput(dparent); | 584 | } while (!IS_ERR(dentry)); |
| 586 | dparent = ERR_PTR(-ENOMEM); | ||
| 587 | goto out; | ||
| 588 | } | ||
| 589 | } | ||
| 590 | |||
| 591 | cFYI(1, "get inode"); | ||
| 592 | if (dchild->d_inode == NULL) { | ||
| 593 | cFYI(1, "not exists"); | ||
| 594 | inode = NULL; | ||
| 595 | if (cifs_sb_master_tcon(CIFS_SB(sb))->unix_ext) | ||
| 596 | rc = cifs_get_inode_info_unix(&inode, full_path, | ||
| 597 | sb, xid); | ||
| 598 | else | ||
| 599 | rc = cifs_get_inode_info(&inode, full_path, | ||
| 600 | NULL, sb, xid, NULL); | ||
| 601 | if (rc) { | ||
| 602 | dput(dchild); | ||
| 603 | dput(dparent); | ||
| 604 | dparent = ERR_PTR(rc); | ||
| 605 | goto out; | ||
| 606 | } | ||
| 607 | alias = d_materialise_unique(dchild, inode); | ||
| 608 | if (alias != NULL) { | ||
| 609 | dput(dchild); | ||
| 610 | if (IS_ERR(alias)) { | ||
| 611 | dput(dparent); | ||
| 612 | dparent = ERR_PTR(-EINVAL); /* XXX */ | ||
| 613 | goto out; | ||
| 614 | } | ||
| 615 | dchild = alias; | ||
| 616 | } | ||
| 617 | } | ||
| 618 | cFYI(1, "parent %p, child %p", dparent, dchild); | ||
| 619 | |||
| 620 | dput(dparent); | ||
| 621 | dparent = dchild; | ||
| 622 | len = 0; | ||
| 623 | pstart = full_path + i + 1; | ||
| 624 | full_path[i] = sep; | ||
| 625 | } | ||
| 626 | out: | ||
| 627 | _FreeXid(xid); | 585 | _FreeXid(xid); |
| 628 | kfree(full_path); | 586 | kfree(full_path); |
| 629 | return dparent; | 587 | return dentry; |
| 630 | } | 588 | } |
| 631 | 589 | ||
| 632 | static int cifs_set_super(struct super_block *sb, void *data) | 590 | static int cifs_set_super(struct super_block *sb, void *data) |
