Commit 08d27eb2 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs

Pull vfs fixes from Al Viro.

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
  posix_acl: de-union a_refcount and a_rcu
  nfs_atomic_open(): prevent parallel nfs_lookup() on a negative hashed
  Use the right predicate in ->atomic_open() instances
parents 92d21ac7 6d4e56ce
...@@ -853,7 +853,7 @@ v9fs_vfs_atomic_open(struct inode *dir, struct dentry *dentry, ...@@ -853,7 +853,7 @@ v9fs_vfs_atomic_open(struct inode *dir, struct dentry *dentry,
struct p9_fid *fid, *inode_fid; struct p9_fid *fid, *inode_fid;
struct dentry *res = NULL; struct dentry *res = NULL;
if (d_unhashed(dentry)) { if (d_in_lookup(dentry)) {
res = v9fs_vfs_lookup(dir, dentry, 0); res = v9fs_vfs_lookup(dir, dentry, 0);
if (IS_ERR(res)) if (IS_ERR(res))
return PTR_ERR(res); return PTR_ERR(res);
......
...@@ -254,7 +254,7 @@ v9fs_vfs_atomic_open_dotl(struct inode *dir, struct dentry *dentry, ...@@ -254,7 +254,7 @@ v9fs_vfs_atomic_open_dotl(struct inode *dir, struct dentry *dentry,
struct posix_acl *pacl = NULL, *dacl = NULL; struct posix_acl *pacl = NULL, *dacl = NULL;
struct dentry *res = NULL; struct dentry *res = NULL;
if (d_unhashed(dentry)) { if (d_in_lookup(dentry)) {
res = v9fs_vfs_lookup(dir, dentry, 0); res = v9fs_vfs_lookup(dir, dentry, 0);
if (IS_ERR(res)) if (IS_ERR(res))
return PTR_ERR(res); return PTR_ERR(res);
......
...@@ -394,7 +394,7 @@ int ceph_atomic_open(struct inode *dir, struct dentry *dentry, ...@@ -394,7 +394,7 @@ int ceph_atomic_open(struct inode *dir, struct dentry *dentry,
if ((flags & O_CREAT) && !req->r_reply_info.head->is_dentry) if ((flags & O_CREAT) && !req->r_reply_info.head->is_dentry)
err = ceph_handle_notrace_create(dir, dentry); err = ceph_handle_notrace_create(dir, dentry);
if (d_unhashed(dentry)) { if (d_in_lookup(dentry)) {
dn = ceph_finish_lookup(req, dentry, err); dn = ceph_finish_lookup(req, dentry, err);
if (IS_ERR(dn)) if (IS_ERR(dn))
err = PTR_ERR(dn); err = PTR_ERR(dn);
......
...@@ -445,7 +445,7 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry, ...@@ -445,7 +445,7 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry,
* Check for hashed negative dentry. We have already revalidated * Check for hashed negative dentry. We have already revalidated
* the dentry and it is fine. No need to perform another lookup. * the dentry and it is fine. No need to perform another lookup.
*/ */
if (!d_unhashed(direntry)) if (!d_in_lookup(direntry))
return -ENOENT; return -ENOENT;
res = cifs_lookup(inode, direntry, 0); res = cifs_lookup(inode, direntry, 0);
......
...@@ -480,7 +480,7 @@ static int fuse_atomic_open(struct inode *dir, struct dentry *entry, ...@@ -480,7 +480,7 @@ static int fuse_atomic_open(struct inode *dir, struct dentry *entry,
struct fuse_conn *fc = get_fuse_conn(dir); struct fuse_conn *fc = get_fuse_conn(dir);
struct dentry *res = NULL; struct dentry *res = NULL;
if (d_unhashed(entry)) { if (d_in_lookup(entry)) {
res = fuse_lookup(dir, entry, 0); res = fuse_lookup(dir, entry, 0);
if (IS_ERR(res)) if (IS_ERR(res))
return PTR_ERR(res); return PTR_ERR(res);
......
...@@ -1189,7 +1189,7 @@ static int gfs2_atomic_open(struct inode *dir, struct dentry *dentry, ...@@ -1189,7 +1189,7 @@ static int gfs2_atomic_open(struct inode *dir, struct dentry *dentry,
struct dentry *d; struct dentry *d;
bool excl = !!(flags & O_EXCL); bool excl = !!(flags & O_EXCL);
if (!d_unhashed(dentry)) if (!d_in_lookup(dentry))
goto skip_lookup; goto skip_lookup;
d = __gfs2_lookup(dir, dentry, file, opened); d = __gfs2_lookup(dir, dentry, file, opened);
......
...@@ -1485,11 +1485,13 @@ int nfs_atomic_open(struct inode *dir, struct dentry *dentry, ...@@ -1485,11 +1485,13 @@ int nfs_atomic_open(struct inode *dir, struct dentry *dentry,
struct file *file, unsigned open_flags, struct file *file, unsigned open_flags,
umode_t mode, int *opened) umode_t mode, int *opened)
{ {
DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq);
struct nfs_open_context *ctx; struct nfs_open_context *ctx;
struct dentry *res; struct dentry *res;
struct iattr attr = { .ia_valid = ATTR_OPEN }; struct iattr attr = { .ia_valid = ATTR_OPEN };
struct inode *inode; struct inode *inode;
unsigned int lookup_flags = 0; unsigned int lookup_flags = 0;
bool switched = false;
int err; int err;
/* Expect a negative dentry */ /* Expect a negative dentry */
...@@ -1504,7 +1506,7 @@ int nfs_atomic_open(struct inode *dir, struct dentry *dentry, ...@@ -1504,7 +1506,7 @@ int nfs_atomic_open(struct inode *dir, struct dentry *dentry,
/* NFS only supports OPEN on regular files */ /* NFS only supports OPEN on regular files */
if ((open_flags & O_DIRECTORY)) { if ((open_flags & O_DIRECTORY)) {
if (!d_unhashed(dentry)) { if (!d_in_lookup(dentry)) {
/* /*
* Hashed negative dentry with O_DIRECTORY: dentry was * Hashed negative dentry with O_DIRECTORY: dentry was
* revalidated and is fine, no need to perform lookup * revalidated and is fine, no need to perform lookup
...@@ -1528,6 +1530,17 @@ int nfs_atomic_open(struct inode *dir, struct dentry *dentry, ...@@ -1528,6 +1530,17 @@ int nfs_atomic_open(struct inode *dir, struct dentry *dentry,
attr.ia_size = 0; attr.ia_size = 0;
} }
if (!(open_flags & O_CREAT) && !d_in_lookup(dentry)) {
d_drop(dentry);
switched = true;
dentry = d_alloc_parallel(dentry->d_parent,
&dentry->d_name, &wq);
if (IS_ERR(dentry))
return PTR_ERR(dentry);
if (unlikely(!d_in_lookup(dentry)))
return finish_no_open(file, dentry);
}
ctx = create_nfs_open_context(dentry, open_flags); ctx = create_nfs_open_context(dentry, open_flags);
err = PTR_ERR(ctx); err = PTR_ERR(ctx);
if (IS_ERR(ctx)) if (IS_ERR(ctx))
...@@ -1563,14 +1576,23 @@ int nfs_atomic_open(struct inode *dir, struct dentry *dentry, ...@@ -1563,14 +1576,23 @@ int nfs_atomic_open(struct inode *dir, struct dentry *dentry,
trace_nfs_atomic_open_exit(dir, ctx, open_flags, err); trace_nfs_atomic_open_exit(dir, ctx, open_flags, err);
put_nfs_open_context(ctx); put_nfs_open_context(ctx);
out: out:
if (unlikely(switched)) {
d_lookup_done(dentry);
dput(dentry);
}
return err; return err;
no_open: no_open:
res = nfs_lookup(dir, dentry, lookup_flags); res = nfs_lookup(dir, dentry, lookup_flags);
err = PTR_ERR(res); if (switched) {
d_lookup_done(dentry);
if (!res)
res = dentry;
else
dput(dentry);
}
if (IS_ERR(res)) if (IS_ERR(res))
goto out; return PTR_ERR(res);
return finish_no_open(file, res); return finish_no_open(file, res);
} }
EXPORT_SYMBOL_GPL(nfs_atomic_open); EXPORT_SYMBOL_GPL(nfs_atomic_open);
......
...@@ -43,10 +43,8 @@ struct posix_acl_entry { ...@@ -43,10 +43,8 @@ struct posix_acl_entry {
}; };
struct posix_acl { struct posix_acl {
union { atomic_t a_refcount;
atomic_t a_refcount; struct rcu_head a_rcu;
struct rcu_head a_rcu;
};
unsigned int a_count; unsigned int a_count;
struct posix_acl_entry a_entries[0]; struct posix_acl_entry a_entries[0];
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment