diff options
author | David Howells <dhowells@redhat.com> | 2013-09-12 14:22:53 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2013-11-09 00:16:30 -0500 |
commit | b18825a7c8e37a7cf6abb97a12a6ad71af160de7 (patch) | |
tree | c3556fc0195f15382d636188f3d4e5fa418d7379 /fs/namei.c | |
parent | afabada957a6b28abfd37eb52efeefdfe6871c4b (diff) |
VFS: Put a small type field into struct dentry::d_flags
Put a type field into struct dentry::d_flags to indicate if the dentry is one
of the following types that relate particularly to pathwalk:
Miss (negative dentry)
Directory
"Automount" directory (defective - no i_op->lookup())
Symlink
Other (regular, socket, fifo, device)
The type field is set to one of the first five types on a dentry by calls to
__d_instantiate() and d_obtain_alias() from information in the inode (if one is
given).
The type is cleared by dentry_unlink_inode() when it reconstitutes an existing
dentry as a negative dentry.
Accessors provided are:
d_set_type(dentry, type)
d_is_directory(dentry)
d_is_autodir(dentry)
d_is_symlink(dentry)
d_is_file(dentry)
d_is_negative(dentry)
d_is_positive(dentry)
A bunch of checks in pathname resolution switched to those.
Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/namei.c')
-rw-r--r-- | fs/namei.c | 95 |
1 files changed, 38 insertions, 57 deletions
diff --git a/fs/namei.c b/fs/namei.c index e5c0118ba9f8..e1fa43346c61 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -1501,18 +1501,9 @@ static void terminate_walk(struct nameidata *nd) | |||
1501 | * so we keep a cache of "no, this doesn't need follow_link" | 1501 | * so we keep a cache of "no, this doesn't need follow_link" |
1502 | * for the common case. | 1502 | * for the common case. |
1503 | */ | 1503 | */ |
1504 | static inline int should_follow_link(struct inode *inode, int follow) | 1504 | static inline int should_follow_link(struct dentry *dentry, int follow) |
1505 | { | 1505 | { |
1506 | if (unlikely(!(inode->i_opflags & IOP_NOFOLLOW))) { | 1506 | return unlikely(d_is_symlink(dentry)) ? follow : 0; |
1507 | if (likely(inode->i_op->follow_link)) | ||
1508 | return follow; | ||
1509 | |||
1510 | /* This gets set once for the inode lifetime */ | ||
1511 | spin_lock(&inode->i_lock); | ||
1512 | inode->i_opflags |= IOP_NOFOLLOW; | ||
1513 | spin_unlock(&inode->i_lock); | ||
1514 | } | ||
1515 | return 0; | ||
1516 | } | 1507 | } |
1517 | 1508 | ||
1518 | static inline int walk_component(struct nameidata *nd, struct path *path, | 1509 | static inline int walk_component(struct nameidata *nd, struct path *path, |
@@ -1542,7 +1533,7 @@ static inline int walk_component(struct nameidata *nd, struct path *path, | |||
1542 | if (!inode) | 1533 | if (!inode) |
1543 | goto out_path_put; | 1534 | goto out_path_put; |
1544 | 1535 | ||
1545 | if (should_follow_link(inode, follow)) { | 1536 | if (should_follow_link(path->dentry, follow)) { |
1546 | if (nd->flags & LOOKUP_RCU) { | 1537 | if (nd->flags & LOOKUP_RCU) { |
1547 | if (unlikely(unlazy_walk(nd, path->dentry))) { | 1538 | if (unlikely(unlazy_walk(nd, path->dentry))) { |
1548 | err = -ECHILD; | 1539 | err = -ECHILD; |
@@ -1601,26 +1592,6 @@ static inline int nested_symlink(struct path *path, struct nameidata *nd) | |||
1601 | } | 1592 | } |
1602 | 1593 | ||
1603 | /* | 1594 | /* |
1604 | * We really don't want to look at inode->i_op->lookup | ||
1605 | * when we don't have to. So we keep a cache bit in | ||
1606 | * the inode ->i_opflags field that says "yes, we can | ||
1607 | * do lookup on this inode". | ||
1608 | */ | ||
1609 | static inline int can_lookup(struct inode *inode) | ||
1610 | { | ||
1611 | if (likely(inode->i_opflags & IOP_LOOKUP)) | ||
1612 | return 1; | ||
1613 | if (likely(!inode->i_op->lookup)) | ||
1614 | return 0; | ||
1615 | |||
1616 | /* We do this once for the lifetime of the inode */ | ||
1617 | spin_lock(&inode->i_lock); | ||
1618 | inode->i_opflags |= IOP_LOOKUP; | ||
1619 | spin_unlock(&inode->i_lock); | ||
1620 | return 1; | ||
1621 | } | ||
1622 | |||
1623 | /* | ||
1624 | * We can do the critical dentry name comparison and hashing | 1595 | * We can do the critical dentry name comparison and hashing |
1625 | * operations one word at a time, but we are limited to: | 1596 | * operations one word at a time, but we are limited to: |
1626 | * | 1597 | * |
@@ -1823,7 +1794,7 @@ static int link_path_walk(const char *name, struct nameidata *nd) | |||
1823 | if (err) | 1794 | if (err) |
1824 | return err; | 1795 | return err; |
1825 | } | 1796 | } |
1826 | if (!can_lookup(nd->inode)) { | 1797 | if (!d_is_directory(nd->path.dentry)) { |
1827 | err = -ENOTDIR; | 1798 | err = -ENOTDIR; |
1828 | break; | 1799 | break; |
1829 | } | 1800 | } |
@@ -1841,9 +1812,10 @@ static int path_init(int dfd, const char *name, unsigned int flags, | |||
1841 | nd->flags = flags | LOOKUP_JUMPED; | 1812 | nd->flags = flags | LOOKUP_JUMPED; |
1842 | nd->depth = 0; | 1813 | nd->depth = 0; |
1843 | if (flags & LOOKUP_ROOT) { | 1814 | if (flags & LOOKUP_ROOT) { |
1844 | struct inode *inode = nd->root.dentry->d_inode; | 1815 | struct dentry *root = nd->root.dentry; |
1816 | struct inode *inode = root->d_inode; | ||
1845 | if (*name) { | 1817 | if (*name) { |
1846 | if (!can_lookup(inode)) | 1818 | if (!d_is_directory(root)) |
1847 | return -ENOTDIR; | 1819 | return -ENOTDIR; |
1848 | retval = inode_permission(inode, MAY_EXEC); | 1820 | retval = inode_permission(inode, MAY_EXEC); |
1849 | if (retval) | 1821 | if (retval) |
@@ -1899,7 +1871,7 @@ static int path_init(int dfd, const char *name, unsigned int flags, | |||
1899 | dentry = f.file->f_path.dentry; | 1871 | dentry = f.file->f_path.dentry; |
1900 | 1872 | ||
1901 | if (*name) { | 1873 | if (*name) { |
1902 | if (!can_lookup(dentry->d_inode)) { | 1874 | if (!d_is_directory(dentry)) { |
1903 | fdput(f); | 1875 | fdput(f); |
1904 | return -ENOTDIR; | 1876 | return -ENOTDIR; |
1905 | } | 1877 | } |
@@ -1981,7 +1953,7 @@ static int path_lookupat(int dfd, const char *name, | |||
1981 | err = complete_walk(nd); | 1953 | err = complete_walk(nd); |
1982 | 1954 | ||
1983 | if (!err && nd->flags & LOOKUP_DIRECTORY) { | 1955 | if (!err && nd->flags & LOOKUP_DIRECTORY) { |
1984 | if (!can_lookup(nd->inode)) { | 1956 | if (!d_is_directory(nd->path.dentry)) { |
1985 | path_put(&nd->path); | 1957 | path_put(&nd->path); |
1986 | err = -ENOTDIR; | 1958 | err = -ENOTDIR; |
1987 | } | 1959 | } |
@@ -2273,7 +2245,7 @@ done: | |||
2273 | } | 2245 | } |
2274 | path->dentry = dentry; | 2246 | path->dentry = dentry; |
2275 | path->mnt = mntget(nd->path.mnt); | 2247 | path->mnt = mntget(nd->path.mnt); |
2276 | if (should_follow_link(dentry->d_inode, nd->flags & LOOKUP_FOLLOW)) | 2248 | if (should_follow_link(dentry, nd->flags & LOOKUP_FOLLOW)) |
2277 | return 1; | 2249 | return 1; |
2278 | follow_mount(path); | 2250 | follow_mount(path); |
2279 | error = 0; | 2251 | error = 0; |
@@ -2417,12 +2389,14 @@ static inline int check_sticky(struct inode *dir, struct inode *inode) | |||
2417 | * 10. We don't allow removal of NFS sillyrenamed files; it's handled by | 2389 | * 10. We don't allow removal of NFS sillyrenamed files; it's handled by |
2418 | * nfs_async_unlink(). | 2390 | * nfs_async_unlink(). |
2419 | */ | 2391 | */ |
2420 | static int may_delete(struct inode *dir,struct dentry *victim,int isdir) | 2392 | static int may_delete(struct inode *dir, struct dentry *victim, bool isdir) |
2421 | { | 2393 | { |
2394 | struct inode *inode = victim->d_inode; | ||
2422 | int error; | 2395 | int error; |
2423 | 2396 | ||
2424 | if (!victim->d_inode) | 2397 | if (d_is_negative(victim)) |
2425 | return -ENOENT; | 2398 | return -ENOENT; |
2399 | BUG_ON(!inode); | ||
2426 | 2400 | ||
2427 | BUG_ON(victim->d_parent->d_inode != dir); | 2401 | BUG_ON(victim->d_parent->d_inode != dir); |
2428 | audit_inode_child(dir, victim, AUDIT_TYPE_CHILD_DELETE); | 2402 | audit_inode_child(dir, victim, AUDIT_TYPE_CHILD_DELETE); |
@@ -2432,15 +2406,16 @@ static int may_delete(struct inode *dir,struct dentry *victim,int isdir) | |||
2432 | return error; | 2406 | return error; |
2433 | if (IS_APPEND(dir)) | 2407 | if (IS_APPEND(dir)) |
2434 | return -EPERM; | 2408 | return -EPERM; |
2435 | if (check_sticky(dir, victim->d_inode)||IS_APPEND(victim->d_inode)|| | 2409 | |
2436 | IS_IMMUTABLE(victim->d_inode) || IS_SWAPFILE(victim->d_inode)) | 2410 | if (check_sticky(dir, inode) || IS_APPEND(inode) || |
2411 | IS_IMMUTABLE(inode) || IS_SWAPFILE(inode)) | ||
2437 | return -EPERM; | 2412 | return -EPERM; |
2438 | if (isdir) { | 2413 | if (isdir) { |
2439 | if (!S_ISDIR(victim->d_inode->i_mode)) | 2414 | if (!d_is_directory(victim) && !d_is_autodir(victim)) |
2440 | return -ENOTDIR; | 2415 | return -ENOTDIR; |
2441 | if (IS_ROOT(victim)) | 2416 | if (IS_ROOT(victim)) |
2442 | return -EBUSY; | 2417 | return -EBUSY; |
2443 | } else if (S_ISDIR(victim->d_inode->i_mode)) | 2418 | } else if (d_is_directory(victim) || d_is_autodir(victim)) |
2444 | return -EISDIR; | 2419 | return -EISDIR; |
2445 | if (IS_DEADDIR(dir)) | 2420 | if (IS_DEADDIR(dir)) |
2446 | return -ENOENT; | 2421 | return -ENOENT; |
@@ -2974,7 +2949,7 @@ retry_lookup: | |||
2974 | /* | 2949 | /* |
2975 | * create/update audit record if it already exists. | 2950 | * create/update audit record if it already exists. |
2976 | */ | 2951 | */ |
2977 | if (path->dentry->d_inode) | 2952 | if (d_is_positive(path->dentry)) |
2978 | audit_inode(name, path->dentry, 0); | 2953 | audit_inode(name, path->dentry, 0); |
2979 | 2954 | ||
2980 | /* | 2955 | /* |
@@ -3003,12 +2978,12 @@ retry_lookup: | |||
3003 | finish_lookup: | 2978 | finish_lookup: |
3004 | /* we _can_ be in RCU mode here */ | 2979 | /* we _can_ be in RCU mode here */ |
3005 | error = -ENOENT; | 2980 | error = -ENOENT; |
3006 | if (!inode) { | 2981 | if (d_is_negative(path->dentry)) { |
3007 | path_to_nameidata(path, nd); | 2982 | path_to_nameidata(path, nd); |
3008 | goto out; | 2983 | goto out; |
3009 | } | 2984 | } |
3010 | 2985 | ||
3011 | if (should_follow_link(inode, !symlink_ok)) { | 2986 | if (should_follow_link(path->dentry, !symlink_ok)) { |
3012 | if (nd->flags & LOOKUP_RCU) { | 2987 | if (nd->flags & LOOKUP_RCU) { |
3013 | if (unlikely(unlazy_walk(nd, path->dentry))) { | 2988 | if (unlikely(unlazy_walk(nd, path->dentry))) { |
3014 | error = -ECHILD; | 2989 | error = -ECHILD; |
@@ -3037,10 +3012,11 @@ finish_open: | |||
3037 | } | 3012 | } |
3038 | audit_inode(name, nd->path.dentry, 0); | 3013 | audit_inode(name, nd->path.dentry, 0); |
3039 | error = -EISDIR; | 3014 | error = -EISDIR; |
3040 | if ((open_flag & O_CREAT) && S_ISDIR(nd->inode->i_mode)) | 3015 | if ((open_flag & O_CREAT) && |
3016 | (d_is_directory(nd->path.dentry) || d_is_autodir(nd->path.dentry))) | ||
3041 | goto out; | 3017 | goto out; |
3042 | error = -ENOTDIR; | 3018 | error = -ENOTDIR; |
3043 | if ((nd->flags & LOOKUP_DIRECTORY) && !can_lookup(nd->inode)) | 3019 | if ((nd->flags & LOOKUP_DIRECTORY) && !d_is_directory(nd->path.dentry)) |
3044 | goto out; | 3020 | goto out; |
3045 | if (!S_ISREG(nd->inode->i_mode)) | 3021 | if (!S_ISREG(nd->inode->i_mode)) |
3046 | will_truncate = false; | 3022 | will_truncate = false; |
@@ -3266,7 +3242,7 @@ struct file *do_file_open_root(struct dentry *dentry, struct vfsmount *mnt, | |||
3266 | nd.root.mnt = mnt; | 3242 | nd.root.mnt = mnt; |
3267 | nd.root.dentry = dentry; | 3243 | nd.root.dentry = dentry; |
3268 | 3244 | ||
3269 | if (dentry->d_inode->i_op->follow_link && op->intent & LOOKUP_OPEN) | 3245 | if (d_is_symlink(dentry) && op->intent & LOOKUP_OPEN) |
3270 | return ERR_PTR(-ELOOP); | 3246 | return ERR_PTR(-ELOOP); |
3271 | 3247 | ||
3272 | file = path_openat(-1, &filename, &nd, op, flags | LOOKUP_RCU); | 3248 | file = path_openat(-1, &filename, &nd, op, flags | LOOKUP_RCU); |
@@ -3316,8 +3292,9 @@ struct dentry *kern_path_create(int dfd, const char *pathname, | |||
3316 | goto unlock; | 3292 | goto unlock; |
3317 | 3293 | ||
3318 | error = -EEXIST; | 3294 | error = -EEXIST; |
3319 | if (dentry->d_inode) | 3295 | if (d_is_positive(dentry)) |
3320 | goto fail; | 3296 | goto fail; |
3297 | |||
3321 | /* | 3298 | /* |
3322 | * Special case - lookup gave negative, but... we had foo/bar/ | 3299 | * Special case - lookup gave negative, but... we had foo/bar/ |
3323 | * From the vfs_mknod() POV we just have a negative dentry - | 3300 | * From the vfs_mknod() POV we just have a negative dentry - |
@@ -3706,7 +3683,7 @@ retry: | |||
3706 | if (nd.last.name[nd.last.len]) | 3683 | if (nd.last.name[nd.last.len]) |
3707 | goto slashes; | 3684 | goto slashes; |
3708 | inode = dentry->d_inode; | 3685 | inode = dentry->d_inode; |
3709 | if (!inode) | 3686 | if (d_is_negative(dentry)) |
3710 | goto slashes; | 3687 | goto slashes; |
3711 | ihold(inode); | 3688 | ihold(inode); |
3712 | error = security_path_unlink(&nd.path, dentry); | 3689 | error = security_path_unlink(&nd.path, dentry); |
@@ -3731,8 +3708,12 @@ exit1: | |||
3731 | return error; | 3708 | return error; |
3732 | 3709 | ||
3733 | slashes: | 3710 | slashes: |
3734 | error = !dentry->d_inode ? -ENOENT : | 3711 | if (d_is_negative(dentry)) |
3735 | S_ISDIR(dentry->d_inode->i_mode) ? -EISDIR : -ENOTDIR; | 3712 | error = -ENOENT; |
3713 | else if (d_is_directory(dentry) || d_is_autodir(dentry)) | ||
3714 | error = -EISDIR; | ||
3715 | else | ||
3716 | error = -ENOTDIR; | ||
3736 | goto exit2; | 3717 | goto exit2; |
3737 | } | 3718 | } |
3738 | 3719 | ||
@@ -4046,7 +4027,7 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
4046 | struct inode *new_dir, struct dentry *new_dentry) | 4027 | struct inode *new_dir, struct dentry *new_dentry) |
4047 | { | 4028 | { |
4048 | int error; | 4029 | int error; |
4049 | int is_dir = S_ISDIR(old_dentry->d_inode->i_mode); | 4030 | int is_dir = d_is_directory(old_dentry) || d_is_autodir(old_dentry); |
4050 | const unsigned char *old_name; | 4031 | const unsigned char *old_name; |
4051 | 4032 | ||
4052 | if (old_dentry->d_inode == new_dentry->d_inode) | 4033 | if (old_dentry->d_inode == new_dentry->d_inode) |
@@ -4134,10 +4115,10 @@ retry: | |||
4134 | goto exit3; | 4115 | goto exit3; |
4135 | /* source must exist */ | 4116 | /* source must exist */ |
4136 | error = -ENOENT; | 4117 | error = -ENOENT; |
4137 | if (!old_dentry->d_inode) | 4118 | if (d_is_negative(old_dentry)) |
4138 | goto exit4; | 4119 | goto exit4; |
4139 | /* unless the source is a directory trailing slashes give -ENOTDIR */ | 4120 | /* unless the source is a directory trailing slashes give -ENOTDIR */ |
4140 | if (!S_ISDIR(old_dentry->d_inode->i_mode)) { | 4121 | if (!d_is_directory(old_dentry) && !d_is_autodir(old_dentry)) { |
4141 | error = -ENOTDIR; | 4122 | error = -ENOTDIR; |
4142 | if (oldnd.last.name[oldnd.last.len]) | 4123 | if (oldnd.last.name[oldnd.last.len]) |
4143 | goto exit4; | 4124 | goto exit4; |