Commit b058efc1 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'work.lookup' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs

Pull dcache lookup cleanups from Al Viro:
 "Cleaning ->lookup() instances up - mostly d_splice_alias() conversions"

* 'work.lookup' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: (29 commits)
  switch the rest of procfs lookups to d_splice_alias()
  procfs: switch instantiate_t to d_splice_alias()
  don't bother with tid_fd_revalidate() in lookups
  proc_lookupfd_common(): don't bother with instantiate unless the file is open
  procfs: get rid of ancient BS in pid_revalidate() uses
  cifs_lookup(): switch to d_splice_alias()
  cifs_lookup(): cifs_get_inode_...() never returns 0 with *inode left NULL
  9p: unify paths in v9fs_vfs_lookup()
  ncp_lookup(): use d_splice_alias()
  hfsplus: switch to d_splice_alias()
  hfs: don't allow mounting over .../rsrc
  hfs: use d_splice_alias()
  omfs_lookup(): report IO errors, use d_splice_alias()
  orangefs_lookup: simplify
  openpromfs: switch to d_splice_alias()
  xfs_vn_lookup: simplify a bit
  adfs_lookup: do not fail with ENOENT on negatives, use d_splice_alias()
  adfs_lookup_byname: .. *is* taken care of in fs/namei.c
  romfs_lookup: switch to d_splice_alias()
  qnx6_lookup: switch to d_splice_alias()
  ...
