Commit 6a3124a3 authored by Latchesar Ionkov's avatar Latchesar Ionkov Committed by Linus Torvalds

[PATCH] v9fs: fix atomic create open

In order to assure atomic create+open v9fs stores the open fid produced by
v9fs_vfs_create in the dentry, from where v9fs_file_open retrieves it and
associates it with the open file.

This patch modifies v9fs to use nameidata.intent.open values to do the atomic
create+open.
Signed-off-by: default avatarLatchesar Ionkov <lucho@ionkov.net>
Signed-off-by: default avatarEric Van Hensbergen <ericvh@gmail.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 77a33135
...@@ -40,7 +40,7 @@ ...@@ -40,7 +40,7 @@
* *
*/ */
static int v9fs_fid_insert(struct v9fs_fid *fid, struct dentry *dentry) int v9fs_fid_insert(struct v9fs_fid *fid, struct dentry *dentry)
{ {
struct list_head *fid_list = (struct list_head *)dentry->d_fsdata; struct list_head *fid_list = (struct list_head *)dentry->d_fsdata;
dprintk(DEBUG_9P, "fid %d (%p) dentry %s (%p)\n", fid->fid, fid, dprintk(DEBUG_9P, "fid %d (%p) dentry %s (%p)\n", fid->fid, fid,
...@@ -68,14 +68,11 @@ static int v9fs_fid_insert(struct v9fs_fid *fid, struct dentry *dentry) ...@@ -68,14 +68,11 @@ static int v9fs_fid_insert(struct v9fs_fid *fid, struct dentry *dentry)
* *
*/ */
struct v9fs_fid *v9fs_fid_create(struct dentry *dentry, struct v9fs_fid *v9fs_fid_create(struct v9fs_session_info *v9ses, int fid)
struct v9fs_session_info *v9ses, int fid, int create)
{ {
struct v9fs_fid *new; struct v9fs_fid *new;
dprintk(DEBUG_9P, "fid create dentry %p, fid %d, create %d\n", dprintk(DEBUG_9P, "fid create fid %d\n", fid);
dentry, fid, create);
new = kmalloc(sizeof(struct v9fs_fid), GFP_KERNEL); new = kmalloc(sizeof(struct v9fs_fid), GFP_KERNEL);
if (new == NULL) { if (new == NULL) {
dprintk(DEBUG_ERROR, "Out of Memory\n"); dprintk(DEBUG_ERROR, "Out of Memory\n");
...@@ -85,19 +82,13 @@ struct v9fs_fid *v9fs_fid_create(struct dentry *dentry, ...@@ -85,19 +82,13 @@ struct v9fs_fid *v9fs_fid_create(struct dentry *dentry,
new->fid = fid; new->fid = fid;
new->v9ses = v9ses; new->v9ses = v9ses;
new->fidopen = 0; new->fidopen = 0;
new->fidcreate = create;
new->fidclunked = 0; new->fidclunked = 0;
new->iounit = 0; new->iounit = 0;
new->rdir_pos = 0; new->rdir_pos = 0;
new->rdir_fcall = NULL; new->rdir_fcall = NULL;
INIT_LIST_HEAD(&new->list);
if (v9fs_fid_insert(new, dentry) == 0)
return new; return new;
else {
dprintk(DEBUG_ERROR, "Problems inserting to dentry\n");
kfree(new);
return NULL;
}
} }
/** /**
...@@ -119,7 +110,7 @@ void v9fs_fid_destroy(struct v9fs_fid *fid) ...@@ -119,7 +110,7 @@ void v9fs_fid_destroy(struct v9fs_fid *fid)
static struct v9fs_fid *v9fs_fid_walk_up(struct dentry *dentry) static struct v9fs_fid *v9fs_fid_walk_up(struct dentry *dentry)
{ {
int fidnum, cfidnum, err; int fidnum, cfidnum, err;
struct v9fs_fid *cfid; struct v9fs_fid *cfid, *fid;
struct dentry *cde; struct dentry *cde;
struct v9fs_session_info *v9ses; struct v9fs_session_info *v9ses;
...@@ -158,7 +149,16 @@ static struct v9fs_fid *v9fs_fid_walk_up(struct dentry *dentry) ...@@ -158,7 +149,16 @@ static struct v9fs_fid *v9fs_fid_walk_up(struct dentry *dentry)
cde = cde->d_parent; cde = cde->d_parent;
} }
return v9fs_fid_create(dentry, v9ses, fidnum, 0); fid = v9fs_fid_create(v9ses, fidnum);
if (fid) {
err = v9fs_fid_insert(fid, dentry);
if (err < 0) {
kfree(fid);
goto clunk_fid;
}
}
return fid;
clunk_fid: clunk_fid:
v9fs_t_clunk(v9ses, fidnum); v9fs_t_clunk(v9ses, fidnum);
...@@ -179,29 +179,12 @@ static struct v9fs_fid *v9fs_fid_walk_up(struct dentry *dentry) ...@@ -179,29 +179,12 @@ static struct v9fs_fid *v9fs_fid_walk_up(struct dentry *dentry)
struct v9fs_fid *v9fs_fid_lookup(struct dentry *dentry) struct v9fs_fid *v9fs_fid_lookup(struct dentry *dentry)
{ {
struct list_head *fid_list = (struct list_head *)dentry->d_fsdata; struct list_head *fid_list = (struct list_head *)dentry->d_fsdata;
struct v9fs_fid *current_fid = NULL;
struct v9fs_fid *temp = NULL;
struct v9fs_fid *return_fid = NULL; struct v9fs_fid *return_fid = NULL;
dprintk(DEBUG_9P, " dentry: %s (%p)\n", dentry->d_iname, dentry); dprintk(DEBUG_9P, " dentry: %s (%p)\n", dentry->d_iname, dentry);
if (fid_list) { if (fid_list)
list_for_each_entry_safe(current_fid, temp, fid_list, list) { return_fid = list_entry(fid_list->next, struct v9fs_fid, list);
if (!current_fid->fidcreate) {
return_fid = current_fid;
break;
}
}
if (!return_fid)
return_fid = current_fid;
}
/* we are at the root but didn't match */
if ((!return_fid) && (dentry->d_parent == dentry)) {
/* TODO: clone attach with new uid */
return_fid = current_fid;
}
if (!return_fid) { if (!return_fid) {
struct dentry *par = current->fs->pwd->d_parent; struct dentry *par = current->fs->pwd->d_parent;
...@@ -228,25 +211,3 @@ struct v9fs_fid *v9fs_fid_lookup(struct dentry *dentry) ...@@ -228,25 +211,3 @@ struct v9fs_fid *v9fs_fid_lookup(struct dentry *dentry)
return return_fid; return return_fid;
} }
struct v9fs_fid *v9fs_fid_get_created(struct dentry *dentry)
{
struct list_head *fid_list;
struct v9fs_fid *fid, *ftmp, *ret;
dprintk(DEBUG_9P, " dentry: %s (%p)\n", dentry->d_iname, dentry);
fid_list = (struct list_head *)dentry->d_fsdata;
ret = NULL;
if (fid_list) {
list_for_each_entry_safe(fid, ftmp, fid_list, list) {
if (fid->fidcreate && fid->pid == current->pid) {
list_del(&fid->list);
ret = fid;
break;
}
}
}
dprintk(DEBUG_9P, "return %p\n", ret);
return ret;
}
...@@ -33,7 +33,6 @@ struct v9fs_fid { ...@@ -33,7 +33,6 @@ struct v9fs_fid {
u32 fid; u32 fid;
unsigned char fidopen; /* set when fid is opened */ unsigned char fidopen; /* set when fid is opened */
unsigned char fidcreate; /* set when fid was just created */
unsigned char fidclunked; /* set when fid has already been clunked */ unsigned char fidclunked; /* set when fid has already been clunked */
struct v9fs_qid qid; struct v9fs_qid qid;
...@@ -56,5 +55,5 @@ struct v9fs_fid { ...@@ -56,5 +55,5 @@ struct v9fs_fid {
struct v9fs_fid *v9fs_fid_lookup(struct dentry *dentry); struct v9fs_fid *v9fs_fid_lookup(struct dentry *dentry);
struct v9fs_fid *v9fs_fid_get_created(struct dentry *); struct v9fs_fid *v9fs_fid_get_created(struct dentry *);
void v9fs_fid_destroy(struct v9fs_fid *fid); void v9fs_fid_destroy(struct v9fs_fid *fid);
struct v9fs_fid *v9fs_fid_create(struct dentry *, struct v9fs_fid *v9fs_fid_create(struct v9fs_session_info *, int fid);
struct v9fs_session_info *v9ses, int fid, int create); int v9fs_fid_insert(struct v9fs_fid *fid, struct dentry *dentry);
...@@ -51,3 +51,4 @@ int v9fs_dir_release(struct inode *inode, struct file *filp); ...@@ -51,3 +51,4 @@ int v9fs_dir_release(struct inode *inode, struct file *filp);
int v9fs_file_open(struct inode *inode, struct file *file); int v9fs_file_open(struct inode *inode, struct file *file);
void v9fs_inode2stat(struct inode *inode, struct v9fs_stat *stat); void v9fs_inode2stat(struct inode *inode, struct v9fs_stat *stat);
void v9fs_dentry_release(struct dentry *); void v9fs_dentry_release(struct dentry *);
int v9fs_uflags2omode(int uflags);
...@@ -53,94 +53,70 @@ ...@@ -53,94 +53,70 @@
int v9fs_file_open(struct inode *inode, struct file *file) int v9fs_file_open(struct inode *inode, struct file *file)
{ {
struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode); struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode);
struct v9fs_fid *v9fid, *fid; struct v9fs_fid *vfid;
struct v9fs_fcall *fcall = NULL; struct v9fs_fcall *fcall = NULL;
int open_mode = 0; int omode;
unsigned int iounit = 0; int fid = V9FS_NOFID;
int newfid = -1; int err;
long result = -1;
dprintk(DEBUG_VFS, "inode: %p file: %p \n", inode, file); dprintk(DEBUG_VFS, "inode: %p file: %p \n", inode, file);
v9fid = v9fs_fid_get_created(file->f_dentry); vfid = v9fs_fid_lookup(file->f_dentry);
if (!v9fid) if (!vfid) {
v9fid = v9fs_fid_lookup(file->f_dentry);
if (!v9fid) {
dprintk(DEBUG_ERROR, "Couldn't resolve fid from dentry\n"); dprintk(DEBUG_ERROR, "Couldn't resolve fid from dentry\n");
return -EBADF; return -EBADF;
} }
if (!v9fid->fidcreate) { fid = v9fs_get_idpool(&v9ses->fidpool);
fid = kmalloc(sizeof(struct v9fs_fid), GFP_KERNEL); if (fid < 0) {
if (fid == NULL) {
dprintk(DEBUG_ERROR, "Out of Memory\n");
return -ENOMEM;
}
fid->fidopen = 0;
fid->fidcreate = 0;
fid->fidclunked = 0;
fid->iounit = 0;
fid->v9ses = v9ses;
newfid = v9fs_get_idpool(&v9ses->fidpool);
if (newfid < 0) {
eprintk(KERN_WARNING, "newfid fails!\n"); eprintk(KERN_WARNING, "newfid fails!\n");
return -ENOSPC; return -ENOSPC;
} }
result = err = v9fs_t_walk(v9ses, vfid->fid, fid, NULL, NULL);
v9fs_t_walk(v9ses, v9fid->fid, newfid, NULL, NULL); if (err < 0) {
if (result < 0) {
v9fs_put_idpool(newfid, &v9ses->fidpool);
dprintk(DEBUG_ERROR, "rewalk didn't work\n"); dprintk(DEBUG_ERROR, "rewalk didn't work\n");
return -EBADF; goto put_fid;
}
vfid = kmalloc(sizeof(struct v9fs_fid), GFP_KERNEL);
if (vfid == NULL) {
dprintk(DEBUG_ERROR, "out of memory\n");
goto clunk_fid;
} }
fid->fid = newfid;
v9fid = fid;
/* TODO: do special things for O_EXCL, O_NOFOLLOW, O_SYNC */ /* TODO: do special things for O_EXCL, O_NOFOLLOW, O_SYNC */
/* translate open mode appropriately */ /* translate open mode appropriately */
open_mode = file->f_flags & 0x3; omode = v9fs_uflags2omode(file->f_flags);
err = v9fs_t_open(v9ses, fid, omode, &fcall);
if (err < 0) {
PRINT_FCALL_ERROR("open failed", fcall);
goto destroy_vfid;
}
if (file->f_flags & O_EXCL) file->private_data = vfid;
open_mode |= V9FS_OEXCL; vfid->fid = fid;
vfid->fidopen = 1;
vfid->fidclunked = 0;
vfid->iounit = fcall->params.ropen.iounit;
vfid->rdir_pos = 0;
vfid->rdir_fcall = NULL;
vfid->filp = file;
kfree(fcall);
if (v9ses->extended) { return 0;
if (file->f_flags & O_TRUNC)
open_mode |= V9FS_OTRUNC;
if (file->f_flags & O_APPEND) destroy_vfid:
open_mode |= V9FS_OAPPEND; v9fs_fid_destroy(vfid);
}
result = v9fs_t_open(v9ses, newfid, open_mode, &fcall); clunk_fid:
if (result < 0) { v9fs_t_clunk(v9ses, fid);
PRINT_FCALL_ERROR("open failed", fcall);
kfree(fcall);
return result;
}
iounit = fcall->params.ropen.iounit; put_fid:
v9fs_put_idpool(fid, &v9ses->fidpool);
kfree(fcall); kfree(fcall);
} else {
/* create case */
newfid = v9fid->fid;
iounit = v9fid->iounit;
v9fid->fidcreate = 0;
}
file->private_data = v9fid;
v9fid->rdir_pos = 0;
v9fid->rdir_fcall = NULL;
v9fid->fidopen = 1;
v9fid->filp = file;
v9fid->iounit = iounit;
return 0; return err;
} }
/** /**
...@@ -289,9 +265,7 @@ v9fs_file_write(struct file *filp, const char __user * data, ...@@ -289,9 +265,7 @@ v9fs_file_write(struct file *filp, const char __user * data,
total += result; total += result;
} while (count); } while (count);
if(inode->i_mapping->nrpages)
invalidate_inode_pages2(inode->i_mapping); invalidate_inode_pages2(inode->i_mapping);
return total; return total;
} }
......
This diff is collapsed.
...@@ -146,7 +146,6 @@ static struct super_block *v9fs_get_sb(struct file_system_type ...@@ -146,7 +146,6 @@ static struct super_block *v9fs_get_sb(struct file_system_type
inode->i_gid = gid; inode->i_gid = gid;
root = d_alloc_root(inode); root = d_alloc_root(inode);
if (!root) { if (!root) {
retval = -ENOMEM; retval = -ENOMEM;
goto put_back_sb; goto put_back_sb;
...@@ -157,24 +156,27 @@ static struct super_block *v9fs_get_sb(struct file_system_type ...@@ -157,24 +156,27 @@ static struct super_block *v9fs_get_sb(struct file_system_type
stat_result = v9fs_t_stat(v9ses, newfid, &fcall); stat_result = v9fs_t_stat(v9ses, newfid, &fcall);
if (stat_result < 0) { if (stat_result < 0) {
dprintk(DEBUG_ERROR, "stat error\n"); dprintk(DEBUG_ERROR, "stat error\n");
kfree(fcall);
v9fs_t_clunk(v9ses, newfid); v9fs_t_clunk(v9ses, newfid);
v9fs_put_idpool(newfid, &v9ses->fidpool);
} else { } else {
/* Setup the Root Inode */ /* Setup the Root Inode */
root_fid = v9fs_fid_create(root, v9ses, newfid, 0); kfree(fcall);
root_fid = v9fs_fid_create(v9ses, newfid);
if (root_fid == NULL) { if (root_fid == NULL) {
retval = -ENOMEM; retval = -ENOMEM;
goto put_back_sb; goto put_back_sb;
} }
retval = v9fs_fid_insert(root_fid, root);
if (retval < 0)
goto put_back_sb;
root_fid->qid = fcall->params.rstat.stat.qid; root_fid->qid = fcall->params.rstat.stat.qid;
root->d_inode->i_ino = root->d_inode->i_ino =
v9fs_qid2ino(&fcall->params.rstat.stat.qid); v9fs_qid2ino(&fcall->params.rstat.stat.qid);
v9fs_stat2inode(&fcall->params.rstat.stat, root->d_inode, sb); v9fs_stat2inode(&fcall->params.rstat.stat, root->d_inode, sb);
} }
kfree(fcall);
if (stat_result < 0) { if (stat_result < 0) {
retval = stat_result; retval = stat_result;
goto put_back_sb; goto put_back_sb;
......
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