diff options
| author | Al Viro <viro@zeniv.linux.org.uk> | 2016-03-08 12:44:17 -0500 |
|---|---|---|
| committer | Al Viro <viro@zeniv.linux.org.uk> | 2016-03-14 00:17:20 -0400 |
| commit | 668d0cd56ef7bc71be6dd8c081007221e09d9a86 (patch) | |
| tree | e4e61bdd16fde1ad932861a23978601c2530f32a | |
| parent | e12a4e8a04a9ef84ba645379c56abad1a0ca9dbd (diff) | |
replace d_add_unique() with saner primitive
new primitive: d_exact_alias(dentry, inode). If there is an unhashed
dentry with the same name/parent and given inode, rehash, grab and
return it. Otherwise, return NULL. The only caller of d_add_unique()
switched to d_exact_alias() + d_splice_alias().
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
| -rw-r--r-- | fs/dcache.c | 125 | ||||
| -rw-r--r-- | fs/nfs/nfs4proc.c | 13 | ||||
| -rw-r--r-- | include/linux/dcache.h | 18 |
3 files changed, 58 insertions, 98 deletions
diff --git a/fs/dcache.c b/fs/dcache.c index 2398f9f94337..4d20bf5c609b 100644 --- a/fs/dcache.c +++ b/fs/dcache.c | |||
| @@ -1782,81 +1782,6 @@ void d_instantiate(struct dentry *entry, struct inode * inode) | |||
| 1782 | EXPORT_SYMBOL(d_instantiate); | 1782 | EXPORT_SYMBOL(d_instantiate); |
| 1783 | 1783 | ||
| 1784 | /** | 1784 | /** |
| 1785 | * d_instantiate_unique - instantiate a non-aliased dentry | ||
| 1786 | * @entry: dentry to instantiate | ||
| 1787 | * @inode: inode to attach to this dentry | ||
| 1788 | * | ||
| 1789 | * Fill in inode information in the entry. On success, it returns NULL. | ||
| 1790 | * If an unhashed alias of "entry" already exists, then we return the | ||
| 1791 | * aliased dentry instead and drop one reference to inode. | ||
| 1792 | * | ||
| 1793 | * Note that in order to avoid conflicts with rename() etc, the caller | ||
| 1794 | * had better be holding the parent directory semaphore. | ||
| 1795 | * | ||
| 1796 | * This also assumes that the inode count has been incremented | ||
| 1797 | * (or otherwise set) by the caller to indicate that it is now | ||
| 1798 | * in use by the dcache. | ||
| 1799 | */ | ||
| 1800 | static struct dentry *__d_instantiate_unique(struct dentry *entry, | ||
| 1801 | struct inode *inode) | ||
| 1802 | { | ||
| 1803 | struct dentry *alias; | ||
| 1804 | int len = entry->d_name.len; | ||
| 1805 | const char *name = entry->d_name.name; | ||
| 1806 | unsigned int hash = entry->d_name.hash; | ||
| 1807 | |||
| 1808 | if (!inode) { | ||
| 1809 | __d_instantiate(entry, NULL); | ||
| 1810 | return NULL; | ||
| 1811 | } | ||
| 1812 | |||
| 1813 | hlist_for_each_entry(alias, &inode->i_dentry, d_u.d_alias) { | ||
| 1814 | /* | ||
| 1815 | * Don't need alias->d_lock here, because aliases with | ||
| 1816 | * d_parent == entry->d_parent are not subject to name or | ||
| 1817 | * parent changes, because the parent inode i_mutex is held. | ||
| 1818 | */ | ||
| 1819 | if (alias->d_name.hash != hash) | ||
| 1820 | continue; | ||
| 1821 | if (alias->d_parent != entry->d_parent) | ||
| 1822 | continue; | ||
| 1823 | if (alias->d_name.len != len) | ||
| 1824 | continue; | ||
| 1825 | if (dentry_cmp(alias, name, len)) | ||
| 1826 | continue; | ||
| 1827 | __dget(alias); | ||
| 1828 | return alias; | ||
| 1829 | } | ||
| 1830 | |||
| 1831 | __d_instantiate(entry, inode); | ||
| 1832 | return NULL; | ||
| 1833 | } | ||
| 1834 | |||
| 1835 | struct dentry *d_instantiate_unique(struct dentry *entry, struct inode *inode) | ||
| 1836 | { | ||
| 1837 | struct dentry *result; | ||
| 1838 | |||
| 1839 | BUG_ON(!hlist_unhashed(&entry->d_u.d_alias)); | ||
| 1840 | |||
| 1841 | if (inode) | ||
| 1842 | spin_lock(&inode->i_lock); | ||
| 1843 | result = __d_instantiate_unique(entry, inode); | ||
| 1844 | if (inode) | ||
| 1845 | spin_unlock(&inode->i_lock); | ||
| 1846 | |||
| 1847 | if (!result) { | ||
| 1848 | security_d_instantiate(entry, inode); | ||
| 1849 | return NULL; | ||
| 1850 | } | ||
| 1851 | |||
| 1852 | BUG_ON(!d_unhashed(result)); | ||
| 1853 | iput(inode); | ||
| 1854 | return result; | ||
| 1855 | } | ||
| 1856 | |||
| 1857 | EXPORT_SYMBOL(d_instantiate_unique); | ||
| 1858 | |||
| 1859 | /** | ||
| 1860 | * d_instantiate_no_diralias - instantiate a non-aliased dentry | 1785 | * d_instantiate_no_diralias - instantiate a non-aliased dentry |
| 1861 | * @entry: dentry to complete | 1786 | * @entry: dentry to complete |
| 1862 | * @inode: inode to attach to this dentry | 1787 | * @inode: inode to attach to this dentry |
| @@ -2437,6 +2362,56 @@ void d_rehash(struct dentry * entry) | |||
| 2437 | EXPORT_SYMBOL(d_rehash); | 2362 | EXPORT_SYMBOL(d_rehash); |
| 2438 | 2363 | ||
| 2439 | /** | 2364 | /** |
| 2365 | * d_exact_alias - find and hash an exact unhashed alias | ||
| 2366 | * @entry: dentry to add | ||
| 2367 | * @inode: The inode to go with this dentry | ||
| 2368 | * | ||
| 2369 | * If an unhashed dentry with the same name/parent and desired | ||
| 2370 | * inode already exists, hash and return it. Otherwise, return | ||
| 2371 | * NULL. | ||
| 2372 | * | ||
| 2373 | * Parent directory should be locked. | ||
| 2374 | */ | ||
| 2375 | struct dentry *d_exact_alias(struct dentry *entry, struct inode *inode) | ||
| 2376 | { | ||
| 2377 | struct dentry *alias; | ||
| 2378 | int len = entry->d_name.len; | ||
| 2379 | const char *name = entry->d_name.name; | ||
| 2380 | unsigned int hash = entry->d_name.hash; | ||
| 2381 | |||
| 2382 | spin_lock(&inode->i_lock); | ||
| 2383 | hlist_for_each_entry(alias, &inode->i_dentry, d_u.d_alias) { | ||
| 2384 | /* | ||
| 2385 | * Don't need alias->d_lock here, because aliases with | ||
| 2386 | * d_parent == entry->d_parent are not subject to name or | ||
| 2387 | * parent changes, because the parent inode i_mutex is held. | ||
| 2388 | */ | ||
| 2389 | if (alias->d_name.hash != hash) | ||
| 2390 | continue; | ||
| 2391 | if (alias->d_parent != entry->d_parent) | ||
| 2392 | continue; | ||
| 2393 | if (alias->d_name.len != len) | ||
| 2394 | continue; | ||
| 2395 | if (dentry_cmp(alias, name, len)) | ||
| 2396 | continue; | ||
| 2397 | spin_lock(&alias->d_lock); | ||
| 2398 | if (!d_unhashed(alias)) { | ||
| 2399 | spin_unlock(&alias->d_lock); | ||
| 2400 | alias = NULL; | ||
| 2401 | } else { | ||
| 2402 | __dget_dlock(alias); | ||
| 2403 | _d_rehash(alias); | ||
| 2404 | spin_unlock(&alias->d_lock); | ||
| 2405 | } | ||
| 2406 | spin_unlock(&inode->i_lock); | ||
| 2407 | return alias; | ||
| 2408 | } | ||
| 2409 | spin_unlock(&inode->i_lock); | ||
| 2410 | return NULL; | ||
| 2411 | } | ||
| 2412 | EXPORT_SYMBOL(d_exact_alias); | ||
| 2413 | |||
| 2414 | /** | ||
| 2440 | * dentry_update_name_case - update case insensitive dentry with a new name | 2415 | * dentry_update_name_case - update case insensitive dentry with a new name |
| 2441 | * @dentry: dentry to be updated | 2416 | * @dentry: dentry to be updated |
| 2442 | * @name: new name | 2417 | * @name: new name |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 4bfc33ad0563..400a70b3be7b 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
| @@ -2461,14 +2461,15 @@ static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata, | |||
| 2461 | 2461 | ||
| 2462 | dentry = opendata->dentry; | 2462 | dentry = opendata->dentry; |
| 2463 | if (d_really_is_negative(dentry)) { | 2463 | if (d_really_is_negative(dentry)) { |
| 2464 | /* FIXME: Is this d_drop() ever needed? */ | 2464 | struct dentry *alias; |
| 2465 | d_drop(dentry); | 2465 | d_drop(dentry); |
| 2466 | dentry = d_add_unique(dentry, igrab(state->inode)); | 2466 | alias = d_exact_alias(dentry, state->inode); |
| 2467 | if (dentry == NULL) { | 2467 | if (!alias) |
| 2468 | dentry = opendata->dentry; | 2468 | alias = d_splice_alias(igrab(state->inode), dentry); |
| 2469 | } else if (dentry != ctx->dentry) { | 2469 | /* d_splice_alias() can't fail here - it's a non-directory */ |
| 2470 | if (alias) { | ||
| 2470 | dput(ctx->dentry); | 2471 | dput(ctx->dentry); |
| 2471 | ctx->dentry = dget(dentry); | 2472 | ctx->dentry = dentry = alias; |
| 2472 | } | 2473 | } |
| 2473 | nfs_set_verifier(dentry, | 2474 | nfs_set_verifier(dentry, |
| 2474 | nfs_save_change_attribute(d_inode(opendata->dir))); | 2475 | nfs_save_change_attribute(d_inode(opendata->dir))); |
diff --git a/include/linux/dcache.h b/include/linux/dcache.h index c4b5f4b3f8f8..bda4ec53886b 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h | |||
| @@ -246,6 +246,7 @@ extern struct dentry * d_alloc(struct dentry *, const struct qstr *); | |||
| 246 | extern struct dentry * d_alloc_pseudo(struct super_block *, const struct qstr *); | 246 | extern struct dentry * d_alloc_pseudo(struct super_block *, const struct qstr *); |
| 247 | extern struct dentry * d_splice_alias(struct inode *, struct dentry *); | 247 | extern struct dentry * d_splice_alias(struct inode *, struct dentry *); |
| 248 | extern struct dentry * d_add_ci(struct dentry *, struct inode *, struct qstr *); | 248 | extern struct dentry * d_add_ci(struct dentry *, struct inode *, struct qstr *); |
| 249 | extern struct dentry * d_exact_alias(struct dentry *, struct inode *); | ||
| 249 | extern struct dentry *d_find_any_alias(struct inode *inode); | 250 | extern struct dentry *d_find_any_alias(struct inode *inode); |
| 250 | extern struct dentry * d_obtain_alias(struct inode *); | 251 | extern struct dentry * d_obtain_alias(struct inode *); |
| 251 | extern struct dentry * d_obtain_root(struct inode *); | 252 | extern struct dentry * d_obtain_root(struct inode *); |
| @@ -288,23 +289,6 @@ static inline void d_add(struct dentry *entry, struct inode *inode) | |||
| 288 | d_rehash(entry); | 289 | d_rehash(entry); |
| 289 | } | 290 | } |
| 290 | 291 | ||
| 291 | /** | ||
| 292 | * d_add_unique - add dentry to hash queues without aliasing | ||
| 293 | * @entry: dentry to add | ||
| 294 | * @inode: The inode to attach to this dentry | ||
| 295 | * | ||
| 296 | * This adds the entry to the hash queues and initializes @inode. | ||
| 297 | * The entry was actually filled in earlier during d_alloc(). | ||
| 298 | */ | ||
| 299 | static inline struct dentry *d_add_unique(struct dentry *entry, struct inode *inode) | ||
| 300 | { | ||
| 301 | struct dentry *res; | ||
| 302 | |||
| 303 | res = d_instantiate_unique(entry, inode); | ||
| 304 | d_rehash(res != NULL ? res : entry); | ||
| 305 | return res; | ||
| 306 | } | ||
| 307 | |||
| 308 | extern void dentry_update_name_case(struct dentry *, struct qstr *); | 292 | extern void dentry_update_name_case(struct dentry *, struct qstr *); |
| 309 | 293 | ||
| 310 | /* used for rename() and baskets */ | 294 | /* used for rename() and baskets */ |