parents 9214407d 888e2b03
...@@ -823,12 +823,11 @@ static struct dentry *ncp_lookup(struct inode *dir, struct dentry *dentry, unsig ...@@ -823,12 +823,11 @@ static struct dentry *ncp_lookup(struct inode *dir, struct dentry *dentry, unsig
struct ncp_server *server = NCP_SERVER(dir); struct ncp_server *server = NCP_SERVER(dir);
struct inode *inode = NULL; struct inode *inode = NULL;
struct ncp_entry_info finfo; struct ncp_entry_info finfo;
int error, res, len; int res, len;
__u8 __name[NCP_MAXPATHLEN + 1]; __u8 __name[NCP_MAXPATHLEN + 1];
error = -EIO;
if (!ncp_conn_valid(server)) if (!ncp_conn_valid(server))
goto finished; return ERR_PTR(-EIO);
ncp_vdbg("server lookup for %pd2\n", dentry); ncp_vdbg("server lookup for %pd2\n", dentry);
...@@ -847,31 +846,20 @@ static struct dentry *ncp_lookup(struct inode *dir, struct dentry *dentry, unsig ...@@ -847,31 +846,20 @@ static struct dentry *ncp_lookup(struct inode *dir, struct dentry *dentry, unsig
res = ncp_obtain_info(server, dir, __name, &(finfo.i)); res = ncp_obtain_info(server, dir, __name, &(finfo.i));
} }
ncp_vdbg("looked for %pd2, res=%d\n", dentry, res); ncp_vdbg("looked for %pd2, res=%d\n", dentry, res);
/* if (!res) {
* If we didn't find an entry, make a negative dentry. /*
*/ * Entry found; create an inode for it.
if (res) */
goto add_entry; finfo.opened = 0;
finfo.ino = iunique(dir->i_sb, 2);
/* finfo.volume = finfo.i.volNumber;
* Create an inode for the entry. inode = ncp_iget(dir->i_sb, &finfo);
*/ if (unlikely(!inode))
finfo.opened = 0; inode = ERR_PTR(-EACCES);
finfo.ino = iunique(dir->i_sb, 2); else
finfo.volume = finfo.i.volNumber; ncp_new_dentry(dentry);
error = -EACCES;
inode = ncp_iget(dir->i_sb, &finfo);
if (inode) {
ncp_new_dentry(dentry);
add_entry:
d_add(dentry, inode);
error = 0;
} }
return d_splice_alias(inode, dentry);
finished:
ncp_vdbg("result=%d\n", error);
return ERR_PTR(error);
} }
/* /*
......
...@@ -823,28 +823,21 @@ struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry, ...@@ -823,28 +823,21 @@ struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
if (IS_ERR(dfid)) if (IS_ERR(dfid))
return ERR_CAST(dfid); return ERR_CAST(dfid);
name = dentry->d_name.name;
fid = p9_client_walk(dfid, 1, &name, 1);
if (IS_ERR(fid)) {
if (fid == ERR_PTR(-ENOENT)) {
d_add(dentry, NULL);
return NULL;
}
return ERR_CAST(fid);
}
/* /*
* Make sure we don't use a wrong inode due to parallel * Make sure we don't use a wrong inode due to parallel
* unlink. For cached mode create calls request for new * unlink. For cached mode create calls request for new
* inode. But with cache disabled, lookup should do this. * inode. But with cache disabled, lookup should do this.
*/ */
if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) name = dentry->d_name.name;
fid = p9_client_walk(dfid, 1, &name, 1);
if (fid == ERR_PTR(-ENOENT))
inode = NULL;
else if (IS_ERR(fid))
inode = ERR_CAST(fid);
else if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE)
inode = v9fs_get_inode_from_fid(v9ses, fid, dir->i_sb); inode = v9fs_get_inode_from_fid(v9ses, fid, dir->i_sb);
else else
inode = v9fs_get_new_inode_from_fid(v9ses, fid, dir->i_sb); inode = v9fs_get_new_inode_from_fid(v9ses, fid, dir->i_sb);
if (IS_ERR(inode)) {
p9_client_clunk(fid);
return ERR_CAST(inode);
}
/* /*
* If we had a rename on the server and a parallel lookup * If we had a rename on the server and a parallel lookup
* for the new name, then make sure we instantiate with * for the new name, then make sure we instantiate with
...@@ -853,12 +846,14 @@ struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry, ...@@ -853,12 +846,14 @@ struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
* k/b. * k/b.
*/ */
res = d_splice_alias(inode, dentry); res = d_splice_alias(inode, dentry);
if (!res) if (!IS_ERR(fid)) {
v9fs_fid_add(dentry, fid); if (!res)
else if (!IS_ERR(res)) v9fs_fid_add(dentry, fid);
v9fs_fid_add(res, fid); else if (!IS_ERR(res))
else v9fs_fid_add(res, fid);
p9_client_clunk(fid); else
p9_client_clunk(fid);
}
return res; return res;
} }
......
...@@ -146,20 +146,6 @@ adfs_dir_lookup_byname(struct inode *inode, const struct qstr *name, struct obje ...@@ -146,20 +146,6 @@ adfs_dir_lookup_byname(struct inode *inode, const struct qstr *name, struct obje
obj->parent_id = inode->i_ino; obj->parent_id = inode->i_ino;
/*
* '.' is handled by reserved_lookup() in fs/namei.c
*/
if (name->len == 2 && name->name[0] == '.' && name->name[1] == '.') {
/*
* Currently unable to fill in the rest of 'obj',
* but this is better than nothing. We need to
* ascend one level to find it's parent.
*/
obj->name_len = 0;
obj->file_id = obj->parent_id;
goto free_out;
}
read_lock(&adfs_dir_lock); read_lock(&adfs_dir_lock);
ret = ops->setpos(&dir, 0); ret = ops->setpos(&dir, 0);
...@@ -266,17 +252,17 @@ adfs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) ...@@ -266,17 +252,17 @@ adfs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
error = adfs_dir_lookup_byname(dir, &dentry->d_name, &obj); error = adfs_dir_lookup_byname(dir, &dentry->d_name, &obj);
if (error == 0) { if (error == 0) {
error = -EACCES;
/* /*
* This only returns NULL if get_empty_inode * This only returns NULL if get_empty_inode
* fails. * fails.
*/ */
inode = adfs_iget(dir->i_sb, &obj); inode = adfs_iget(dir->i_sb, &obj);
if (inode) if (!inode)
error = 0; inode = ERR_PTR(-EACCES);
} else if (error != -ENOENT) {
inode = ERR_PTR(error);
} }
d_add(dentry, inode); return d_splice_alias(inode, dentry);
return ERR_PTR(error);
} }
/* /*
......
...@@ -21,10 +21,9 @@ ...@@ -21,10 +21,9 @@
#define dprintf(x...) #define dprintf(x...)
#endif #endif
static int bfs_add_entry(struct inode *dir, const unsigned char *name, static int bfs_add_entry(struct inode *dir, const struct qstr *child, int ino);
int namelen, int ino);
static struct buffer_head *bfs_find_entry(struct inode *dir, static struct buffer_head *bfs_find_entry(struct inode *dir,
const unsigned char *name, int namelen, const struct qstr *child,
struct bfs_dirent **res_dir); struct bfs_dirent **res_dir);
static int bfs_readdir(struct file *f, struct dir_context *ctx) static int bfs_readdir(struct file *f, struct dir_context *ctx)
...@@ -111,8 +110,7 @@ static int bfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, ...@@ -111,8 +110,7 @@ static int bfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
mark_inode_dirty(inode); mark_inode_dirty(inode);
bfs_dump_imap("create", s); bfs_dump_imap("create", s);
err = bfs_add_entry(dir, dentry->d_name.name, dentry->d_name.len, err = bfs_add_entry(dir, &dentry->d_name, inode->i_ino);
inode->i_ino);
if (err) { if (err) {
inode_dec_link_count(inode); inode_dec_link_count(inode);
mutex_unlock(&info->bfs_lock); mutex_unlock(&info->bfs_lock);
...@@ -136,19 +134,14 @@ static struct dentry *bfs_lookup(struct inode *dir, struct dentry *dentry, ...@@ -136,19 +134,14 @@ static struct dentry *bfs_lookup(struct inode *dir, struct dentry *dentry,
return ERR_PTR(-ENAMETOOLONG); return ERR_PTR(-ENAMETOOLONG);
mutex_lock(&info->bfs_lock); mutex_lock(&info->bfs_lock);
bh = bfs_find_entry(dir, dentry->d_name.name, dentry->d_name.len, &de); bh = bfs_find_entry(dir, &dentry->d_name, &de);
if (bh) { if (bh) {
unsigned long ino = (unsigned long)le16_to_cpu(de->ino); unsigned long ino = (unsigned long)le16_to_cpu(de->ino);
brelse(bh); brelse(bh);
inode = bfs_iget(dir->i_sb, ino); inode = bfs_iget(dir->i_sb, ino);
if (IS_ERR(inode)) {
mutex_unlock(&info->bfs_lock);
return ERR_CAST(inode);
}
} }
mutex_unlock(&info->bfs_lock); mutex_unlock(&info->bfs_lock);
d_add(dentry, inode); return d_splice_alias(inode, dentry);
return NULL;
} }
static int bfs_link(struct dentry *old, struct inode *dir, static int bfs_link(struct dentry *old, struct inode *dir,
...@@ -159,8 +152,7 @@ static int bfs_link(struct dentry *old, struct inode *dir, ...@@ -159,8 +152,7 @@ static int bfs_link(struct dentry *old, struct inode *dir,
int err; int err;
mutex_lock(&info->bfs_lock); mutex_lock(&info->bfs_lock);
err = bfs_add_entry(dir, new->d_name.name, new->d_name.len, err = bfs_add_entry(dir, &new->d_name, inode->i_ino);
inode->i_ino);
if (err) { if (err) {
mutex_unlock(&info->bfs_lock); mutex_unlock(&info->bfs_lock);
return err; return err;
...@@ -183,7 +175,7 @@ static int bfs_unlink(struct inode *dir, struct dentry *dentry) ...@@ -183,7 +175,7 @@ static int bfs_unlink(struct inode *dir, struct dentry *dentry)
struct bfs_sb_info *info = BFS_SB(inode->i_sb); struct bfs_sb_info *info = BFS_SB(inode->i_sb);
mutex_lock(&info->bfs_lock); mutex_lock(&info->bfs_lock);
bh = bfs_find_entry(dir, dentry->d_name.name, dentry->d_name.len, &de); bh = bfs_find_entry(dir, &dentry->d_name, &de);
if (!bh || (le16_to_cpu(de->ino) != inode->i_ino)) if (!bh || (le16_to_cpu(de->ino) != inode->i_ino))
goto out_brelse; goto out_brelse;
...@@ -228,27 +220,21 @@ static int bfs_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -228,27 +220,21 @@ static int bfs_rename(struct inode *old_dir, struct dentry *old_dentry,
info = BFS_SB(old_inode->i_sb); info = BFS_SB(old_inode->i_sb);
mutex_lock(&info->bfs_lock); mutex_lock(&info->bfs_lock);
old_bh = bfs_find_entry(old_dir, old_bh = bfs_find_entry(old_dir, &old_dentry->d_name, &old_de);
old_dentry->d_name.name,
old_dentry->d_name.len, &old_de);
if (!old_bh || (le16_to_cpu(old_de->ino) != old_inode->i_ino)) if (!old_bh || (le16_to_cpu(old_de->ino) != old_inode->i_ino))
goto end_rename; goto end_rename;
error = -EPERM; error = -EPERM;
new_inode = d_inode(new_dentry); new_inode = d_inode(new_dentry);
new_bh = bfs_find_entry(new_dir, new_bh = bfs_find_entry(new_dir, &new_dentry->d_name, &new_de);
new_dentry->d_name.name,
new_dentry->d_name.len, &new_de);
if (new_bh && !new_inode) { if (new_bh && !new_inode) {
brelse(new_bh); brelse(new_bh);
new_bh = NULL; new_bh = NULL;
} }
if (!new_bh) { if (!new_bh) {
error = bfs_add_entry(new_dir, error = bfs_add_entry(new_dir, &new_dentry->d_name,
new_dentry->d_name.name,
new_dentry->d_name.len,
old_inode->i_ino); old_inode->i_ino);
if (error) if (error)
goto end_rename; goto end_rename;
...@@ -278,9 +264,10 @@ const struct inode_operations bfs_dir_inops = { ...@@ -278,9 +264,10 @@ const struct inode_operations bfs_dir_inops = {
.rename = bfs_rename, .rename = bfs_rename,
}; };
static int bfs_add_entry(struct inode *dir, const unsigned char *name, static int bfs_add_entry(struct inode *dir, const struct qstr *child, int ino)
int namelen, int ino)
{ {
const unsigned char *name = child->name;
int namelen = child->len;
struct buffer_head *bh; struct buffer_head *bh;
struct bfs_dirent *de; struct bfs_dirent *de;
int block, sblock, eblock, off, pos; int block, sblock, eblock, off, pos;
...@@ -332,12 +319,14 @@ static inline int bfs_namecmp(int len, const unsigned char *name, ...@@ -332,12 +319,14 @@ static inline int bfs_namecmp(int len, const unsigned char *name,
} }
static struct buffer_head *bfs_find_entry(struct inode *dir, static struct buffer_head *bfs_find_entry(struct inode *dir,
const unsigned char *name, int namelen, const struct qstr *child,
struct bfs_dirent **res_dir) struct bfs_dirent **res_dir)
{ {
unsigned long block = 0, offset = 0; unsigned long block = 0, offset = 0;
struct buffer_head *bh = NULL; struct buffer_head *bh = NULL;
struct bfs_dirent *de; struct bfs_dirent *de;
const unsigned char *name = child->name;
int namelen = child->len;
*res_dir = NULL; *res_dir = NULL;
if (namelen > BFS_NAMELEN) if (namelen > BFS_NAMELEN)
......
...@@ -780,21 +780,25 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, ...@@ -780,21 +780,25 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
tlink = cifs_sb_tlink(cifs_sb); tlink = cifs_sb_tlink(cifs_sb);
if (IS_ERR(tlink)) { if (IS_ERR(tlink)) {
free_xid(xid); free_xid(xid);
return (struct dentry *)tlink; return ERR_CAST(tlink);
} }
pTcon = tlink_tcon(tlink); pTcon = tlink_tcon(tlink);
rc = check_name(direntry, pTcon); rc = check_name(direntry, pTcon);
if (rc) if (unlikely(rc)) {
goto lookup_out; cifs_put_tlink(tlink);
free_xid(xid);
return ERR_PTR(rc);
}
/* can not grab the rename sem here since it would /* can not grab the rename sem here since it would
deadlock in the cases (beginning of sys_rename itself) deadlock in the cases (beginning of sys_rename itself)
in which we already have the sb rename sem */ in which we already have the sb rename sem */
full_path = build_path_from_dentry(direntry); full_path = build_path_from_dentry(direntry);
if (full_path == NULL) { if (full_path == NULL) {
rc = -ENOMEM; cifs_put_tlink(tlink);
goto lookup_out; free_xid(xid);
return ERR_PTR(-ENOMEM);
} }
if (d_really_is_positive(direntry)) { if (d_really_is_positive(direntry)) {
...@@ -813,29 +817,25 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, ...@@ -813,29 +817,25 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
parent_dir_inode->i_sb, xid, NULL); parent_dir_inode->i_sb, xid, NULL);
} }
if ((rc == 0) && (newInode != NULL)) { if (rc == 0) {
d_add(direntry, newInode);
/* since paths are not looked up by component - the parent /* since paths are not looked up by component - the parent
directories are presumed to be good here */ directories are presumed to be good here */
renew_parental_timestamps(direntry); renew_parental_timestamps(direntry);
} else if (rc == -ENOENT) { } else if (rc == -ENOENT) {
rc = 0;
cifs_set_time(direntry, jiffies); cifs_set_time(direntry, jiffies);
d_add(direntry, NULL); newInode = NULL;
/* if it was once a directory (but how can we tell?) we could do } else {
shrink_dcache_parent(direntry); */ if (rc != -EACCES) {
} else if (rc != -EACCES) { cifs_dbg(FYI, "Unexpected lookup error %d\n", rc);
cifs_dbg(FYI, "Unexpected lookup error %d\n", rc); /* We special case check for Access Denied - since that
/* We special case check for Access Denied - since that is a common return code */
is a common return code */ }
newInode = ERR_PTR(rc);
} }
lookup_out:
kfree(full_path); kfree(full_path);
cifs_put_tlink(tlink); cifs_put_tlink(tlink);
free_xid(xid); free_xid(xid);
return ERR_PTR(rc); return d_splice_alias(newInode, direntry);
} }
static int static int
......
...@@ -808,10 +808,7 @@ static struct dentry *cramfs_lookup(struct inode *dir, struct dentry *dentry, un ...@@ -808,10 +808,7 @@ static struct dentry *cramfs_lookup(struct inode *dir, struct dentry *dentry, un
} }
out: out:
mutex_unlock(&read_mutex); mutex_unlock(&read_mutex);
if (IS_ERR(inode)) return d_splice_alias(inode, dentry);
return ERR_CAST(inode);
d_add(dentry, inode);
return NULL;
} }
static int cramfs_readpage(struct file *file, struct page *page) static int cramfs_readpage(struct file *file, struct page *page)
......
...@@ -193,13 +193,9 @@ vxfs_lookup(struct inode *dip, struct dentry *dp, unsigned int flags) ...@@ -193,13 +193,9 @@ vxfs_lookup(struct inode *dip, struct dentry *dp, unsigned int flags)
return ERR_PTR(-ENAMETOOLONG); return ERR_PTR(-ENAMETOOLONG);
ino = vxfs_inode_by_name(dip, dp); ino = vxfs_inode_by_name(dip, dp);
if (ino) { if (ino)
ip = vxfs_iget(dip->i_sb, ino); ip = vxfs_iget(dip->i_sb, ino);
if (IS_ERR(ip)) return d_splice_alias(ip, dp);
return ERR_CAST(ip);
}
d_add(dp, ip);
return NULL;
} }
/** /**
......
...@@ -31,21 +31,15 @@ static struct dentry *hfs_lookup(struct inode *dir, struct dentry *dentry, ...@@ -31,21 +31,15 @@ static struct dentry *hfs_lookup(struct inode *dir, struct dentry *dentry,
hfs_cat_build_key(dir->i_sb, fd.search_key, dir->i_ino, &dentry->d_name); hfs_cat_build_key(dir->i_sb, fd.search_key, dir->i_ino, &dentry->d_name);
res = hfs_brec_read(&fd, &rec, sizeof(rec)); res = hfs_brec_read(&fd, &rec, sizeof(rec));
if (res) { if (res) {
hfs_find_exit(&fd); if (res != -ENOENT)
if (res == -ENOENT) { inode = ERR_PTR(res);
/* No such entry */ } else {
inode = NULL; inode = hfs_iget(dir->i_sb, &fd.search_key->cat, &rec);
goto done; if (!inode)
} inode = ERR_PTR(-EACCES);
return ERR_PTR(res);
} }
inode = hfs_iget(dir->i_sb, &fd.search_key->cat, &rec);
hfs_find_exit(&fd); hfs_find_exit(&fd);
if (!inode) return d_splice_alias(inode, dentry);
return ERR_PTR(-EACCES);
done:
d_add(dentry, inode);
return NULL;
} }
/* /*
......
...@@ -543,9 +543,9 @@ static struct dentry *hfs_file_lookup(struct inode *dir, struct dentry *dentry, ...@@ -543,9 +543,9 @@ static struct dentry *hfs_file_lookup(struct inode *dir, struct dentry *dentry,
igrab(dir); igrab(dir);
hlist_add_fake(&inode->i_hash); hlist_add_fake(&inode->i_hash);
mark_inode_dirty(inode); mark_inode_dirty(inode);
dont_mount(dentry);
out: out:
d_add(dentry, inode); return d_splice_alias(inode, dentry);
return NULL;
} }
void hfs_evict_inode(struct inode *inode) void hfs_evict_inode(struct inode *inode)
......
...@@ -122,8 +122,7 @@ static struct dentry *hfsplus_lookup(struct inode *dir, struct dentry *dentry, ...@@ -122,8 +122,7 @@ static struct dentry *hfsplus_lookup(struct inode *dir, struct dentry *dentry,
if (S_ISREG(inode->i_mode)) if (S_ISREG(inode->i_mode))
HFSPLUS_I(inode)->linkid = linkid; HFSPLUS_I(inode)->linkid = linkid;
out: out:
d_add(dentry, inode); return d_splice_alias(inode, dentry);
return NULL;
fail: fail:
hfs_find_exit(&fd); hfs_find_exit(&fd);
return ERR_PTR(err); return ERR_PTR(err);
......
...@@ -28,13 +28,9 @@ static struct dentry *minix_lookup(struct inode * dir, struct dentry *dentry, un ...@@ -28,13 +28,9 @@ static struct dentry *minix_lookup(struct inode * dir, struct dentry *dentry, un
return ERR_PTR(-ENAMETOOLONG); return ERR_PTR(-ENAMETOOLONG);
ino = minix_inode_by_name(dentry); ino = minix_inode_by_name(dentry);
if (ino) { if (ino)
inode = minix_iget(dir->i_sb, ino); inode = minix_iget(dir->i_sb, ino);
if (IS_ERR(inode)) return d_splice_alias(inode, dentry);
return ERR_CAST(inode);
}
d_add(dentry, inode);
return NULL;
} }
static int minix_mknod(struct inode * dir, struct dentry *dentry, umode_t mode, dev_t rdev) static int minix_mknod(struct inode * dir, struct dentry *dentry, umode_t mode, dev_t rdev)
......
...@@ -305,11 +305,10 @@ static struct dentry *omfs_lookup(struct inode *dir, struct dentry *dentry, ...@@ -305,11 +305,10 @@ static struct dentry *omfs_lookup(struct inode *dir, struct dentry *dentry,
ino_t ino = be64_to_cpu(oi->i_head.h_self); ino_t ino = be64_to_cpu(oi->i_head.h_self);
brelse(bh); brelse(bh);
inode = omfs_iget(dir->i_sb, ino); inode = omfs_iget(dir->i_sb, ino);
if (IS_ERR(inode)) } else if (bh != ERR_PTR(-ENOENT)) {
return ERR_CAST(inode); inode = ERR_CAST(bh);
} }
d_add(dentry, inode); return d_splice_alias(inode, dentry);
return NULL;
} }
/* sanity check block's self pointer */ /* sanity check block's self pointer */
......
...@@ -256,8 +256,7 @@ static struct dentry *openpromfs_lookup(struct inode *dir, struct dentry *dentry ...@@ -256,8 +256,7 @@ static struct dentry *openpromfs_lookup(struct inode *dir, struct dentry *dentry
break; break;
} }
d_add(dentry, inode); return d_splice_alias(inode, dentry);
return NULL;
} }
static int openpromfs_readdir(struct file *file, struct dir_context *ctx) static int openpromfs_readdir(struct file *file, struct dir_context *ctx)
......
...@@ -110,7 +110,6 @@ static struct dentry *orangefs_lookup(struct inode *dir, struct dentry *dentry, ...@@ -110,7 +110,6 @@ static struct dentry *orangefs_lookup(struct inode *dir, struct dentry *dentry,
struct orangefs_inode_s *parent = ORANGEFS_I(dir); struct orangefs_inode_s *parent = ORANGEFS_I(dir);
struct orangefs_kernel_op_s *new_op; struct orangefs_kernel_op_s *new_op;
struct inode *inode; struct inode *inode;
struct dentry *res;
int ret = -EINVAL; int ret = -EINVAL;
/* /*
...@@ -158,65 +157,18 @@ static struct dentry *orangefs_lookup(struct inode *dir, struct dentry *dentry, ...@@ -158,65 +157,18 @@ static struct dentry *orangefs_lookup(struct inode *dir, struct dentry *dentry,
new_op->downcall.resp.lookup.refn.fs_id, new_op->downcall.resp.lookup.refn.fs_id,
ret); ret);
if (ret < 0) { if (ret >= 0) {
if (ret == -ENOENT) { orangefs_set_timeout(dentry);
/* inode = orangefs_iget(dir->i_sb, &new_op->downcall.resp.lookup.refn);
* if no inode was found, add a negative dentry to } else if (ret == -ENOENT) {
* dcache anyway; if we don't, we don't hold expected inode = NULL;
* lookup semantics and we most noticeably break } else {
* during directory renames.
*
* however, if the operation failed or exited, do not
* add the dentry (e.g. in the case that a touch is
* issued on a file that already exists that was
* interrupted during this lookup -- no need to add
* another negative dentry for an existing file)
*/
gossip_debug(GOSSIP_NAME_DEBUG,
"orangefs_lookup: Adding *negative* dentry "
"%p for %pd\n",
dentry,
dentry);
d_add(dentry, NULL);
res = NULL;
goto out;
}
/* must be a non-recoverable error */ /* must be a non-recoverable error */
res = ERR_PTR(ret); inode = ERR_PTR(ret);
goto out;
}
orangefs_set_timeout(dentry);
inode = orangefs_iget(dir->i_sb, &new_op->downcall.resp.lookup.refn);
if (IS_ERR(inode)) {
gossip_debug(GOSSIP_NAME_DEBUG,
"error %ld from iget\n", PTR_ERR(inode));
res = ERR_CAST(inode);
goto out;
} }
gossip_debug(GOSSIP_NAME_DEBUG,
"%s:%s:%d "
"Found good inode [%lu] with count [%d]\n",
__FILE__,
__func__,
__LINE__,
inode->i_ino,
(int)atomic_read(&inode->i_count));
/* update dentry/inode pair into dcache */
res = d_splice_alias(inode, dentry);
gossip_debug(GOSSIP_NAME_DEBUG,
"Lookup success (inode ct = %d)\n",
(int)atomic_read(&inode->i_count));
out:
op_release(new_op); op_release(new_op);
return res; return d_splice_alias(inode, dentry);
} }
/* return 0 on success; non-zero otherwise */ /* return 0 on success; non-zero otherwise */
......
...@@ -1807,15 +1807,22 @@ int pid_getattr(const struct path *path, struct kstat *stat, ...@@ -1807,15 +1807,22 @@ int pid_getattr(const struct path *path, struct kstat *stat,
/* dentry stuff */ /* dentry stuff */
/* /*
* Exceptional case: normally we are not allowed to unhash a busy * Set <pid>/... inode ownership (can change due to setuid(), etc.)
* directory. In this case, however, we can do it - no aliasing problems */
* due to the way we treat inodes. void pid_update_inode(struct task_struct *task, struct inode *inode)
* {
task_dump_owner(task, inode->i_mode, &inode->i_uid, &inode->i_gid);
inode->i_mode &= ~(S_ISUID | S_ISGID);
security_task_to_inode(task, inode);
}
/*
* Rewrite the inode's ownerships here because the owning task may have * Rewrite the inode's ownerships here because the owning task may have
* performed a setuid(), etc. * performed a setuid(), etc.
* *
*/ */
int pid_revalidate(struct dentry *dentry, unsigned int flags) static int pid_revalidate(struct dentry *dentry, unsigned int flags)
{ {
struct inode *inode; struct inode *inode;
struct task_struct *task; struct task_struct *task;
...@@ -1827,10 +1834,7 @@ int pid_revalidate(struct dentry *dentry, unsigned int flags) ...@@ -1827,10 +1834,7 @@ int pid_revalidate(struct dentry *dentry, unsigned int flags)
task = get_proc_task(inode); task = get_proc_task(inode);
if (task) { if (task) {
task_dump_owner(task, inode->i_mode, &inode->i_uid, &inode->i_gid); pid_update_inode(task, inode);
inode->i_mode &= ~(S_ISUID | S_ISGID);
security_task_to_inode(task, inode);
put_task_struct(task); put_task_struct(task);
return 1; return 1;
} }
...@@ -1878,8 +1882,8 @@ bool proc_fill_cache(struct file *file, struct dir_context *ctx, ...@@ -1878,8 +1882,8 @@ bool proc_fill_cache(struct file *file, struct dir_context *ctx,
struct dentry *child, *dir = file->f_path.dentry; struct dentry *child, *dir = file->f_path.dentry;
struct qstr qname = QSTR_INIT(name, len); struct qstr qname = QSTR_INIT(name, len);
struct inode *inode; struct inode *inode;
unsigned type; unsigned type = DT_UNKNOWN;
ino_t ino; ino_t ino = 1;
child = d_hash_and_lookup(dir, &qname); child = d_hash_and_lookup(dir, &qname);
if (!child) { if (!child) {
...@@ -1888,22 +1892,23 @@ bool proc_fill_cache(struct file *file, struct dir_context *ctx, ...@@ -1888,22 +1892,23 @@ bool proc_fill_cache(struct file *file, struct dir_context *ctx,
if (IS_ERR(child)) if (IS_ERR(child))
goto end_instantiate; goto end_instantiate;
if (d_in_lookup(child)) { if (d_in_lookup(child)) {
int err = instantiate(d_inode(dir), child, task, ptr); struct dentry *res;
res = instantiate(child, task, ptr);
d_lookup_done(child); d_lookup_done(child);
if (err < 0) { if (IS_ERR(res))
dput(child);
goto end_instantiate; goto end_instantiate;
if (unlikely(res)) {
dput(child);
child = res;
} }
} }
} }
inode = d_inode(child); inode = d_inode(child);
ino = inode->i_ino; ino = inode->i_ino;
type = inode->i_mode >> 12; type = inode->i_mode >> 12;
end_instantiate:
dput(child); dput(child);
return dir_emit(ctx, name, len, ino, type); return dir_emit(ctx, name, len, ino, type);
end_instantiate:
return dir_emit(ctx, name, len, 1, DT_UNKNOWN);
} }
/* /*
...@@ -2065,19 +2070,19 @@ static const struct inode_operations proc_map_files_link_inode_operations = { ...@@ -2065,19 +2070,19 @@ static const struct inode_operations proc_map_files_link_inode_operations = {
.setattr = proc_setattr, .setattr = proc_setattr,
}; };
static int static struct dentry *
proc_map_files_instantiate(struct inode *dir, struct dentry *dentry, proc_map_files_instantiate(struct dentry *dentry,
struct task_struct *task, const void *ptr) struct task_struct *task, const void *ptr)
{ {
fmode_t mode = (fmode_t)(unsigned long)ptr; fmode_t mode = (fmode_t)(unsigned long)ptr;
struct proc_inode *ei; struct proc_inode *ei;
struct inode *inode; struct inode *inode;
inode = proc_pid_make_inode(dir->i_sb, task, S_IFLNK | inode = proc_pid_make_inode(dentry->d_sb, task, S_IFLNK |
((mode & FMODE_READ ) ? S_IRUSR : 0) | ((mode & FMODE_READ ) ? S_IRUSR : 0) |
((mode & FMODE_WRITE) ? S_IWUSR : 0)); ((mode & FMODE_WRITE) ? S_IWUSR : 0));
if (!inode) if (!inode)
return -ENOENT; return ERR_PTR(-ENOENT);
ei = PROC_I(inode); ei = PROC_I(inode);
ei->op.proc_get_link = map_files_get_link; ei->op.proc_get_link = map_files_get_link;
...@@ -2086,9 +2091,7 @@ proc_map_files_instantiate(struct inode *dir, struct dentry *dentry, ...@@ -2086,9 +2091,7 @@ proc_map_files_instantiate(struct inode *dir, struct dentry *dentry,
inode->i_size = 64; inode->i_size = 64;
d_set_d_op(dentry, &tid_map_files_dentry_operations); d_set_d_op(dentry, &tid_map_files_dentry_operations);
d_add(dentry, inode); return d_splice_alias(inode, dentry);
return 0;
} }
static struct dentry *proc_map_files_lookup(struct inode *dir, static struct dentry *proc_map_files_lookup(struct inode *dir,
...@@ -2097,19 +2100,19 @@ static struct dentry *proc_map_files_lookup(struct inode *dir, ...@@ -2097,19 +2100,19 @@ static struct dentry *proc_map_files_lookup(struct inode *dir,
unsigned long vm_start, vm_end; unsigned long vm_start, vm_end;
struct vm_area_struct *vma; struct vm_area_struct *vma;
struct task_struct *task; struct task_struct *task;
int result; struct dentry *result;
struct mm_struct *mm; struct mm_struct *mm;
result = -ENOENT; result = ERR_PTR(-ENOENT);
task = get_proc_task(dir); task = get_proc_task(dir);
if (!task) if (!task)
goto out; goto out;
result = -EACCES; result = ERR_PTR(-EACCES);
if (!ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS)) if (!ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS))
goto out_put_task; goto out_put_task;
result = -ENOENT; result = ERR_PTR(-ENOENT);
if (dname_to_vma_addr(dentry, &vm_start, &vm_end)) if (dname_to_vma_addr(dentry, &vm_start, &vm_end))
goto out_put_task; goto out_put_task;
...@@ -2123,7 +2126,7 @@ static struct dentry *proc_map_files_lookup(struct inode *dir, ...@@ -2123,7 +2126,7 @@ static struct dentry *proc_map_files_lookup(struct inode *dir,
goto out_no_vma; goto out_no_vma;
if (vma->vm_file) if (vma->vm_file)
result = proc_map_files_instantiate(dir, dentry, task, result = proc_map_files_instantiate(dentry, task,
(void *)(unsigned long)vma->vm_file->f_mode); (void *)(unsigned long)vma->vm_file->f_mode);
out_no_vma: out_no_vma:
...@@ -2132,7 +2135,7 @@ static struct dentry *proc_map_files_lookup(struct inode *dir, ...@@ -2132,7 +2135,7 @@ static struct dentry *proc_map_files_lookup(struct inode *dir,
out_put_task: out_put_task:
put_task_struct(task); put_task_struct(task);
out: out:
return ERR_PTR(result); return result;
} }
static const struct inode_operations proc_map_files_inode_operations = { static const struct inode_operations proc_map_files_inode_operations = {
...@@ -2433,16 +2436,16 @@ static const struct file_operations proc_pid_set_timerslack_ns_operations = { ...@@ -2433,16 +2436,16 @@ static const struct file_operations proc_pid_set_timerslack_ns_operations = {
.release = single_release, .release = single_release,
}; };
static int proc_pident_instantiate(struct inode *dir, static struct dentry *proc_pident_instantiate(struct dentry *dentry,
struct dentry *dentry, struct task_struct *task, const void *ptr) struct task_struct *task, const void *ptr)
{ {
const struct pid_entry *p = ptr; const struct pid_entry *p = ptr;
struct inode *inode; struct inode *inode;
struct proc_inode *ei; struct proc_inode *ei;
inode = proc_pid_make_inode(dir->i_sb, task, p->mode); inode = proc_pid_make_inode(dentry->d_sb, task, p->mode);
if (!inode) if (!inode)
goto out; return ERR_PTR(-ENOENT);
ei = PROC_I(inode); ei = PROC_I(inode);
if (S_ISDIR(inode->i_mode)) if (S_ISDIR(inode->i_mode))
...@@ -2452,13 +2455,9 @@ static int proc_pident_instantiate(struct inode *dir, ...@@ -2452,13 +2455,9 @@ static int proc_pident_instantiate(struct inode *dir,
if (p->fop) if (p->fop)
inode->i_fop = p->fop; inode->i_fop = p->fop;
ei->op = p->op; ei->op = p->op;
pid_update_inode(task, inode);
d_set_d_op(dentry, &pid_dentry_operations); d_set_d_op(dentry, &pid_dentry_operations);
d_add(dentry, inode); return d_splice_alias(inode, dentry);
/* Close the race of the process dying before we return the dentry */
if (pid_revalidate(dentry, 0))
return 0;
out:
return -ENOENT;
} }
static struct dentry *proc_pident_lookup(struct inode *dir, static struct dentry *proc_pident_lookup(struct inode *dir,
...@@ -2466,11 +2465,9 @@ static struct dentry *proc_pident_lookup(struct inode *dir, ...@@ -2466,11 +2465,9 @@ static struct dentry *proc_pident_lookup(struct inode *dir,
const struct pid_entry *ents, const struct pid_entry *ents,
unsigned int nents) unsigned int nents)
{ {
int error;
struct task_struct *task = get_proc_task(dir); struct task_struct *task = get_proc_task(dir);
const struct pid_entry *p, *last; const struct pid_entry *p, *last;
struct dentry *res = ERR_PTR(-ENOENT);
error = -ENOENT;
if (!task) if (!task)
goto out_no_task; goto out_no_task;
...@@ -2489,11 +2486,11 @@ static struct dentry *proc_pident_lookup(struct inode *dir, ...@@ -2489,11 +2486,11 @@ static struct dentry *proc_pident_lookup(struct inode *dir,
if (p >= last) if (p >= last)
goto out; goto out;
error = proc_pident_instantiate(dir, dentry, task, p); res = proc_pident_instantiate(dentry, task, p);
out: out:
put_task_struct(task); put_task_struct(task);
out_no_task: out_no_task:
return ERR_PTR(error); return res;
} }
static int proc_pident_readdir(struct file *file, struct dir_context *ctx, static int proc_pident_readdir(struct file *file, struct dir_context *ctx,
...@@ -3136,38 +3133,32 @@ void proc_flush_task(struct task_struct *task) ...@@ -3136,38 +3133,32 @@ void proc_flush_task(struct task_struct *task)
} }
} }
static int proc_pid_instantiate(struct inode *dir, static struct dentry *proc_pid_instantiate(struct dentry * dentry,
struct dentry * dentry,
struct task_struct *task, const void *ptr) struct task_struct *task, const void *ptr)
{ {
struct inode *inode; struct inode *inode;
inode = proc_pid_make_inode(dir->i_sb, task, S_IFDIR | S_IRUGO | S_IXUGO); inode = proc_pid_make_inode(dentry->d_sb, task, S_IFDIR | S_IRUGO | S_IXUGO);
if (!inode) if (!inode)
goto out; return ERR_PTR(-ENOENT);
inode->i_op = &proc_tgid_base_inode_operations; inode->i_op = &proc_tgid_base_inode_operations;
inode->i_fop = &proc_tgid_base_operations; inode->i_fop = &proc_tgid_base_operations;
inode->i_flags|=S_IMMUTABLE; inode->i_flags|=S_IMMUTABLE;
set_nlink(inode, nlink_tgid); set_nlink(inode, nlink_tgid);
pid_update_inode(task, inode);
d_set_d_op(dentry, &pid_dentry_operations); d_set_d_op(dentry, &pid_dentry_operations);
return d_splice_alias(inode, dentry);
d_add(dentry, inode);
/* Close the race of the process dying before we return the dentry */
if (pid_revalidate(dentry, 0))
return 0;
out:
return -ENOENT;
} }
struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, unsigned int flags) struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, unsigned int flags)
{ {
int result = -ENOENT;
struct task_struct *task; struct task_struct *task;
unsigned tgid; unsigned tgid;
struct pid_namespace *ns; struct pid_namespace *ns;
struct dentry *result = ERR_PTR(-ENOENT);
tgid = name_to_int(&dentry->d_name); tgid = name_to_int(&dentry->d_name);
if (tgid == ~0U) if (tgid == ~0U)
...@@ -3182,10 +3173,10 @@ struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, unsign ...@@ -3182,10 +3173,10 @@ struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, unsign
if (!task) if (!task)
goto out; goto out;
result = proc_pid_instantiate(dir, dentry, task, NULL); result = proc_pid_instantiate(dentry, task, NULL);
put_task_struct(task); put_task_struct(task);
out: out:
return ERR_PTR(result); return result;
} }
/* /*
...@@ -3433,37 +3424,32 @@ static const struct inode_operations proc_tid_base_inode_operations = { ...@@ -3433,37 +3424,32 @@ static const struct inode_operations proc_tid_base_inode_operations = {
.setattr = proc_setattr, .setattr = proc_setattr,
}; };
static int proc_task_instantiate(struct inode *dir, static struct dentry *proc_task_instantiate(struct dentry *dentry,
struct dentry *dentry, struct task_struct *task, const void *ptr) struct task_struct *task, const void *ptr)
{ {
struct inode *inode; struct inode *inode;
inode = proc_pid_make_inode(dir->i_sb, task, S_IFDIR | S_IRUGO | S_IXUGO); inode = proc_pid_make_inode(dentry->d_sb, task, S_IFDIR | S_IRUGO | S_IXUGO);
if (!inode) if (!inode)
goto out; return ERR_PTR(-ENOENT);
inode->i_op = &proc_tid_base_inode_operations; inode->i_op = &proc_tid_base_inode_operations;
inode->i_fop = &proc_tid_base_operations; inode->i_fop = &proc_tid_base_operations;
inode->i_flags|=S_IMMUTABLE; inode->i_flags |= S_IMMUTABLE;
set_nlink(inode, nlink_tid); set_nlink(inode, nlink_tid);
pid_update_inode(task, inode);
d_set_d_op(dentry, &pid_dentry_operations); d_set_d_op(dentry, &pid_dentry_operations);
return d_splice_alias(inode, dentry);
d_add(dentry, inode);
/* Close the race of the process dying before we return the dentry */
if (pid_revalidate(dentry, 0))
return 0;
out:
return -ENOENT;
} }
static struct dentry *proc_task_lookup(struct inode *dir, struct dentry * dentry, unsigned int flags) static struct dentry *proc_task_lookup(struct inode *dir, struct dentry * dentry, unsigned int flags)
{ {
int result = -ENOENT;
struct task_struct *task; struct task_struct *task;
struct task_struct *leader = get_proc_task(dir); struct task_struct *leader = get_proc_task(dir);
unsigned tid; unsigned tid;
struct pid_namespace *ns; struct pid_namespace *ns;
struct dentry *result = ERR_PTR(-ENOENT);
if (!leader) if (!leader)
goto out_no_task; goto out_no_task;
...@@ -3483,13 +3469,13 @@ static struct dentry *proc_task_lookup(struct inode *dir, struct dentry * dentry ...@@ -3483,13 +3469,13 @@ static struct dentry *proc_task_lookup(struct inode *dir, struct dentry * dentry
if (!same_thread_group(leader, task)) if (!same_thread_group(leader, task))
goto out_drop_task; goto out_drop_task;
result = proc_task_instantiate(dir, dentry, task, NULL); result = proc_task_instantiate(dentry, task, NULL);
out_drop_task: out_drop_task:
put_task_struct(task); put_task_struct(task);
out: out:
put_task_struct(leader); put_task_struct(leader);
out_no_task: out_no_task:
return ERR_PTR(result); return result;
} }
/* /*
......
...@@ -81,9 +81,41 @@ static const struct file_operations proc_fdinfo_file_operations = { ...@@ -81,9 +81,41 @@ static const struct file_operations proc_fdinfo_file_operations = {
.release = single_release, .release = single_release,
}; };
static bool tid_fd_mode(struct task_struct *task, unsigned fd, fmode_t *mode)
{
struct files_struct *files = get_files_struct(task);
struct file *file;
if (!files)
return false;
rcu_read_lock();
file = fcheck_files(files, fd);
if (file)
*mode = file->f_mode;
rcu_read_unlock();
put_files_struct(files);
return !!file;
}
static void tid_fd_update_inode(struct task_struct *task, struct inode *inode,
fmode_t f_mode)
{
task_dump_owner(task, 0, &inode->i_uid, &inode->i_gid);
if (S_ISLNK(inode->i_mode)) {
unsigned i_mode = S_IFLNK;
if (f_mode & FMODE_READ)
i_mode |= S_IRUSR | S_IXUSR;
if (f_mode & FMODE_WRITE)
i_mode |= S_IWUSR | S_IXUSR;
inode->i_mode = i_mode;
}
security_task_to_inode(task, inode);
}
static int tid_fd_revalidate(struct dentry *dentry, unsigned int flags) static int tid_fd_revalidate(struct dentry *dentry, unsigned int flags)
{ {
struct files_struct *files;
struct task_struct *task; struct task_struct *task;
struct inode *inode; struct inode *inode;
unsigned int fd; unsigned int fd;
...@@ -96,35 +128,11 @@ static int tid_fd_revalidate(struct dentry *dentry, unsigned int flags) ...@@ -96,35 +128,11 @@ static int tid_fd_revalidate(struct dentry *dentry, unsigned int flags)
fd = proc_fd(inode); fd = proc_fd(inode);
if (task) { if (task) {
files = get_files_struct(task); fmode_t f_mode;
if (files) { if (tid_fd_mode(task, fd, &f_mode)) {
struct file *file; tid_fd_update_inode(task, inode, f_mode);
put_task_struct(task);
rcu_read_lock(); return 1;
file = fcheck_files(files, fd);
if (file) {
unsigned f_mode = file->f_mode;
rcu_read_unlock();
put_files_struct(files);
task_dump_owner(task, 0, &inode->i_uid, &inode->i_gid);
if (S_ISLNK(inode->i_mode)) {
unsigned i_mode = S_IFLNK;
if (f_mode & FMODE_READ)
i_mode |= S_IRUSR | S_IXUSR;
if (f_mode & FMODE_WRITE)
i_mode |= S_IWUSR | S_IXUSR;
inode->i_mode = i_mode;
}
security_task_to_inode(task, inode);
put_task_struct(task);
return 1;
}
rcu_read_unlock();
put_files_struct(files);
} }
put_task_struct(task); put_task_struct(task);
} }
...@@ -166,34 +174,33 @@ static int proc_fd_link(struct dentry *dentry, struct path *path) ...@@ -166,34 +174,33 @@ static int proc_fd_link(struct dentry *dentry, struct path *path)
return ret; return ret;
} }
static int struct fd_data {
proc_fd_instantiate(struct inode *dir, struct dentry *dentry, fmode_t mode;
struct task_struct *task, const void *ptr) unsigned fd;
};
static struct dentry *proc_fd_instantiate(struct dentry *dentry,
struct task_struct *task, const void *ptr)
{ {
unsigned fd = (unsigned long)ptr; const struct fd_data *data = ptr;
struct proc_inode *ei; struct proc_inode *ei;
struct inode *inode; struct inode *inode;
inode = proc_pid_make_inode(dir->i_sb, task, S_IFLNK); inode = proc_pid_make_inode(dentry->d_sb, task, S_IFLNK);
if (!inode) if (!inode)
goto out; return ERR_PTR(-ENOENT);
ei = PROC_I(inode); ei = PROC_I(inode);
ei->fd = fd; ei->fd = data->fd;
inode->i_op = &proc_pid_link_inode_operations; inode->i_op = &proc_pid_link_inode_operations;
inode->i_size = 64; inode->i_size = 64;
ei->op.proc_get_link = proc_fd_link; ei->op.proc_get_link = proc_fd_link;
tid_fd_update_inode(task, inode, data->mode);
d_set_d_op(dentry, &tid_fd_dentry_operations); d_set_d_op(dentry, &tid_fd_dentry_operations);
d_add(dentry, inode); return d_splice_alias(inode, dentry);
/* Close the race of the process dying before we return the dentry */
if (tid_fd_revalidate(dentry, 0))
return 0;
out:
return -ENOENT;
} }
static struct dentry *proc_lookupfd_common(struct inode *dir, static struct dentry *proc_lookupfd_common(struct inode *dir,
...@@ -201,19 +208,21 @@ static struct dentry *proc_lookupfd_common(struct inode *dir, ...@@ -201,19 +208,21 @@ static struct dentry *proc_lookupfd_common(struct inode *dir,
instantiate_t instantiate) instantiate_t instantiate)
{ {
struct task_struct *task = get_proc_task(dir); struct task_struct *task = get_proc_task(dir);
int result = -ENOENT; struct fd_data data = {.fd = name_to_int(&dentry->d_name)};
unsigned fd = name_to_int(&dentry->d_name); struct dentry *result = ERR_PTR(-ENOENT);
if (!task) if (!task)
goto out_no_task; goto out_no_task;
if (fd == ~0U) if (data.fd == ~0U)
goto out;
if (!tid_fd_mode(task, data.fd, &data.mode))
goto out; goto out;
result = instantiate(dir, dentry, task, (void *)(unsigned long)fd); result = instantiate(dentry, task, &data);
out: out:
put_task_struct(task); put_task_struct(task);
out_no_task: out_no_task:
return ERR_PTR(result); return result;
} }
static int proc_readfd_common(struct file *file, struct dir_context *ctx, static int proc_readfd_common(struct file *file, struct dir_context *ctx,
...@@ -236,17 +245,22 @@ static int proc_readfd_common(struct file *file, struct dir_context *ctx, ...@@ -236,17 +245,22 @@ static int proc_readfd_common(struct file *file, struct dir_context *ctx,
for (fd = ctx->pos - 2; for (fd = ctx->pos - 2;
fd < files_fdtable(files)->max_fds; fd < files_fdtable(files)->max_fds;
fd++, ctx->pos++) { fd++, ctx->pos++) {
struct file *f;
struct fd_data data;
char name[10 + 1]; char name[10 + 1];
int len; int len;
if (!fcheck_files(files, fd)) f = fcheck_files(files, fd);
if (!f)
continue; continue;
data.mode = f->f_mode;
rcu_read_unlock(); rcu_read_unlock();
data.fd = fd;
len = snprintf(name, sizeof(name), "%u", fd); len = snprintf(name, sizeof(name), "%u", fd);
if (!proc_fill_cache(file, ctx, if (!proc_fill_cache(file, ctx,
name, len, instantiate, p, name, len, instantiate, p,
(void *)(unsigned long)fd)) &data))
goto out_fd_loop; goto out_fd_loop;
cond_resched(); cond_resched();
rcu_read_lock(); rcu_read_lock();
...@@ -304,31 +318,25 @@ const struct inode_operations proc_fd_inode_operations = { ...@@ -304,31 +318,25 @@ const struct inode_operations proc_fd_inode_operations = {
.setattr = proc_setattr, .setattr = proc_setattr,
}; };
static int static struct dentry *proc_fdinfo_instantiate(struct dentry *dentry,
proc_fdinfo_instantiate(struct inode *dir, struct dentry *dentry, struct task_struct *task, const void *ptr)
struct task_struct *task, const void *ptr)
{ {
unsigned fd = (unsigned long)ptr; const struct fd_data *data = ptr;
struct proc_inode *ei; struct proc_inode *ei;
struct inode *inode; struct inode *inode;
inode = proc_pid_make_inode(dir->i_sb, task, S_IFREG | S_IRUSR); inode = proc_pid_make_inode(dentry->d_sb, task, S_IFREG | S_IRUSR);
if (!inode) if (!inode)
goto out; return ERR_PTR(-ENOENT);
ei = PROC_I(inode); ei = PROC_I(inode);
ei->fd = fd; ei->fd = data->fd;
inode->i_fop = &proc_fdinfo_file_operations; inode->i_fop = &proc_fdinfo_file_operations;
tid_fd_update_inode(task, inode, 0);
d_set_d_op(dentry, &tid_fd_dentry_operations); d_set_d_op(dentry, &tid_fd_dentry_operations);
d_add(dentry, inode); return d_splice_alias(inode, dentry);
/* Close the race of the process dying before we return the dentry */
if (tid_fd_revalidate(dentry, 0))
return 0;
out:
return -ENOENT;
} }
static struct dentry * static struct dentry *
......
...@@ -257,8 +257,7 @@ struct dentry *proc_lookup_de(struct inode *dir, struct dentry *dentry, ...@@ -257,8 +257,7 @@ struct dentry *proc_lookup_de(struct inode *dir, struct dentry *dentry,
if (!inode) if (!inode)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
d_set_d_op(dentry, &proc_misc_dentry_ops); d_set_d_op(dentry, &proc_misc_dentry_ops);
d_add(dentry, inode); return d_splice_alias(inode, dentry);
return NULL;
} }
read_unlock(&proc_subdir_lock); read_unlock(&proc_subdir_lock);
return ERR_PTR(-ENOENT); return ERR_PTR(-ENOENT);
......
...@@ -152,14 +152,14 @@ extern const struct dentry_operations pid_dentry_operations; ...@@ -152,14 +152,14 @@ extern const struct dentry_operations pid_dentry_operations;
extern int pid_getattr(const struct path *, struct kstat *, u32, unsigned int); extern int pid_getattr(const struct path *, struct kstat *, u32, unsigned int);
extern int proc_setattr(struct dentry *, struct iattr *); extern int proc_setattr(struct dentry *, struct iattr *);
extern struct inode *proc_pid_make_inode(struct super_block *, struct task_struct *, umode_t); extern struct inode *proc_pid_make_inode(struct super_block *, struct task_struct *, umode_t);
extern int pid_revalidate(struct dentry *, unsigned int); extern void pid_update_inode(struct task_struct *, struct inode *);
extern int pid_delete_dentry(const struct dentry *); extern int pid_delete_dentry(const struct dentry *);
extern int proc_pid_readdir(struct file *, struct dir_context *); extern int proc_pid_readdir(struct file *, struct dir_context *);
extern struct dentry *proc_pid_lookup(struct inode *, struct dentry *, unsigned int); extern struct dentry *proc_pid_lookup(struct inode *, struct dentry *, unsigned int);
extern loff_t mem_lseek(struct file *, loff_t, int); extern loff_t mem_lseek(struct file *, loff_t, int);
/* Lookups */ /* Lookups */
typedef int instantiate_t(struct inode *, struct dentry *, typedef struct dentry *instantiate_t(struct dentry *,
struct task_struct *, const void *); struct task_struct *, const void *);
extern bool proc_fill_cache(struct file *, struct dir_context *, const char *, int, extern bool proc_fill_cache(struct file *, struct dir_context *, const char *, int,
instantiate_t, struct task_struct *, const void *); instantiate_t, struct task_struct *, const void *);
......
...@@ -87,28 +87,24 @@ static const struct inode_operations proc_ns_link_inode_operations = { ...@@ -87,28 +87,24 @@ static const struct inode_operations proc_ns_link_inode_operations = {
.setattr = proc_setattr, .setattr = proc_setattr,
}; };
static int proc_ns_instantiate(struct inode *dir, static struct dentry *proc_ns_instantiate(struct dentry *dentry,
struct dentry *dentry, struct task_struct *task, const void *ptr) struct task_struct *task, const void *ptr)
{ {
const struct proc_ns_operations *ns_ops = ptr; const struct proc_ns_operations *ns_ops = ptr;
struct inode *inode; struct inode *inode;
struct proc_inode *ei; struct proc_inode *ei;
inode = proc_pid_make_inode(dir->i_sb, task, S_IFLNK | S_IRWXUGO); inode = proc_pid_make_inode(dentry->d_sb, task, S_IFLNK | S_IRWXUGO);
if (!inode) if (!inode)
goto out; return ERR_PTR(-ENOENT);
ei = PROC_I(inode); ei = PROC_I(inode);
inode->i_op = &proc_ns_link_inode_operations; inode->i_op = &proc_ns_link_inode_operations;
ei->ns_ops = ns_ops; ei->ns_ops = ns_ops;
pid_update_inode(task, inode);
d_set_d_op(dentry, &pid_dentry_operations); d_set_d_op(dentry, &pid_dentry_operations);
d_add(dentry, inode); return d_splice_alias(inode, dentry);
/* Close the race of the process dying before we return the dentry */
if (pid_revalidate(dentry, 0))
return 0;
out:
return -ENOENT;
} }
static int proc_ns_dir_readdir(struct file *file, struct dir_context *ctx) static int proc_ns_dir_readdir(struct file *file, struct dir_context *ctx)
...@@ -147,12 +143,10 @@ const struct file_operations proc_ns_dir_operations = { ...@@ -147,12 +143,10 @@ const struct file_operations proc_ns_dir_operations = {
static struct dentry *proc_ns_dir_lookup(struct inode *dir, static struct dentry *proc_ns_dir_lookup(struct inode *dir,
struct dentry *dentry, unsigned int flags) struct dentry *dentry, unsigned int flags)
{ {
int error;
struct task_struct *task = get_proc_task(dir); struct task_struct *task = get_proc_task(dir);
const struct proc_ns_operations **entry, **last; const struct proc_ns_operations **entry, **last;
unsigned int len = dentry->d_name.len; unsigned int len = dentry->d_name.len;
struct dentry *res = ERR_PTR(-ENOENT);
error = -ENOENT;
if (!task) if (!task)
goto out_no_task; goto out_no_task;
...@@ -167,11 +161,11 @@ static struct dentry *proc_ns_dir_lookup(struct inode *dir, ...@@ -167,11 +161,11 @@ static struct dentry *proc_ns_dir_lookup(struct inode *dir,
if (entry == last) if (entry == last)
goto out; goto out;
error = proc_ns_instantiate(dir, dentry, task, *entry); res = proc_ns_instantiate(dentry, task, *entry);
out: out:
put_task_struct(task); put_task_struct(task);
out_no_task: out_no_task:
return ERR_PTR(error); return res;
} }
const struct inode_operations proc_ns_dir_inode_operations = { const struct inode_operations proc_ns_dir_inode_operations = {
......
...@@ -554,9 +554,8 @@ static struct dentry *proc_sys_lookup(struct inode *dir, struct dentry *dentry, ...@@ -554,9 +554,8 @@ static struct dentry *proc_sys_lookup(struct inode *dir, struct dentry *dentry,
if (!inode) if (!inode)
goto out; goto out;
err = NULL;
d_set_d_op(dentry, &proc_sys_dentry_operations); d_set_d_op(dentry, &proc_sys_dentry_operations);
d_add(dentry, inode); err = d_splice_alias(inode, dentry);
out: out:
if (h) if (h)
...@@ -684,6 +683,7 @@ static bool proc_sys_fill_cache(struct file *file, ...@@ -684,6 +683,7 @@ static bool proc_sys_fill_cache(struct file *file,
if (IS_ERR(child)) if (IS_ERR(child))
return false; return false;
if (d_in_lookup(child)) { if (d_in_lookup(child)) {
struct dentry *res;
inode = proc_sys_make_inode(dir->d_sb, head, table); inode = proc_sys_make_inode(dir->d_sb, head, table);
if (!inode) { if (!inode) {
d_lookup_done(child); d_lookup_done(child);
...@@ -691,7 +691,16 @@ static bool proc_sys_fill_cache(struct file *file, ...@@ -691,7 +691,16 @@ static bool proc_sys_fill_cache(struct file *file,
return false; return false;
} }
d_set_d_op(child, &proc_sys_dentry_operations); d_set_d_op(child, &proc_sys_dentry_operations);
d_add(child, inode); res = d_splice_alias(inode, child);
d_lookup_done(child);
if (unlikely(res)) {
if (IS_ERR(res)) {
dput(child);
return false;
}
dput(child);
child = res;
}
} }
} }
inode = d_inode(child); inode = d_inode(child);
......
...@@ -114,13 +114,9 @@ struct dentry * qnx4_lookup(struct inode *dir, struct dentry *dentry, unsigned i ...@@ -114,13 +114,9 @@ struct dentry * qnx4_lookup(struct inode *dir, struct dentry *dentry, unsigned i
brelse(bh); brelse(bh);
foundinode = qnx4_iget(dir->i_sb, ino); foundinode = qnx4_iget(dir->i_sb, ino);
if (IS_ERR(foundinode)) { if (IS_ERR(foundinode))
QNX4DEBUG((KERN_ERR "qnx4: lookup->iget -> error %ld\n", QNX4DEBUG((KERN_ERR "qnx4: lookup->iget -> error %ld\n",
PTR_ERR(foundinode))); PTR_ERR(foundinode)));
return ERR_CAST(foundinode);
}
out: out:
d_add(dentry, foundinode); return d_splice_alias(foundinode, dentry);
return NULL;
} }
...@@ -29,15 +29,11 @@ struct dentry *qnx6_lookup(struct inode *dir, struct dentry *dentry, ...@@ -29,15 +29,11 @@ struct dentry *qnx6_lookup(struct inode *dir, struct dentry *dentry,
if (ino) { if (ino) {
foundinode = qnx6_iget(dir->i_sb, ino); foundinode = qnx6_iget(dir->i_sb, ino);
qnx6_put_page(page); qnx6_put_page(page);
if (IS_ERR(foundinode)) { if (IS_ERR(foundinode))
pr_debug("lookup->iget -> error %ld\n", pr_debug("lookup->iget -> error %ld\n",
PTR_ERR(foundinode)); PTR_ERR(foundinode));
return ERR_CAST(foundinode);
}
} else { } else {
pr_debug("%s(): not found %s\n", __func__, name); pr_debug("%s(): not found %s\n", __func__, name);
return NULL;
} }
d_add(dentry, foundinode); return d_splice_alias(foundinode, dentry);
return NULL;
} }
...@@ -213,7 +213,7 @@ static struct dentry *romfs_lookup(struct inode *dir, struct dentry *dentry, ...@@ -213,7 +213,7 @@ static struct dentry *romfs_lookup(struct inode *dir, struct dentry *dentry,
unsigned int flags) unsigned int flags)
{ {
unsigned long offset, maxoff; unsigned long offset, maxoff;
struct inode *inode; struct inode *inode = NULL;
struct romfs_inode ri; struct romfs_inode ri;
const char *name; /* got from dentry */ const char *name; /* got from dentry */
int len, ret; int len, ret;
...@@ -233,7 +233,7 @@ static struct dentry *romfs_lookup(struct inode *dir, struct dentry *dentry, ...@@ -233,7 +233,7 @@ static struct dentry *romfs_lookup(struct inode *dir, struct dentry *dentry,
for (;;) { for (;;) {
if (!offset || offset >= maxoff) if (!offset || offset >= maxoff)
goto out0; break;
ret = romfs_dev_read(dir->i_sb, offset, &ri, sizeof(ri)); ret = romfs_dev_read(dir->i_sb, offset, &ri, sizeof(ri));
if (ret < 0) if (ret < 0)
...@@ -244,37 +244,19 @@ static struct dentry *romfs_lookup(struct inode *dir, struct dentry *dentry, ...@@ -244,37 +244,19 @@ static struct dentry *romfs_lookup(struct inode *dir, struct dentry *dentry,
len); len);
if (ret < 0) if (ret < 0)
goto error; goto error;
if (ret == 1) if (ret == 1) {
/* Hard link handling */
if ((be32_to_cpu(ri.next) & ROMFH_TYPE) == ROMFH_HRD)
offset = be32_to_cpu(ri.spec) & ROMFH_MASK;
inode = romfs_iget(dir->i_sb, offset);
break; break;
}
/* next entry */ /* next entry */
offset = be32_to_cpu(ri.next) & ROMFH_MASK; offset = be32_to_cpu(ri.next) & ROMFH_MASK;
} }
/* Hard link handling */ return d_splice_alias(inode, dentry);
if ((be32_to_cpu(ri.next) & ROMFH_TYPE) == ROMFH_HRD)
offset = be32_to_cpu(ri.spec) & ROMFH_MASK;
inode = romfs_iget(dir->i_sb, offset);
if (IS_ERR(inode)) {
ret = PTR_ERR(inode);
goto error;
}
goto outi;
/*
* it's a bit funky, _lookup needs to return an error code
* (negative) or a NULL, both as a dentry. ENOENT should not
* be returned, instead we need to create a negative dentry by
* d_add(dentry, NULL); and return 0 as no error.
* (Although as I see, it only matters on writable file
* systems).
*/
out0:
inode = NULL;
outi:
d_add(dentry, inode);
ret = 0;
error: error:
return ERR_PTR(ret); return ERR_PTR(ret);
} }
......
...@@ -51,14 +51,9 @@ static struct dentry *sysv_lookup(struct inode * dir, struct dentry * dentry, un ...@@ -51,14 +51,9 @@ static struct dentry *sysv_lookup(struct inode * dir, struct dentry * dentry, un
if (dentry->d_name.len > SYSV_NAMELEN) if (dentry->d_name.len > SYSV_NAMELEN)
return ERR_PTR(-ENAMETOOLONG); return ERR_PTR(-ENAMETOOLONG);
ino = sysv_inode_by_name(dentry); ino = sysv_inode_by_name(dentry);
if (ino)
if (ino) {
inode = sysv_iget(dir->i_sb, ino); inode = sysv_iget(dir->i_sb, ino);
if (IS_ERR(inode)) return d_splice_alias(inode, dentry);
return ERR_CAST(inode);
}
d_add(dentry, inode);
return NULL;
} }
static int sysv_mknod(struct inode * dir, struct dentry * dentry, umode_t mode, dev_t rdev) static int sysv_mknod(struct inode * dir, struct dentry * dentry, umode_t mode, dev_t rdev)
......
...@@ -214,7 +214,7 @@ static struct dentry *ubifs_lookup(struct inode *dir, struct dentry *dentry, ...@@ -214,7 +214,7 @@ static struct dentry *ubifs_lookup(struct inode *dir, struct dentry *dentry,
int err; int err;
union ubifs_key key; union ubifs_key key;
struct inode *inode = NULL; struct inode *inode = NULL;
struct ubifs_dent_node *dent; struct ubifs_dent_node *dent = NULL;
struct ubifs_info *c = dir->i_sb->s_fs_info; struct ubifs_info *c = dir->i_sb->s_fs_info;
struct fscrypt_name nm; struct fscrypt_name nm;
...@@ -229,14 +229,14 @@ static struct dentry *ubifs_lookup(struct inode *dir, struct dentry *dentry, ...@@ -229,14 +229,14 @@ static struct dentry *ubifs_lookup(struct inode *dir, struct dentry *dentry,
return ERR_PTR(err); return ERR_PTR(err);
if (fname_len(&nm) > UBIFS_MAX_NLEN) { if (fname_len(&nm) > UBIFS_MAX_NLEN) {
err = -ENAMETOOLONG; inode = ERR_PTR(-ENAMETOOLONG);
goto out_fname; goto done;
} }
dent = kmalloc(UBIFS_MAX_DENT_NODE_SZ, GFP_NOFS); dent = kmalloc(UBIFS_MAX_DENT_NODE_SZ, GFP_NOFS);
if (!dent) { if (!dent) {
err = -ENOMEM; inode = ERR_PTR(-ENOMEM);
goto out_fname; goto done;
} }
if (nm.hash) { if (nm.hash) {
...@@ -250,16 +250,16 @@ static struct dentry *ubifs_lookup(struct inode *dir, struct dentry *dentry, ...@@ -250,16 +250,16 @@ static struct dentry *ubifs_lookup(struct inode *dir, struct dentry *dentry,
} }
if (err) { if (err) {
if (err == -ENOENT) { if (err == -ENOENT)
dbg_gen("not found"); dbg_gen("not found");
goto done; else
} inode = ERR_PTR(err);
goto out_dent; goto done;
} }
if (dbg_check_name(c, dent, &nm)) { if (dbg_check_name(c, dent, &nm)) {
err = -EINVAL; inode = ERR_PTR(-EINVAL);
goto out_dent; goto done;
} }
inode = ubifs_iget(dir->i_sb, le64_to_cpu(dent->inum)); inode = ubifs_iget(dir->i_sb, le64_to_cpu(dent->inum));
...@@ -272,7 +272,7 @@ static struct dentry *ubifs_lookup(struct inode *dir, struct dentry *dentry, ...@@ -272,7 +272,7 @@ static struct dentry *ubifs_lookup(struct inode *dir, struct dentry *dentry,
ubifs_err(c, "dead directory entry '%pd', error %d", ubifs_err(c, "dead directory entry '%pd', error %d",
dentry, err); dentry, err);
ubifs_ro_mode(c, err); ubifs_ro_mode(c, err);
goto out_dent; goto done;
} }
if (ubifs_crypt_is_encrypted(dir) && if (ubifs_crypt_is_encrypted(dir) &&
...@@ -280,27 +280,14 @@ static struct dentry *ubifs_lookup(struct inode *dir, struct dentry *dentry, ...@@ -280,27 +280,14 @@ static struct dentry *ubifs_lookup(struct inode *dir, struct dentry *dentry,
!fscrypt_has_permitted_context(dir, inode)) { !fscrypt_has_permitted_context(dir, inode)) {
ubifs_warn(c, "Inconsistent encryption contexts: %lu/%lu", ubifs_warn(c, "Inconsistent encryption contexts: %lu/%lu",
dir->i_ino, inode->i_ino); dir->i_ino, inode->i_ino);
err = -EPERM; iput(inode);
goto out_inode; inode = ERR_PTR(-EPERM);
} }
done: done:
kfree(dent); kfree(dent);
fscrypt_free_filename(&nm); fscrypt_free_filename(&nm);
/* return d_splice_alias(inode, dentry);
* Note, d_splice_alias() would be required instead if we supported
* NFS.
*/
d_add(dentry, inode);
return NULL;
out_inode:
iput(inode);
out_dent:
kfree(dent);
out_fname:
fscrypt_free_filename(&nm);
return ERR_PTR(err);
} }
static int ubifs_create(struct inode *dir, struct dentry *dentry, umode_t mode, static int ubifs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
......
...@@ -260,6 +260,7 @@ xfs_vn_lookup( ...@@ -260,6 +260,7 @@ xfs_vn_lookup(
struct dentry *dentry, struct dentry *dentry,
unsigned int flags) unsigned int flags)
{ {
struct inode *inode;
struct xfs_inode *cip; struct xfs_inode *cip;
struct xfs_name name; struct xfs_name name;
int error; int error;
...@@ -269,14 +270,13 @@ xfs_vn_lookup( ...@@ -269,14 +270,13 @@ xfs_vn_lookup(
xfs_dentry_to_name(&name, dentry); xfs_dentry_to_name(&name, dentry);
error = xfs_lookup(XFS_I(dir), &name, &cip, NULL); error = xfs_lookup(XFS_I(dir), &name, &cip, NULL);
if (unlikely(error)) { if (likely(!error))
if (unlikely(error != -ENOENT)) inode = VFS_I(cip);
return ERR_PTR(error); else if (likely(error == -ENOENT))
d_add(dentry, NULL); inode = NULL;
return NULL; else
} inode = ERR_PTR(error);
return d_splice_alias(inode, dentry);
return d_splice_alias(VFS_I(cip), dentry);
} }
STATIC struct dentry * STATIC struct dentry *
......
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