aboutsummaryrefslogtreecommitdiff
path: root/fs/dcache.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-02-26 20:16:07 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2013-02-26 20:16:07 -0800
commitd895cb1af15c04c522a25c79cc429076987c089b (patch)
tree895dc9157e28f603d937a58be664e4e440d5530c /fs/dcache.c
parent9626357371b519f2b955fef399647181034a77fe (diff)
parentd3d009cb965eae7e002ea5badf603ea8f4c34915 (diff)
downloadlinaro-lsk-d895cb1af15c04c522a25c79cc429076987c089b.tar.gz
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull vfs pile (part one) from Al Viro: "Assorted stuff - cleaning namei.c up a bit, fixing ->d_name/->d_parent locking violations, etc. The most visible changes here are death of FS_REVAL_DOT (replaced with "has ->d_weak_revalidate()") and a new helper getting from struct file to inode. Some bits of preparation to xattr method interface changes. Misc patches by various people sent this cycle *and* ocfs2 fixes from several cycles ago that should've been upstream right then. PS: the next vfs pile will be xattr stuff." * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: (46 commits) saner proc_get_inode() calling conventions proc: avoid extra pde_put() in proc_fill_super() fs: change return values from -EACCES to -EPERM fs/exec.c: make bprm_mm_init() static ocfs2/dlm: use GFP_ATOMIC inside a spin_lock ocfs2: fix possible use-after-free with AIO ocfs2: Fix oops in ocfs2_fast_symlink_readpage() code path get_empty_filp()/alloc_file() leave both ->f_pos and ->f_version zero target: writev() on single-element vector is pointless export kernel_write(), convert open-coded instances fs: encode_fh: return FILEID_INVALID if invalid fid_type kill f_vfsmnt vfs: kill FS_REVAL_DOT by adding a d_weak_revalidate dentry op nfsd: handle vfs_getattr errors in acl protocol switch vfs_getattr() to struct path default SET_PERSONALITY() in linux/elf.h ceph: prepopulate inodes only when request is aborted d_hash_and_lookup(): export, switch open-coded instances 9p: switch v9fs_set_create_acl() to inode+fid, do it before d_instantiate() 9p: split dropping the acls from v9fs_set_create_acl() ...
Diffstat (limited to 'fs/dcache.c')
-rw-r--r--fs/dcache.c80
1 files changed, 21 insertions, 59 deletions
diff --git a/fs/dcache.c b/fs/dcache.c
index 19153a0a810..68220dd0c13 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)
WARN_ON_ONCE(dentry->d_flags & (DCACHE_OP_HASH |
DCACHE_OP_COMPARE |
DCACHE_OP_REVALIDATE |
+ DCACHE_OP_WEAK_REVALIDATE |
DCACHE_OP_DELETE ));
dentry->d_op = op;
if (!op)
@@ -1368,6 +1369,8 @@ void d_set_d_op(struct dentry *dentry, const struct dentry_operations *op)
dentry->d_flags |= DCACHE_OP_COMPARE;
if (op->d_revalidate)
dentry->d_flags |= DCACHE_OP_REVALIDATE;
+ if (op->d_weak_revalidate)
+ dentry->d_flags |= DCACHE_OP_WEAK_REVALIDATE;
if (op->d_delete)
dentry->d_flags |= DCACHE_OP_DELETE;
if (op->d_prune)
@@ -1672,7 +1675,6 @@ EXPORT_SYMBOL(d_splice_alias);
struct dentry *d_add_ci(struct dentry *dentry, struct inode *inode,
struct qstr *name)
{
- int error;
struct dentry *found;
struct dentry *new;
@@ -1681,10 +1683,12 @@ struct dentry *d_add_ci(struct dentry *dentry, struct inode *inode,
* if not go ahead and create it now.
*/
found = d_hash_and_lookup(dentry->d_parent, name);
+ if (unlikely(IS_ERR(found)))
+ goto err_out;
if (!found) {
new = d_alloc(dentry->d_parent, name);
if (!new) {
- error = -ENOMEM;
+ found = ERR_PTR(-ENOMEM);
goto err_out;
}
@@ -1725,7 +1729,7 @@ struct dentry *d_add_ci(struct dentry *dentry, struct inode *inode,
err_out:
iput(inode);
- return ERR_PTR(error);
+ return found;
}
EXPORT_SYMBOL(d_add_ci);
@@ -1889,7 +1893,7 @@ seqretry:
* dentry is returned. The caller must use dput to free the entry when it has
* finished using it. %NULL is returned if the dentry does not exist.
*/
-struct dentry *d_lookup(struct dentry *parent, struct qstr *name)
+struct dentry *d_lookup(const struct dentry *parent, const struct qstr *name)
{
struct dentry *dentry;
unsigned seq;
@@ -1919,7 +1923,7 @@ EXPORT_SYMBOL(d_lookup);
*
* __d_lookup callers must be commented.
*/
-struct dentry *__d_lookup(struct dentry *parent, struct qstr *name)
+struct dentry *__d_lookup(const struct dentry *parent, const struct qstr *name)
{
unsigned int len = name->len;
unsigned int hash = name->hash;
@@ -1997,12 +2001,10 @@ next:
* @dir: Directory to search in
* @name: qstr of name we wish to find
*
- * On hash failure or on lookup failure NULL is returned.
+ * On lookup failure NULL is returned; on bad name - ERR_PTR(-error)
*/
struct dentry *d_hash_and_lookup(struct dentry *dir, struct qstr *name)
{
- struct dentry *dentry = NULL;
-
/*
* Check for a fs-specific hash function. Note that we must
* 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)
*/
name->hash = full_name_hash(name->name, name->len);
if (dir->d_flags & DCACHE_OP_HASH) {
- if (dir->d_op->d_hash(dir, dir->d_inode, name) < 0)
- goto out;
+ int err = dir->d_op->d_hash(dir, dir->d_inode, name);
+ if (unlikely(err < 0))
+ return ERR_PTR(err);
}
- dentry = d_lookup(dir, name);
-out:
- return dentry;
+ return d_lookup(dir, name);
}
+EXPORT_SYMBOL(d_hash_and_lookup);
/**
* d_validate - verify dentry provided from insecure source (deprecated)
@@ -2394,7 +2396,7 @@ out_err:
*/
static void __d_materialise_dentry(struct dentry *dentry, struct dentry *anon)
{
- struct dentry *dparent, *aparent;
+ struct dentry *dparent;
dentry_lock_for_move(anon, dentry);
@@ -2402,24 +2404,15 @@ static void __d_materialise_dentry(struct dentry *dentry, struct dentry *anon)
write_seqcount_begin(&anon->d_seq);
dparent = dentry->d_parent;
- aparent = anon->d_parent;
switch_names(dentry, anon);
swap(dentry->d_name.hash, anon->d_name.hash);
- dentry->d_parent = (aparent == anon) ? dentry : aparent;
- list_del(&dentry->d_u.d_child);
- if (!IS_ROOT(dentry))
- list_add(&dentry->d_u.d_child, &dentry->d_parent->d_subdirs);
- else
- INIT_LIST_HEAD(&dentry->d_u.d_child);
-
- anon->d_parent = (dparent == dentry) ? anon : dparent;
+ dentry->d_parent = dentry;
+ list_del_init(&dentry->d_u.d_child);
+ anon->d_parent = dparent;
list_del(&anon->d_u.d_child);
- if (!IS_ROOT(anon))
- list_add(&anon->d_u.d_child, &anon->d_parent->d_subdirs);
- else
- INIT_LIST_HEAD(&anon->d_u.d_child);
+ list_add(&anon->d_u.d_child, &dparent->d_subdirs);
write_seqcount_end(&dentry->d_seq);
write_seqcount_end(&anon->d_seq);
@@ -2722,37 +2715,6 @@ char *d_path(const struct path *path, char *buf, int buflen)
}
EXPORT_SYMBOL(d_path);
-/**
- * d_path_with_unreachable - return the path of a dentry
- * @path: path to report
- * @buf: buffer to return value in
- * @buflen: buffer length
- *
- * The difference from d_path() is that this prepends "(unreachable)"
- * to paths which are unreachable from the current process' root.
- */
-char *d_path_with_unreachable(const struct path *path, char *buf, int buflen)
-{
- char *res = buf + buflen;
- struct path root;
- int error;
-
- if (path->dentry->d_op && path->dentry->d_op->d_dname)
- return path->dentry->d_op->d_dname(path->dentry, buf, buflen);
-
- get_fs_root(current->fs, &root);
- write_seqlock(&rename_lock);
- error = path_with_deleted(path, &root, &res, &buflen);
- if (error > 0)
- error = prepend_unreachable(&res, &buflen);
- write_sequnlock(&rename_lock);
- path_put(&root);
- if (error)
- res = ERR_PTR(error);
-
- return res;
-}
-
/*
* Helper function for dentry_operations.d_dname() members
*/
@@ -3035,7 +2997,7 @@ ino_t find_inode_number(struct dentry *dir, struct qstr *name)
ino_t ino = 0;
dentry = d_hash_and_lookup(dir, name);
- if (dentry) {
+ if (!IS_ERR_OR_NULL(dentry)) {
if (dentry->d_inode)
ino = dentry->d_inode->i_ino;
dput(dentry);