diff options
Diffstat (limited to 'fs/dcache.c')
-rw-r--r-- | fs/dcache.c | 80 |
1 files changed, 21 insertions, 59 deletions
diff --git a/fs/dcache.c b/fs/dcache.c index 19153a0a810c..68220dd0c135 100644 --- a/fs/dcache.c +++ b/fs/dcache.c | |||
@@ -1358,6 +1358,7 @@ void d_set_d_op(struct dentry *dentry, const struct dentry_operations *op) | |||
1358 | WARN_ON_ONCE(dentry->d_flags & (DCACHE_OP_HASH | | 1358 | WARN_ON_ONCE(dentry->d_flags & (DCACHE_OP_HASH | |
1359 | DCACHE_OP_COMPARE | | 1359 | DCACHE_OP_COMPARE | |
1360 | DCACHE_OP_REVALIDATE | | 1360 | DCACHE_OP_REVALIDATE | |
1361 | DCACHE_OP_WEAK_REVALIDATE | | ||
1361 | DCACHE_OP_DELETE )); | 1362 | DCACHE_OP_DELETE )); |
1362 | dentry->d_op = op; | 1363 | dentry->d_op = op; |
1363 | if (!op) | 1364 | if (!op) |
@@ -1368,6 +1369,8 @@ void d_set_d_op(struct dentry *dentry, const struct dentry_operations *op) | |||
1368 | dentry->d_flags |= DCACHE_OP_COMPARE; | 1369 | dentry->d_flags |= DCACHE_OP_COMPARE; |
1369 | if (op->d_revalidate) | 1370 | if (op->d_revalidate) |
1370 | dentry->d_flags |= DCACHE_OP_REVALIDATE; | 1371 | dentry->d_flags |= DCACHE_OP_REVALIDATE; |
1372 | if (op->d_weak_revalidate) | ||
1373 | dentry->d_flags |= DCACHE_OP_WEAK_REVALIDATE; | ||
1371 | if (op->d_delete) | 1374 | if (op->d_delete) |
1372 | dentry->d_flags |= DCACHE_OP_DELETE; | 1375 | dentry->d_flags |= DCACHE_OP_DELETE; |
1373 | if (op->d_prune) | 1376 | if (op->d_prune) |
@@ -1672,7 +1675,6 @@ EXPORT_SYMBOL(d_splice_alias); | |||
1672 | struct dentry *d_add_ci(struct dentry *dentry, struct inode *inode, | 1675 | struct dentry *d_add_ci(struct dentry *dentry, struct inode *inode, |
1673 | struct qstr *name) | 1676 | struct qstr *name) |
1674 | { | 1677 | { |
1675 | int error; | ||
1676 | struct dentry *found; | 1678 | struct dentry *found; |
1677 | struct dentry *new; | 1679 | struct dentry *new; |
1678 | 1680 | ||
@@ -1681,10 +1683,12 @@ struct dentry *d_add_ci(struct dentry *dentry, struct inode *inode, | |||
1681 | * if not go ahead and create it now. | 1683 | * if not go ahead and create it now. |
1682 | */ | 1684 | */ |
1683 | found = d_hash_and_lookup(dentry->d_parent, name); | 1685 | found = d_hash_and_lookup(dentry->d_parent, name); |
1686 | if (unlikely(IS_ERR(found))) | ||
1687 | goto err_out; | ||
1684 | if (!found) { | 1688 | if (!found) { |
1685 | new = d_alloc(dentry->d_parent, name); | 1689 | new = d_alloc(dentry->d_parent, name); |
1686 | if (!new) { | 1690 | if (!new) { |
1687 | error = -ENOMEM; | 1691 | found = ERR_PTR(-ENOMEM); |
1688 | goto err_out; | 1692 | goto err_out; |
1689 | } | 1693 | } |
1690 | 1694 | ||
@@ -1725,7 +1729,7 @@ struct dentry *d_add_ci(struct dentry *dentry, struct inode *inode, | |||
1725 | 1729 | ||
1726 | err_out: | 1730 | err_out: |
1727 | iput(inode); | 1731 | iput(inode); |
1728 | return ERR_PTR(error); | 1732 | return found; |
1729 | } | 1733 | } |
1730 | EXPORT_SYMBOL(d_add_ci); | 1734 | EXPORT_SYMBOL(d_add_ci); |
1731 | 1735 | ||
@@ -1889,7 +1893,7 @@ seqretry: | |||
1889 | * dentry is returned. The caller must use dput to free the entry when it has | 1893 | * dentry is returned. The caller must use dput to free the entry when it has |
1890 | * finished using it. %NULL is returned if the dentry does not exist. | 1894 | * finished using it. %NULL is returned if the dentry does not exist. |
1891 | */ | 1895 | */ |
1892 | struct dentry *d_lookup(struct dentry *parent, struct qstr *name) | 1896 | struct dentry *d_lookup(const struct dentry *parent, const struct qstr *name) |
1893 | { | 1897 | { |
1894 | struct dentry *dentry; | 1898 | struct dentry *dentry; |
1895 | unsigned seq; | 1899 | unsigned seq; |
@@ -1919,7 +1923,7 @@ EXPORT_SYMBOL(d_lookup); | |||
1919 | * | 1923 | * |
1920 | * __d_lookup callers must be commented. | 1924 | * __d_lookup callers must be commented. |
1921 | */ | 1925 | */ |
1922 | struct dentry *__d_lookup(struct dentry *parent, struct qstr *name) | 1926 | struct dentry *__d_lookup(const struct dentry *parent, const struct qstr *name) |
1923 | { | 1927 | { |
1924 | unsigned int len = name->len; | 1928 | unsigned int len = name->len; |
1925 | unsigned int hash = name->hash; | 1929 | unsigned int hash = name->hash; |
@@ -1997,12 +2001,10 @@ next: | |||
1997 | * @dir: Directory to search in | 2001 | * @dir: Directory to search in |
1998 | * @name: qstr of name we wish to find | 2002 | * @name: qstr of name we wish to find |
1999 | * | 2003 | * |
2000 | * On hash failure or on lookup failure NULL is returned. | 2004 | * On lookup failure NULL is returned; on bad name - ERR_PTR(-error) |
2001 | */ | 2005 | */ |
2002 | struct dentry *d_hash_and_lookup(struct dentry *dir, struct qstr *name) | 2006 | struct dentry *d_hash_and_lookup(struct dentry *dir, struct qstr *name) |
2003 | { | 2007 | { |
2004 | struct dentry *dentry = NULL; | ||
2005 | |||
2006 | /* | 2008 | /* |
2007 | * Check for a fs-specific hash function. Note that we must | 2009 | * Check for a fs-specific hash function. Note that we must |
2008 | * calculate the standard hash first, as the d_op->d_hash() | 2010 | * calculate the standard hash first, as the d_op->d_hash() |
@@ -2010,13 +2012,13 @@ struct dentry *d_hash_and_lookup(struct dentry *dir, struct qstr *name) | |||
2010 | */ | 2012 | */ |
2011 | name->hash = full_name_hash(name->name, name->len); | 2013 | name->hash = full_name_hash(name->name, name->len); |
2012 | if (dir->d_flags & DCACHE_OP_HASH) { | 2014 | if (dir->d_flags & DCACHE_OP_HASH) { |
2013 | if (dir->d_op->d_hash(dir, dir->d_inode, name) < 0) | 2015 | int err = dir->d_op->d_hash(dir, dir->d_inode, name); |
2014 | goto out; | 2016 | if (unlikely(err < 0)) |
2017 | return ERR_PTR(err); | ||
2015 | } | 2018 | } |
2016 | dentry = d_lookup(dir, name); | 2019 | return d_lookup(dir, name); |
2017 | out: | ||
2018 | return dentry; | ||
2019 | } | 2020 | } |
2021 | EXPORT_SYMBOL(d_hash_and_lookup); | ||
2020 | 2022 | ||
2021 | /** | 2023 | /** |
2022 | * d_validate - verify dentry provided from insecure source (deprecated) | 2024 | * d_validate - verify dentry provided from insecure source (deprecated) |
@@ -2394,7 +2396,7 @@ out_err: | |||
2394 | */ | 2396 | */ |
2395 | static void __d_materialise_dentry(struct dentry *dentry, struct dentry *anon) | 2397 | static void __d_materialise_dentry(struct dentry *dentry, struct dentry *anon) |
2396 | { | 2398 | { |
2397 | struct dentry *dparent, *aparent; | 2399 | struct dentry *dparent; |
2398 | 2400 | ||
2399 | dentry_lock_for_move(anon, dentry); | 2401 | dentry_lock_for_move(anon, dentry); |
2400 | 2402 | ||
@@ -2402,24 +2404,15 @@ static void __d_materialise_dentry(struct dentry *dentry, struct dentry *anon) | |||
2402 | write_seqcount_begin(&anon->d_seq); | 2404 | write_seqcount_begin(&anon->d_seq); |
2403 | 2405 | ||
2404 | dparent = dentry->d_parent; | 2406 | dparent = dentry->d_parent; |
2405 | aparent = anon->d_parent; | ||
2406 | 2407 | ||
2407 | switch_names(dentry, anon); | 2408 | switch_names(dentry, anon); |
2408 | swap(dentry->d_name.hash, anon->d_name.hash); | 2409 | swap(dentry->d_name.hash, anon->d_name.hash); |
2409 | 2410 | ||
2410 | dentry->d_parent = (aparent == anon) ? dentry : aparent; | 2411 | dentry->d_parent = dentry; |
2411 | list_del(&dentry->d_u.d_child); | 2412 | list_del_init(&dentry->d_u.d_child); |
2412 | if (!IS_ROOT(dentry)) | 2413 | anon->d_parent = dparent; |
2413 | list_add(&dentry->d_u.d_child, &dentry->d_parent->d_subdirs); | ||
2414 | else | ||
2415 | INIT_LIST_HEAD(&dentry->d_u.d_child); | ||
2416 | |||
2417 | anon->d_parent = (dparent == dentry) ? anon : dparent; | ||
2418 | list_del(&anon->d_u.d_child); | 2414 | list_del(&anon->d_u.d_child); |
2419 | if (!IS_ROOT(anon)) | 2415 | list_add(&anon->d_u.d_child, &dparent->d_subdirs); |
2420 | list_add(&anon->d_u.d_child, &anon->d_parent->d_subdirs); | ||
2421 | else | ||
2422 | INIT_LIST_HEAD(&anon->d_u.d_child); | ||
2423 | 2416 | ||
2424 | write_seqcount_end(&dentry->d_seq); | 2417 | write_seqcount_end(&dentry->d_seq); |
2425 | write_seqcount_end(&anon->d_seq); | 2418 | write_seqcount_end(&anon->d_seq); |
@@ -2722,37 +2715,6 @@ char *d_path(const struct path *path, char *buf, int buflen) | |||
2722 | } | 2715 | } |
2723 | EXPORT_SYMBOL(d_path); | 2716 | EXPORT_SYMBOL(d_path); |
2724 | 2717 | ||
2725 | /** | ||
2726 | * d_path_with_unreachable - return the path of a dentry | ||
2727 | * @path: path to report | ||
2728 | * @buf: buffer to return value in | ||
2729 | * @buflen: buffer length | ||
2730 | * | ||
2731 | * The difference from d_path() is that this prepends "(unreachable)" | ||
2732 | * to paths which are unreachable from the current process' root. | ||
2733 | */ | ||
2734 | char *d_path_with_unreachable(const struct path *path, char *buf, int buflen) | ||
2735 | { | ||
2736 | char *res = buf + buflen; | ||
2737 | struct path root; | ||
2738 | int error; | ||
2739 | |||
2740 | if (path->dentry->d_op && path->dentry->d_op->d_dname) | ||
2741 | return path->dentry->d_op->d_dname(path->dentry, buf, buflen); | ||
2742 | |||
2743 | get_fs_root(current->fs, &root); | ||
2744 | write_seqlock(&rename_lock); | ||
2745 | error = path_with_deleted(path, &root, &res, &buflen); | ||
2746 | if (error > 0) | ||
2747 | error = prepend_unreachable(&res, &buflen); | ||
2748 | write_sequnlock(&rename_lock); | ||
2749 | path_put(&root); | ||
2750 | if (error) | ||
2751 | res = ERR_PTR(error); | ||
2752 | |||
2753 | return res; | ||
2754 | } | ||
2755 | |||
2756 | /* | 2718 | /* |
2757 | * Helper function for dentry_operations.d_dname() members | 2719 | * Helper function for dentry_operations.d_dname() members |
2758 | */ | 2720 | */ |
@@ -3035,7 +2997,7 @@ ino_t find_inode_number(struct dentry *dir, struct qstr *name) | |||
3035 | ino_t ino = 0; | 2997 | ino_t ino = 0; |
3036 | 2998 | ||
3037 | dentry = d_hash_and_lookup(dir, name); | 2999 | dentry = d_hash_and_lookup(dir, name); |
3038 | if (dentry) { | 3000 | if (!IS_ERR_OR_NULL(dentry)) { |
3039 | if (dentry->d_inode) | 3001 | if (dentry->d_inode) |
3040 | ino = dentry->d_inode->i_ino; | 3002 | ino = dentry->d_inode->i_ino; |
3041 | dput(dentry); | 3003 | dput(dentry); |