diff options
-rw-r--r-- | fs/namei.c | 118 |
1 files changed, 35 insertions, 83 deletions
diff --git a/fs/namei.c b/fs/namei.c index f5de5bb1a61f..b9e537980ef5 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -1520,45 +1520,44 @@ return_err: | |||
1520 | return err; | 1520 | return err; |
1521 | } | 1521 | } |
1522 | 1522 | ||
1523 | static int path_init_rcu(int dfd, const char *name, unsigned int flags, struct nameidata *nd) | 1523 | static int path_init(int dfd, const char *name, unsigned int flags, struct nameidata *nd) |
1524 | { | 1524 | { |
1525 | int retval = 0; | 1525 | int retval = 0; |
1526 | int fput_needed; | 1526 | int fput_needed; |
1527 | struct file *file; | 1527 | struct file *file; |
1528 | 1528 | ||
1529 | nd->last_type = LAST_ROOT; /* if there are only slashes... */ | 1529 | nd->last_type = LAST_ROOT; /* if there are only slashes... */ |
1530 | nd->flags = flags | LOOKUP_RCU; | 1530 | nd->flags = flags; |
1531 | nd->depth = 0; | 1531 | nd->depth = 0; |
1532 | nd->root.mnt = NULL; | 1532 | nd->root.mnt = NULL; |
1533 | nd->file = NULL; | 1533 | nd->file = NULL; |
1534 | 1534 | ||
1535 | if (*name=='/') { | 1535 | if (*name=='/') { |
1536 | struct fs_struct *fs = current->fs; | 1536 | if (flags & LOOKUP_RCU) { |
1537 | unsigned seq; | 1537 | br_read_lock(vfsmount_lock); |
1538 | 1538 | rcu_read_lock(); | |
1539 | br_read_lock(vfsmount_lock); | 1539 | set_root_rcu(nd); |
1540 | rcu_read_lock(); | 1540 | } else { |
1541 | 1541 | set_root(nd); | |
1542 | do { | 1542 | path_get(&nd->root); |
1543 | seq = read_seqcount_begin(&fs->seq); | 1543 | } |
1544 | nd->root = fs->root; | 1544 | nd->path = nd->root; |
1545 | nd->path = nd->root; | ||
1546 | nd->seq = __read_seqcount_begin(&nd->path.dentry->d_seq); | ||
1547 | } while (read_seqcount_retry(&fs->seq, seq)); | ||
1548 | |||
1549 | } else if (dfd == AT_FDCWD) { | 1545 | } else if (dfd == AT_FDCWD) { |
1550 | struct fs_struct *fs = current->fs; | 1546 | if (flags & LOOKUP_RCU) { |
1551 | unsigned seq; | 1547 | struct fs_struct *fs = current->fs; |
1552 | 1548 | unsigned seq; | |
1553 | br_read_lock(vfsmount_lock); | ||
1554 | rcu_read_lock(); | ||
1555 | 1549 | ||
1556 | do { | 1550 | br_read_lock(vfsmount_lock); |
1557 | seq = read_seqcount_begin(&fs->seq); | 1551 | rcu_read_lock(); |
1558 | nd->path = fs->pwd; | ||
1559 | nd->seq = __read_seqcount_begin(&nd->path.dentry->d_seq); | ||
1560 | } while (read_seqcount_retry(&fs->seq, seq)); | ||
1561 | 1552 | ||
1553 | do { | ||
1554 | seq = read_seqcount_begin(&fs->seq); | ||
1555 | nd->path = fs->pwd; | ||
1556 | nd->seq = __read_seqcount_begin(&nd->path.dentry->d_seq); | ||
1557 | } while (read_seqcount_retry(&fs->seq, seq)); | ||
1558 | } else { | ||
1559 | get_fs_pwd(current->fs, &nd->path); | ||
1560 | } | ||
1562 | } else { | 1561 | } else { |
1563 | struct dentry *dentry; | 1562 | struct dentry *dentry; |
1564 | 1563 | ||
@@ -1578,62 +1577,18 @@ static int path_init_rcu(int dfd, const char *name, unsigned int flags, struct n | |||
1578 | goto fput_fail; | 1577 | goto fput_fail; |
1579 | 1578 | ||
1580 | nd->path = file->f_path; | 1579 | nd->path = file->f_path; |
1581 | if (fput_needed) | 1580 | if (flags & LOOKUP_RCU) { |
1582 | nd->file = file; | 1581 | if (fput_needed) |
1583 | 1582 | nd->file = file; | |
1584 | nd->seq = __read_seqcount_begin(&nd->path.dentry->d_seq); | 1583 | nd->seq = __read_seqcount_begin(&nd->path.dentry->d_seq); |
1585 | br_read_lock(vfsmount_lock); | 1584 | br_read_lock(vfsmount_lock); |
1586 | rcu_read_lock(); | 1585 | rcu_read_lock(); |
1586 | } else { | ||
1587 | path_get(&file->f_path); | ||
1588 | fput_light(file, fput_needed); | ||
1589 | } | ||
1587 | } | 1590 | } |
1588 | nd->inode = nd->path.dentry->d_inode; | ||
1589 | return 0; | ||
1590 | 1591 | ||
1591 | fput_fail: | ||
1592 | fput_light(file, fput_needed); | ||
1593 | out_fail: | ||
1594 | return retval; | ||
1595 | } | ||
1596 | |||
1597 | static int path_init(int dfd, const char *name, unsigned int flags, struct nameidata *nd) | ||
1598 | { | ||
1599 | int retval = 0; | ||
1600 | int fput_needed; | ||
1601 | struct file *file; | ||
1602 | |||
1603 | nd->last_type = LAST_ROOT; /* if there are only slashes... */ | ||
1604 | nd->flags = flags; | ||
1605 | nd->depth = 0; | ||
1606 | nd->root.mnt = NULL; | ||
1607 | |||
1608 | if (*name=='/') { | ||
1609 | set_root(nd); | ||
1610 | nd->path = nd->root; | ||
1611 | path_get(&nd->root); | ||
1612 | } else if (dfd == AT_FDCWD) { | ||
1613 | get_fs_pwd(current->fs, &nd->path); | ||
1614 | } else { | ||
1615 | struct dentry *dentry; | ||
1616 | |||
1617 | file = fget_light(dfd, &fput_needed); | ||
1618 | retval = -EBADF; | ||
1619 | if (!file) | ||
1620 | goto out_fail; | ||
1621 | |||
1622 | dentry = file->f_path.dentry; | ||
1623 | |||
1624 | retval = -ENOTDIR; | ||
1625 | if (!S_ISDIR(dentry->d_inode->i_mode)) | ||
1626 | goto fput_fail; | ||
1627 | |||
1628 | retval = file_permission(file, MAY_EXEC); | ||
1629 | if (retval) | ||
1630 | goto fput_fail; | ||
1631 | |||
1632 | nd->path = file->f_path; | ||
1633 | path_get(&file->f_path); | ||
1634 | |||
1635 | fput_light(file, fput_needed); | ||
1636 | } | ||
1637 | nd->inode = nd->path.dentry->d_inode; | 1592 | nd->inode = nd->path.dentry->d_inode; |
1638 | return 0; | 1593 | return 0; |
1639 | 1594 | ||
@@ -1663,10 +1618,7 @@ static int path_lookupat(int dfd, const char *name, | |||
1663 | * be handled by restarting a traditional ref-walk (which will always | 1618 | * be handled by restarting a traditional ref-walk (which will always |
1664 | * be able to complete). | 1619 | * be able to complete). |
1665 | */ | 1620 | */ |
1666 | if (flags & LOOKUP_RCU) | 1621 | retval = path_init(dfd, name, flags, nd); |
1667 | retval = path_init_rcu(dfd, name, flags, nd); | ||
1668 | else | ||
1669 | retval = path_init(dfd, name, flags, nd); | ||
1670 | 1622 | ||
1671 | if (unlikely(retval)) | 1623 | if (unlikely(retval)) |
1672 | return retval; | 1624 | return retval; |