Commit b18825a7c8e37a7cf6abb97a12a6ad71af160de7
Committed by
Al Viro
1 parent
afabada957
Exists in
master
and in
16 other branches
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>
Showing 3 changed files with 158 additions and 82 deletions Side-by-side Diff
fs/dcache.c
... | ... | @@ -343,6 +343,7 @@ |
343 | 343 | __releases(dentry->d_inode->i_lock) |
344 | 344 | { |
345 | 345 | struct inode *inode = dentry->d_inode; |
346 | + __d_clear_type(dentry); | |
346 | 347 | dentry->d_inode = NULL; |
347 | 348 | hlist_del_init(&dentry->d_alias); |
348 | 349 | dentry_rcuwalk_barrier(dentry); |
349 | 350 | |
350 | 351 | |
351 | 352 | |
... | ... | @@ -1648,14 +1649,42 @@ |
1648 | 1649 | } |
1649 | 1650 | EXPORT_SYMBOL(d_set_d_op); |
1650 | 1651 | |
1652 | +static unsigned d_flags_for_inode(struct inode *inode) | |
1653 | +{ | |
1654 | + unsigned add_flags = DCACHE_FILE_TYPE; | |
1655 | + | |
1656 | + if (!inode) | |
1657 | + return DCACHE_MISS_TYPE; | |
1658 | + | |
1659 | + if (S_ISDIR(inode->i_mode)) { | |
1660 | + add_flags = DCACHE_DIRECTORY_TYPE; | |
1661 | + if (unlikely(!(inode->i_opflags & IOP_LOOKUP))) { | |
1662 | + if (unlikely(!inode->i_op->lookup)) | |
1663 | + add_flags = DCACHE_AUTODIR_TYPE; | |
1664 | + else | |
1665 | + inode->i_opflags |= IOP_LOOKUP; | |
1666 | + } | |
1667 | + } else if (unlikely(!(inode->i_opflags & IOP_NOFOLLOW))) { | |
1668 | + if (unlikely(inode->i_op->follow_link)) | |
1669 | + add_flags = DCACHE_SYMLINK_TYPE; | |
1670 | + else | |
1671 | + inode->i_opflags |= IOP_NOFOLLOW; | |
1672 | + } | |
1673 | + | |
1674 | + if (unlikely(IS_AUTOMOUNT(inode))) | |
1675 | + add_flags |= DCACHE_NEED_AUTOMOUNT; | |
1676 | + return add_flags; | |
1677 | +} | |
1678 | + | |
1651 | 1679 | static void __d_instantiate(struct dentry *dentry, struct inode *inode) |
1652 | 1680 | { |
1681 | + unsigned add_flags = d_flags_for_inode(inode); | |
1682 | + | |
1653 | 1683 | spin_lock(&dentry->d_lock); |
1654 | - if (inode) { | |
1655 | - if (unlikely(IS_AUTOMOUNT(inode))) | |
1656 | - dentry->d_flags |= DCACHE_NEED_AUTOMOUNT; | |
1684 | + dentry->d_flags &= ~DCACHE_ENTRY_TYPE; | |
1685 | + dentry->d_flags |= add_flags; | |
1686 | + if (inode) | |
1657 | 1687 | hlist_add_head(&dentry->d_alias, &inode->i_dentry); |
1658 | - } | |
1659 | 1688 | dentry->d_inode = inode; |
1660 | 1689 | dentry_rcuwalk_barrier(dentry); |
1661 | 1690 | spin_unlock(&dentry->d_lock); |
... | ... | @@ -1860,6 +1889,7 @@ |
1860 | 1889 | static const struct qstr anonstring = QSTR_INIT("/", 1); |
1861 | 1890 | struct dentry *tmp; |
1862 | 1891 | struct dentry *res; |
1892 | + unsigned add_flags; | |
1863 | 1893 | |
1864 | 1894 | if (!inode) |
1865 | 1895 | return ERR_PTR(-ESTALE); |
1866 | 1896 | |
... | ... | @@ -1885,9 +1915,11 @@ |
1885 | 1915 | } |
1886 | 1916 | |
1887 | 1917 | /* attach a disconnected dentry */ |
1918 | + add_flags = d_flags_for_inode(inode) | DCACHE_DISCONNECTED; | |
1919 | + | |
1888 | 1920 | spin_lock(&tmp->d_lock); |
1889 | 1921 | tmp->d_inode = inode; |
1890 | - tmp->d_flags |= DCACHE_DISCONNECTED; | |
1922 | + tmp->d_flags |= add_flags; | |
1891 | 1923 | hlist_add_head(&tmp->d_alias, &inode->i_dentry); |
1892 | 1924 | hlist_bl_lock(&tmp->d_sb->s_anon); |
1893 | 1925 | hlist_bl_add_head(&tmp->d_hash, &tmp->d_sb->s_anon); |
fs/namei.c
... | ... | @@ -1501,18 +1501,9 @@ |
1501 | 1501 | * so we keep a cache of "no, this doesn't need follow_link" |
1502 | 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))) { | |
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; | |
1506 | + return unlikely(d_is_symlink(dentry)) ? follow : 0; | |
1516 | 1507 | } |
1517 | 1508 | |
1518 | 1509 | static inline int walk_component(struct nameidata *nd, struct path *path, |
... | ... | @@ -1542,7 +1533,7 @@ |
1542 | 1533 | if (!inode) |
1543 | 1534 | goto out_path_put; |
1544 | 1535 | |
1545 | - if (should_follow_link(inode, follow)) { | |
1536 | + if (should_follow_link(path->dentry, follow)) { | |
1546 | 1537 | if (nd->flags & LOOKUP_RCU) { |
1547 | 1538 | if (unlikely(unlazy_walk(nd, path->dentry))) { |
1548 | 1539 | err = -ECHILD; |
... | ... | @@ -1601,26 +1592,6 @@ |
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 | 1595 | * We can do the critical dentry name comparison and hashing |
1625 | 1596 | * operations one word at a time, but we are limited to: |
1626 | 1597 | * |
... | ... | @@ -1823,7 +1794,7 @@ |
1823 | 1794 | if (err) |
1824 | 1795 | return err; |
1825 | 1796 | } |
1826 | - if (!can_lookup(nd->inode)) { | |
1797 | + if (!d_is_directory(nd->path.dentry)) { | |
1827 | 1798 | err = -ENOTDIR; |
1828 | 1799 | break; |
1829 | 1800 | } |
1830 | 1801 | |
... | ... | @@ -1841,9 +1812,10 @@ |
1841 | 1812 | nd->flags = flags | LOOKUP_JUMPED; |
1842 | 1813 | nd->depth = 0; |
1843 | 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 | 1817 | if (*name) { |
1846 | - if (!can_lookup(inode)) | |
1818 | + if (!d_is_directory(root)) | |
1847 | 1819 | return -ENOTDIR; |
1848 | 1820 | retval = inode_permission(inode, MAY_EXEC); |
1849 | 1821 | if (retval) |
... | ... | @@ -1899,7 +1871,7 @@ |
1899 | 1871 | dentry = f.file->f_path.dentry; |
1900 | 1872 | |
1901 | 1873 | if (*name) { |
1902 | - if (!can_lookup(dentry->d_inode)) { | |
1874 | + if (!d_is_directory(dentry)) { | |
1903 | 1875 | fdput(f); |
1904 | 1876 | return -ENOTDIR; |
1905 | 1877 | } |
... | ... | @@ -1981,7 +1953,7 @@ |
1981 | 1953 | err = complete_walk(nd); |
1982 | 1954 | |
1983 | 1955 | if (!err && nd->flags & LOOKUP_DIRECTORY) { |
1984 | - if (!can_lookup(nd->inode)) { | |
1956 | + if (!d_is_directory(nd->path.dentry)) { | |
1985 | 1957 | path_put(&nd->path); |
1986 | 1958 | err = -ENOTDIR; |
1987 | 1959 | } |
... | ... | @@ -2273,7 +2245,7 @@ |
2273 | 2245 | } |
2274 | 2246 | path->dentry = dentry; |
2275 | 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 | 2249 | return 1; |
2278 | 2250 | follow_mount(path); |
2279 | 2251 | error = 0; |
2280 | 2252 | |
2281 | 2253 | |
2282 | 2254 | |
... | ... | @@ -2417,12 +2389,14 @@ |
2417 | 2389 | * 10. We don't allow removal of NFS sillyrenamed files; it's handled by |
2418 | 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 | 2395 | int error; |
2423 | 2396 | |
2424 | - if (!victim->d_inode) | |
2397 | + if (d_is_negative(victim)) | |
2425 | 2398 | return -ENOENT; |
2399 | + BUG_ON(!inode); | |
2426 | 2400 | |
2427 | 2401 | BUG_ON(victim->d_parent->d_inode != dir); |
2428 | 2402 | audit_inode_child(dir, victim, AUDIT_TYPE_CHILD_DELETE); |
2429 | 2403 | |
2430 | 2404 | |
... | ... | @@ -2432,15 +2406,16 @@ |
2432 | 2406 | return error; |
2433 | 2407 | if (IS_APPEND(dir)) |
2434 | 2408 | return -EPERM; |
2435 | - if (check_sticky(dir, victim->d_inode)||IS_APPEND(victim->d_inode)|| | |
2436 | - IS_IMMUTABLE(victim->d_inode) || IS_SWAPFILE(victim->d_inode)) | |
2409 | + | |
2410 | + if (check_sticky(dir, inode) || IS_APPEND(inode) || | |
2411 | + IS_IMMUTABLE(inode) || IS_SWAPFILE(inode)) | |
2437 | 2412 | return -EPERM; |
2438 | 2413 | if (isdir) { |
2439 | - if (!S_ISDIR(victim->d_inode->i_mode)) | |
2414 | + if (!d_is_directory(victim) && !d_is_autodir(victim)) | |
2440 | 2415 | return -ENOTDIR; |
2441 | 2416 | if (IS_ROOT(victim)) |
2442 | 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 | 2419 | return -EISDIR; |
2445 | 2420 | if (IS_DEADDIR(dir)) |
2446 | 2421 | return -ENOENT; |
... | ... | @@ -2974,7 +2949,7 @@ |
2974 | 2949 | /* |
2975 | 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 | 2953 | audit_inode(name, path->dentry, 0); |
2979 | 2954 | |
2980 | 2955 | /* |
2981 | 2956 | |
... | ... | @@ -3003,12 +2978,12 @@ |
3003 | 2978 | finish_lookup: |
3004 | 2979 | /* we _can_ be in RCU mode here */ |
3005 | 2980 | error = -ENOENT; |
3006 | - if (!inode) { | |
2981 | + if (d_is_negative(path->dentry)) { | |
3007 | 2982 | path_to_nameidata(path, nd); |
3008 | 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 | 2987 | if (nd->flags & LOOKUP_RCU) { |
3013 | 2988 | if (unlikely(unlazy_walk(nd, path->dentry))) { |
3014 | 2989 | error = -ECHILD; |
3015 | 2990 | |
... | ... | @@ -3037,10 +3012,11 @@ |
3037 | 3012 | } |
3038 | 3013 | audit_inode(name, nd->path.dentry, 0); |
3039 | 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 | 3017 | goto out; |
3042 | 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 | 3020 | goto out; |
3045 | 3021 | if (!S_ISREG(nd->inode->i_mode)) |
3046 | 3022 | will_truncate = false; |
... | ... | @@ -3266,7 +3242,7 @@ |
3266 | 3242 | nd.root.mnt = mnt; |
3267 | 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 | 3246 | return ERR_PTR(-ELOOP); |
3271 | 3247 | |
3272 | 3248 | file = path_openat(-1, &filename, &nd, op, flags | LOOKUP_RCU); |
3273 | 3249 | |
... | ... | @@ -3316,8 +3292,9 @@ |
3316 | 3292 | goto unlock; |
3317 | 3293 | |
3318 | 3294 | error = -EEXIST; |
3319 | - if (dentry->d_inode) | |
3295 | + if (d_is_positive(dentry)) | |
3320 | 3296 | goto fail; |
3297 | + | |
3321 | 3298 | /* |
3322 | 3299 | * Special case - lookup gave negative, but... we had foo/bar/ |
3323 | 3300 | * From the vfs_mknod() POV we just have a negative dentry - |
... | ... | @@ -3706,7 +3683,7 @@ |
3706 | 3683 | if (nd.last.name[nd.last.len]) |
3707 | 3684 | goto slashes; |
3708 | 3685 | inode = dentry->d_inode; |
3709 | - if (!inode) | |
3686 | + if (d_is_negative(dentry)) | |
3710 | 3687 | goto slashes; |
3711 | 3688 | ihold(inode); |
3712 | 3689 | error = security_path_unlink(&nd.path, dentry); |
... | ... | @@ -3731,8 +3708,12 @@ |
3731 | 3708 | return error; |
3732 | 3709 | |
3733 | 3710 | slashes: |
3734 | - error = !dentry->d_inode ? -ENOENT : | |
3735 | - S_ISDIR(dentry->d_inode->i_mode) ? -EISDIR : -ENOTDIR; | |
3711 | + if (d_is_negative(dentry)) | |
3712 | + error = -ENOENT; | |
3713 | + else if (d_is_directory(dentry) || d_is_autodir(dentry)) | |
3714 | + error = -EISDIR; | |
3715 | + else | |
3716 | + error = -ENOTDIR; | |
3736 | 3717 | goto exit2; |
3737 | 3718 | } |
3738 | 3719 | |
... | ... | @@ -4046,7 +4027,7 @@ |
4046 | 4027 | struct inode *new_dir, struct dentry *new_dentry) |
4047 | 4028 | { |
4048 | 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 | 4031 | const unsigned char *old_name; |
4051 | 4032 | |
4052 | 4033 | if (old_dentry->d_inode == new_dentry->d_inode) |
4053 | 4034 | |
... | ... | @@ -4134,10 +4115,10 @@ |
4134 | 4115 | goto exit3; |
4135 | 4116 | /* source must exist */ |
4136 | 4117 | error = -ENOENT; |
4137 | - if (!old_dentry->d_inode) | |
4118 | + if (d_is_negative(old_dentry)) | |
4138 | 4119 | goto exit4; |
4139 | 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 | 4122 | error = -ENOTDIR; |
4142 | 4123 | if (oldnd.last.name[oldnd.last.len]) |
4143 | 4124 | goto exit4; |
include/linux/dcache.h
... | ... | @@ -169,13 +169,13 @@ |
169 | 169 | */ |
170 | 170 | |
171 | 171 | /* d_flags entries */ |
172 | -#define DCACHE_OP_HASH 0x0001 | |
173 | -#define DCACHE_OP_COMPARE 0x0002 | |
174 | -#define DCACHE_OP_REVALIDATE 0x0004 | |
175 | -#define DCACHE_OP_DELETE 0x0008 | |
176 | -#define DCACHE_OP_PRUNE 0x0010 | |
172 | +#define DCACHE_OP_HASH 0x00000001 | |
173 | +#define DCACHE_OP_COMPARE 0x00000002 | |
174 | +#define DCACHE_OP_REVALIDATE 0x00000004 | |
175 | +#define DCACHE_OP_DELETE 0x00000008 | |
176 | +#define DCACHE_OP_PRUNE 0x00000010 | |
177 | 177 | |
178 | -#define DCACHE_DISCONNECTED 0x0020 | |
178 | +#define DCACHE_DISCONNECTED 0x00000020 | |
179 | 179 | /* This dentry is possibly not currently connected to the dcache tree, in |
180 | 180 | * which case its parent will either be itself, or will have this flag as |
181 | 181 | * well. nfsd will not use a dentry with this bit set, but will first |
182 | 182 | |
183 | 183 | |
184 | 184 | |
185 | 185 | |
186 | 186 | |
187 | 187 | |
188 | 188 | |
... | ... | @@ -186,31 +186,39 @@ |
186 | 186 | * dentry into place and return that dentry rather than the passed one, |
187 | 187 | * typically using d_splice_alias. */ |
188 | 188 | |
189 | -#define DCACHE_REFERENCED 0x0040 /* Recently used, don't discard. */ | |
190 | -#define DCACHE_RCUACCESS 0x0080 /* Entry has ever been RCU-visible */ | |
189 | +#define DCACHE_REFERENCED 0x00000040 /* Recently used, don't discard. */ | |
190 | +#define DCACHE_RCUACCESS 0x00000080 /* Entry has ever been RCU-visible */ | |
191 | 191 | |
192 | -#define DCACHE_CANT_MOUNT 0x0100 | |
193 | -#define DCACHE_GENOCIDE 0x0200 | |
194 | -#define DCACHE_SHRINK_LIST 0x0400 | |
192 | +#define DCACHE_CANT_MOUNT 0x00000100 | |
193 | +#define DCACHE_GENOCIDE 0x00000200 | |
194 | +#define DCACHE_SHRINK_LIST 0x00000400 | |
195 | 195 | |
196 | -#define DCACHE_OP_WEAK_REVALIDATE 0x0800 | |
196 | +#define DCACHE_OP_WEAK_REVALIDATE 0x00000800 | |
197 | 197 | |
198 | -#define DCACHE_NFSFS_RENAMED 0x1000 | |
198 | +#define DCACHE_NFSFS_RENAMED 0x00001000 | |
199 | 199 | /* this dentry has been "silly renamed" and has to be deleted on the last |
200 | 200 | * dput() */ |
201 | -#define DCACHE_COOKIE 0x2000 /* For use by dcookie subsystem */ | |
202 | -#define DCACHE_FSNOTIFY_PARENT_WATCHED 0x4000 | |
201 | +#define DCACHE_COOKIE 0x00002000 /* For use by dcookie subsystem */ | |
202 | +#define DCACHE_FSNOTIFY_PARENT_WATCHED 0x00004000 | |
203 | 203 | /* Parent inode is watched by some fsnotify listener */ |
204 | 204 | |
205 | -#define DCACHE_MOUNTED 0x10000 /* is a mountpoint */ | |
206 | -#define DCACHE_NEED_AUTOMOUNT 0x20000 /* handle automount on this dir */ | |
207 | -#define DCACHE_MANAGE_TRANSIT 0x40000 /* manage transit from this dirent */ | |
205 | +#define DCACHE_DENTRY_KILLED 0x00008000 | |
206 | + | |
207 | +#define DCACHE_MOUNTED 0x00010000 /* is a mountpoint */ | |
208 | +#define DCACHE_NEED_AUTOMOUNT 0x00020000 /* handle automount on this dir */ | |
209 | +#define DCACHE_MANAGE_TRANSIT 0x00040000 /* manage transit from this dirent */ | |
208 | 210 | #define DCACHE_MANAGED_DENTRY \ |
209 | 211 | (DCACHE_MOUNTED|DCACHE_NEED_AUTOMOUNT|DCACHE_MANAGE_TRANSIT) |
210 | 212 | |
211 | -#define DCACHE_LRU_LIST 0x80000 | |
212 | -#define DCACHE_DENTRY_KILLED 0x100000 | |
213 | +#define DCACHE_LRU_LIST 0x00080000 | |
213 | 214 | |
215 | +#define DCACHE_ENTRY_TYPE 0x00700000 | |
216 | +#define DCACHE_MISS_TYPE 0x00000000 /* Negative dentry */ | |
217 | +#define DCACHE_DIRECTORY_TYPE 0x00100000 /* Normal directory */ | |
218 | +#define DCACHE_AUTODIR_TYPE 0x00200000 /* Lookupless directory (presumed automount) */ | |
219 | +#define DCACHE_SYMLINK_TYPE 0x00300000 /* Symlink */ | |
220 | +#define DCACHE_FILE_TYPE 0x00400000 /* Other file type */ | |
221 | + | |
214 | 222 | extern seqlock_t rename_lock; |
215 | 223 | |
216 | 224 | static inline int dname_external(const struct dentry *dentry) |
... | ... | @@ -392,6 +400,61 @@ |
392 | 400 | static inline bool d_mountpoint(const struct dentry *dentry) |
393 | 401 | { |
394 | 402 | return dentry->d_flags & DCACHE_MOUNTED; |
403 | +} | |
404 | + | |
405 | +/* | |
406 | + * Directory cache entry type accessor functions. | |
407 | + */ | |
408 | +static inline void __d_set_type(struct dentry *dentry, unsigned type) | |
409 | +{ | |
410 | + dentry->d_flags = (dentry->d_flags & ~DCACHE_ENTRY_TYPE) | type; | |
411 | +} | |
412 | + | |
413 | +static inline void __d_clear_type(struct dentry *dentry) | |
414 | +{ | |
415 | + __d_set_type(dentry, DCACHE_MISS_TYPE); | |
416 | +} | |
417 | + | |
418 | +static inline void d_set_type(struct dentry *dentry, unsigned type) | |
419 | +{ | |
420 | + spin_lock(&dentry->d_lock); | |
421 | + __d_set_type(dentry, type); | |
422 | + spin_unlock(&dentry->d_lock); | |
423 | +} | |
424 | + | |
425 | +static inline unsigned __d_entry_type(const struct dentry *dentry) | |
426 | +{ | |
427 | + return dentry->d_flags & DCACHE_ENTRY_TYPE; | |
428 | +} | |
429 | + | |
430 | +static inline bool d_is_directory(const struct dentry *dentry) | |
431 | +{ | |
432 | + return __d_entry_type(dentry) == DCACHE_DIRECTORY_TYPE; | |
433 | +} | |
434 | + | |
435 | +static inline bool d_is_autodir(const struct dentry *dentry) | |
436 | +{ | |
437 | + return __d_entry_type(dentry) == DCACHE_AUTODIR_TYPE; | |
438 | +} | |
439 | + | |
440 | +static inline bool d_is_symlink(const struct dentry *dentry) | |
441 | +{ | |
442 | + return __d_entry_type(dentry) == DCACHE_SYMLINK_TYPE; | |
443 | +} | |
444 | + | |
445 | +static inline bool d_is_file(const struct dentry *dentry) | |
446 | +{ | |
447 | + return __d_entry_type(dentry) == DCACHE_FILE_TYPE; | |
448 | +} | |
449 | + | |
450 | +static inline bool d_is_negative(const struct dentry *dentry) | |
451 | +{ | |
452 | + return __d_entry_type(dentry) == DCACHE_MISS_TYPE; | |
453 | +} | |
454 | + | |
455 | +static inline bool d_is_positive(const struct dentry *dentry) | |
456 | +{ | |
457 | + return !d_is_negative(dentry); | |
395 | 458 | } |
396 | 459 | |
397 | 460 | extern int sysctl_vfs_cache_pressure; |