Commit 28c51ee3 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://github.com/ericvh/linux

* 'for-linus' of git://github.com/ericvh/linux:
  fs/9p: Use protocol-defined value for lock/getlock 'type' field.
  fs/9p: Always ask new inode in lookup for cache mode disabled
  fs/9p: Add OS dependent open flags in 9p protocol
  net/9p: Fix kernel crash with msize 512K
  fs/9p: Don't update file type when updating file attributes
  fs/9p: Add fid before dentry instantiation
parents 11545267 51b8b4fb
...@@ -54,9 +54,9 @@ extern struct kmem_cache *v9fs_inode_cache; ...@@ -54,9 +54,9 @@ extern struct kmem_cache *v9fs_inode_cache;
struct inode *v9fs_alloc_inode(struct super_block *sb); struct inode *v9fs_alloc_inode(struct super_block *sb);
void v9fs_destroy_inode(struct inode *inode); void v9fs_destroy_inode(struct inode *inode);
struct inode *v9fs_get_inode(struct super_block *sb, int mode); struct inode *v9fs_get_inode(struct super_block *sb, int mode, dev_t);
int v9fs_init_inode(struct v9fs_session_info *v9ses, int v9fs_init_inode(struct v9fs_session_info *v9ses,
struct inode *inode, int mode); struct inode *inode, int mode, dev_t);
void v9fs_evict_inode(struct inode *inode); void v9fs_evict_inode(struct inode *inode);
ino_t v9fs_qid2ino(struct p9_qid *qid); ino_t v9fs_qid2ino(struct p9_qid *qid);
void v9fs_stat2inode(struct p9_wstat *, struct inode *, struct super_block *); void v9fs_stat2inode(struct p9_wstat *, struct inode *, struct super_block *);
...@@ -83,4 +83,6 @@ static inline void v9fs_invalidate_inode_attr(struct inode *inode) ...@@ -83,4 +83,6 @@ static inline void v9fs_invalidate_inode_attr(struct inode *inode)
v9inode->cache_validity |= V9FS_INO_INVALID_ATTR; v9inode->cache_validity |= V9FS_INO_INVALID_ATTR;
return; return;
} }
int v9fs_open_to_dotl_flags(int flags);
#endif #endif
...@@ -65,7 +65,7 @@ int v9fs_file_open(struct inode *inode, struct file *file) ...@@ -65,7 +65,7 @@ int v9fs_file_open(struct inode *inode, struct file *file)
v9inode = V9FS_I(inode); v9inode = V9FS_I(inode);
v9ses = v9fs_inode2v9ses(inode); v9ses = v9fs_inode2v9ses(inode);
if (v9fs_proto_dotl(v9ses)) if (v9fs_proto_dotl(v9ses))
omode = file->f_flags; omode = v9fs_open_to_dotl_flags(file->f_flags);
else else
omode = v9fs_uflags2omode(file->f_flags, omode = v9fs_uflags2omode(file->f_flags,
v9fs_proto_dotu(v9ses)); v9fs_proto_dotu(v9ses));
...@@ -169,7 +169,18 @@ static int v9fs_file_do_lock(struct file *filp, int cmd, struct file_lock *fl) ...@@ -169,7 +169,18 @@ static int v9fs_file_do_lock(struct file *filp, int cmd, struct file_lock *fl)
/* convert posix lock to p9 tlock args */ /* convert posix lock to p9 tlock args */
memset(&flock, 0, sizeof(flock)); memset(&flock, 0, sizeof(flock));
flock.type = fl->fl_type; /* map the lock type */
switch (fl->fl_type) {
case F_RDLCK:
flock.type = P9_LOCK_TYPE_RDLCK;
break;
case F_WRLCK:
flock.type = P9_LOCK_TYPE_WRLCK;
break;
case F_UNLCK:
flock.type = P9_LOCK_TYPE_UNLCK;
break;
}
flock.start = fl->fl_start; flock.start = fl->fl_start;
if (fl->fl_end == OFFSET_MAX) if (fl->fl_end == OFFSET_MAX)
flock.length = 0; flock.length = 0;
...@@ -245,7 +256,7 @@ static int v9fs_file_getlock(struct file *filp, struct file_lock *fl) ...@@ -245,7 +256,7 @@ static int v9fs_file_getlock(struct file *filp, struct file_lock *fl)
/* convert posix lock to p9 tgetlock args */ /* convert posix lock to p9 tgetlock args */
memset(&glock, 0, sizeof(glock)); memset(&glock, 0, sizeof(glock));
glock.type = fl->fl_type; glock.type = P9_LOCK_TYPE_UNLCK;
glock.start = fl->fl_start; glock.start = fl->fl_start;
if (fl->fl_end == OFFSET_MAX) if (fl->fl_end == OFFSET_MAX)
glock.length = 0; glock.length = 0;
...@@ -257,17 +268,26 @@ static int v9fs_file_getlock(struct file *filp, struct file_lock *fl) ...@@ -257,17 +268,26 @@ static int v9fs_file_getlock(struct file *filp, struct file_lock *fl)
res = p9_client_getlock_dotl(fid, &glock); res = p9_client_getlock_dotl(fid, &glock);
if (res < 0) if (res < 0)
return res; return res;
if (glock.type != F_UNLCK) { /* map 9p lock type to os lock type */
fl->fl_type = glock.type; switch (glock.type) {
case P9_LOCK_TYPE_RDLCK:
fl->fl_type = F_RDLCK;
break;
case P9_LOCK_TYPE_WRLCK:
fl->fl_type = F_WRLCK;
break;
case P9_LOCK_TYPE_UNLCK:
fl->fl_type = F_UNLCK;
break;
}
if (glock.type != P9_LOCK_TYPE_UNLCK) {
fl->fl_start = glock.start; fl->fl_start = glock.start;
if (glock.length == 0) if (glock.length == 0)
fl->fl_end = OFFSET_MAX; fl->fl_end = OFFSET_MAX;
else else
fl->fl_end = glock.start + glock.length - 1; fl->fl_end = glock.start + glock.length - 1;
fl->fl_pid = glock.proc_id; fl->fl_pid = glock.proc_id;
} else }
fl->fl_type = F_UNLCK;
return res; return res;
} }
......
...@@ -95,15 +95,18 @@ static int unixmode2p9mode(struct v9fs_session_info *v9ses, int mode) ...@@ -95,15 +95,18 @@ static int unixmode2p9mode(struct v9fs_session_info *v9ses, int mode)
/** /**
* p9mode2unixmode- convert plan9 mode bits to unix mode bits * p9mode2unixmode- convert plan9 mode bits to unix mode bits
* @v9ses: v9fs session information * @v9ses: v9fs session information
* @mode: mode to convert * @stat: p9_wstat from which mode need to be derived
* @rdev: major number, minor number in case of device files.
* *
*/ */
static int p9mode2unixmode(struct v9fs_session_info *v9ses,
static int p9mode2unixmode(struct v9fs_session_info *v9ses, int mode) struct p9_wstat *stat, dev_t *rdev)
{ {
int res; int res;
int mode = stat->mode;
res = mode & 0777; res = mode & S_IALLUGO;
*rdev = 0;
if ((mode & P9_DMDIR) == P9_DMDIR) if ((mode & P9_DMDIR) == P9_DMDIR)
res |= S_IFDIR; res |= S_IFDIR;
...@@ -116,9 +119,26 @@ static int p9mode2unixmode(struct v9fs_session_info *v9ses, int mode) ...@@ -116,9 +119,26 @@ static int p9mode2unixmode(struct v9fs_session_info *v9ses, int mode)
&& (v9ses->nodev == 0)) && (v9ses->nodev == 0))
res |= S_IFIFO; res |= S_IFIFO;
else if ((mode & P9_DMDEVICE) && (v9fs_proto_dotu(v9ses)) else if ((mode & P9_DMDEVICE) && (v9fs_proto_dotu(v9ses))
&& (v9ses->nodev == 0)) && (v9ses->nodev == 0)) {
res |= S_IFBLK; char type = 0, ext[32];
else int major = -1, minor = -1;
strncpy(ext, stat->extension, sizeof(ext));
sscanf(ext, "%c %u %u", &type, &major, &minor);
switch (type) {
case 'c':
res |= S_IFCHR;
break;
case 'b':
res |= S_IFBLK;
break;
default:
P9_DPRINTK(P9_DEBUG_ERROR,
"Unknown special type %c %s\n", type,
stat->extension);
};
*rdev = MKDEV(major, minor);
} else
res |= S_IFREG; res |= S_IFREG;
if (v9fs_proto_dotu(v9ses)) { if (v9fs_proto_dotu(v9ses)) {
...@@ -131,7 +151,6 @@ static int p9mode2unixmode(struct v9fs_session_info *v9ses, int mode) ...@@ -131,7 +151,6 @@ static int p9mode2unixmode(struct v9fs_session_info *v9ses, int mode)
if ((mode & P9_DMSETVTX) == P9_DMSETVTX) if ((mode & P9_DMSETVTX) == P9_DMSETVTX)
res |= S_ISVTX; res |= S_ISVTX;
} }
return res; return res;
} }
...@@ -242,13 +261,13 @@ void v9fs_destroy_inode(struct inode *inode) ...@@ -242,13 +261,13 @@ void v9fs_destroy_inode(struct inode *inode)
} }
int v9fs_init_inode(struct v9fs_session_info *v9ses, int v9fs_init_inode(struct v9fs_session_info *v9ses,
struct inode *inode, int mode) struct inode *inode, int mode, dev_t rdev)
{ {
int err = 0; int err = 0;
inode_init_owner(inode, NULL, mode); inode_init_owner(inode, NULL, mode);
inode->i_blocks = 0; inode->i_blocks = 0;
inode->i_rdev = 0; inode->i_rdev = rdev;
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
inode->i_mapping->a_ops = &v9fs_addr_operations; inode->i_mapping->a_ops = &v9fs_addr_operations;
...@@ -335,7 +354,7 @@ int v9fs_init_inode(struct v9fs_session_info *v9ses, ...@@ -335,7 +354,7 @@ int v9fs_init_inode(struct v9fs_session_info *v9ses,
* *
*/ */
struct inode *v9fs_get_inode(struct super_block *sb, int mode) struct inode *v9fs_get_inode(struct super_block *sb, int mode, dev_t rdev)
{ {
int err; int err;
struct inode *inode; struct inode *inode;
...@@ -348,7 +367,7 @@ struct inode *v9fs_get_inode(struct super_block *sb, int mode) ...@@ -348,7 +367,7 @@ struct inode *v9fs_get_inode(struct super_block *sb, int mode)
P9_EPRINTK(KERN_WARNING, "Problem allocating inode\n"); P9_EPRINTK(KERN_WARNING, "Problem allocating inode\n");
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
} }
err = v9fs_init_inode(v9ses, inode, mode); err = v9fs_init_inode(v9ses, inode, mode, rdev);
if (err) { if (err) {
iput(inode); iput(inode);
return ERR_PTR(err); return ERR_PTR(err);
...@@ -435,11 +454,12 @@ void v9fs_evict_inode(struct inode *inode) ...@@ -435,11 +454,12 @@ void v9fs_evict_inode(struct inode *inode)
static int v9fs_test_inode(struct inode *inode, void *data) static int v9fs_test_inode(struct inode *inode, void *data)
{ {
int umode; int umode;
dev_t rdev;
struct v9fs_inode *v9inode = V9FS_I(inode); struct v9fs_inode *v9inode = V9FS_I(inode);
struct p9_wstat *st = (struct p9_wstat *)data; struct p9_wstat *st = (struct p9_wstat *)data;
struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode); struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode);
umode = p9mode2unixmode(v9ses, st->mode); umode = p9mode2unixmode(v9ses, st, &rdev);
/* don't match inode of different type */ /* don't match inode of different type */
if ((inode->i_mode & S_IFMT) != (umode & S_IFMT)) if ((inode->i_mode & S_IFMT) != (umode & S_IFMT))
return 0; return 0;
...@@ -473,6 +493,7 @@ static struct inode *v9fs_qid_iget(struct super_block *sb, ...@@ -473,6 +493,7 @@ static struct inode *v9fs_qid_iget(struct super_block *sb,
struct p9_wstat *st, struct p9_wstat *st,
int new) int new)
{ {
dev_t rdev;
int retval, umode; int retval, umode;
unsigned long i_ino; unsigned long i_ino;
struct inode *inode; struct inode *inode;
...@@ -496,8 +517,8 @@ static struct inode *v9fs_qid_iget(struct super_block *sb, ...@@ -496,8 +517,8 @@ static struct inode *v9fs_qid_iget(struct super_block *sb,
* later. * later.
*/ */
inode->i_ino = i_ino; inode->i_ino = i_ino;
umode = p9mode2unixmode(v9ses, st->mode); umode = p9mode2unixmode(v9ses, st, &rdev);
retval = v9fs_init_inode(v9ses, inode, umode); retval = v9fs_init_inode(v9ses, inode, umode, rdev);
if (retval) if (retval)
goto error; goto error;
...@@ -531,6 +552,19 @@ v9fs_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid, ...@@ -531,6 +552,19 @@ v9fs_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid,
return inode; return inode;
} }
/**
* v9fs_at_to_dotl_flags- convert Linux specific AT flags to
* plan 9 AT flag.
* @flags: flags to convert
*/
static int v9fs_at_to_dotl_flags(int flags)
{
int rflags = 0;
if (flags & AT_REMOVEDIR)
rflags |= P9_DOTL_AT_REMOVEDIR;
return rflags;
}
/** /**
* v9fs_remove - helper function to remove files and directories * v9fs_remove - helper function to remove files and directories
* @dir: directory inode that is being deleted * @dir: directory inode that is being deleted
...@@ -558,7 +592,8 @@ static int v9fs_remove(struct inode *dir, struct dentry *dentry, int flags) ...@@ -558,7 +592,8 @@ static int v9fs_remove(struct inode *dir, struct dentry *dentry, int flags)
return retval; return retval;
} }
if (v9fs_proto_dotl(v9ses)) if (v9fs_proto_dotl(v9ses))
retval = p9_client_unlinkat(dfid, dentry->d_name.name, flags); retval = p9_client_unlinkat(dfid, dentry->d_name.name,
v9fs_at_to_dotl_flags(flags));
if (retval == -EOPNOTSUPP) { if (retval == -EOPNOTSUPP) {
/* Try the one based on path */ /* Try the one based on path */
v9fid = v9fs_fid_clone(dentry); v9fid = v9fs_fid_clone(dentry);
...@@ -645,13 +680,11 @@ v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir, ...@@ -645,13 +680,11 @@ v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir,
P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n", err); P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n", err);
goto error; goto error;
} }
d_instantiate(dentry, inode);
err = v9fs_fid_add(dentry, fid); err = v9fs_fid_add(dentry, fid);
if (err < 0) if (err < 0)
goto error; goto error;
d_instantiate(dentry, inode);
return ofid; return ofid;
error: error:
if (ofid) if (ofid)
p9_client_clunk(ofid); p9_client_clunk(ofid);
...@@ -792,6 +825,7 @@ static int v9fs_vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) ...@@ -792,6 +825,7 @@ static int v9fs_vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry, struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
struct nameidata *nameidata) struct nameidata *nameidata)
{ {
struct dentry *res;
struct super_block *sb; struct super_block *sb;
struct v9fs_session_info *v9ses; struct v9fs_session_info *v9ses;
struct p9_fid *dfid, *fid; struct p9_fid *dfid, *fid;
...@@ -823,22 +857,35 @@ struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry, ...@@ -823,22 +857,35 @@ struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
return ERR_PTR(result); return ERR_PTR(result);
} }
/*
inode = v9fs_get_inode_from_fid(v9ses, fid, dir->i_sb); * Make sure we don't use a wrong inode due to parallel
* unlink. For cached mode create calls request for new
* inode. But with cache disabled, lookup should do this.
*/
if (v9ses->cache)
inode = v9fs_get_inode_from_fid(v9ses, fid, dir->i_sb);
else
inode = v9fs_get_new_inode_from_fid(v9ses, fid, dir->i_sb);
if (IS_ERR(inode)) { if (IS_ERR(inode)) {
result = PTR_ERR(inode); result = PTR_ERR(inode);
inode = NULL; inode = NULL;
goto error; goto error;
} }
result = v9fs_fid_add(dentry, fid); result = v9fs_fid_add(dentry, fid);
if (result < 0) if (result < 0)
goto error_iput; goto error_iput;
inst_out: inst_out:
d_add(dentry, inode); /*
return NULL; * If we had a rename on the server and a parallel lookup
* for the new name, then make sure we instantiate with
* the new name. ie look up for a/b, while on server somebody
* moved b under k and client parallely did a lookup for
* k/b.
*/
res = d_materialise_unique(dentry, inode);
if (!IS_ERR(res))
return res;
result = PTR_ERR(res);
error_iput: error_iput:
iput(inode); iput(inode);
error: error:
...@@ -1002,7 +1049,7 @@ v9fs_vfs_getattr(struct vfsmount *mnt, struct dentry *dentry, ...@@ -1002,7 +1049,7 @@ v9fs_vfs_getattr(struct vfsmount *mnt, struct dentry *dentry,
return PTR_ERR(st); return PTR_ERR(st);
v9fs_stat2inode(st, dentry->d_inode, dentry->d_inode->i_sb); v9fs_stat2inode(st, dentry->d_inode, dentry->d_inode->i_sb);
generic_fillattr(dentry->d_inode, stat); generic_fillattr(dentry->d_inode, stat);
p9stat_free(st); p9stat_free(st);
kfree(st); kfree(st);
...@@ -1086,6 +1133,7 @@ void ...@@ -1086,6 +1133,7 @@ void
v9fs_stat2inode(struct p9_wstat *stat, struct inode *inode, v9fs_stat2inode(struct p9_wstat *stat, struct inode *inode,
struct super_block *sb) struct super_block *sb)
{ {
mode_t mode;
char ext[32]; char ext[32];
char tag_name[14]; char tag_name[14];
unsigned int i_nlink; unsigned int i_nlink;
...@@ -1121,31 +1169,9 @@ v9fs_stat2inode(struct p9_wstat *stat, struct inode *inode, ...@@ -1121,31 +1169,9 @@ v9fs_stat2inode(struct p9_wstat *stat, struct inode *inode,
inode->i_nlink = i_nlink; inode->i_nlink = i_nlink;
} }
} }
inode->i_mode = p9mode2unixmode(v9ses, stat->mode); mode = stat->mode & S_IALLUGO;
if ((S_ISBLK(inode->i_mode)) || (S_ISCHR(inode->i_mode))) { mode |= inode->i_mode & ~S_IALLUGO;
char type = 0; inode->i_mode = mode;
int major = -1;
int minor = -1;
strncpy(ext, stat->extension, sizeof(ext));
sscanf(ext, "%c %u %u", &type, &major, &minor);
switch (type) {
case 'c':
inode->i_mode &= ~S_IFBLK;
inode->i_mode |= S_IFCHR;
break;
case 'b':
break;
default:
P9_DPRINTK(P9_DEBUG_ERROR,
"Unknown special type %c %s\n", type,
stat->extension);
};
inode->i_rdev = MKDEV(major, minor);
init_special_inode(inode, inode->i_mode, inode->i_rdev);
} else
inode->i_rdev = 0;
i_size_write(inode, stat->length); i_size_write(inode, stat->length);
/* not real number of blocks, but 512 byte ones ... */ /* not real number of blocks, but 512 byte ones ... */
...@@ -1411,6 +1437,8 @@ v9fs_vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev) ...@@ -1411,6 +1437,8 @@ v9fs_vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev)
int v9fs_refresh_inode(struct p9_fid *fid, struct inode *inode) int v9fs_refresh_inode(struct p9_fid *fid, struct inode *inode)
{ {
int umode;
dev_t rdev;
loff_t i_size; loff_t i_size;
struct p9_wstat *st; struct p9_wstat *st;
struct v9fs_session_info *v9ses; struct v9fs_session_info *v9ses;
...@@ -1419,6 +1447,12 @@ int v9fs_refresh_inode(struct p9_fid *fid, struct inode *inode) ...@@ -1419,6 +1447,12 @@ int v9fs_refresh_inode(struct p9_fid *fid, struct inode *inode)
st = p9_client_stat(fid); st = p9_client_stat(fid);
if (IS_ERR(st)) if (IS_ERR(st))
return PTR_ERR(st); return PTR_ERR(st);
/*
* Don't update inode if the file type is different
*/
umode = p9mode2unixmode(v9ses, st, &rdev);
if ((inode->i_mode & S_IFMT) != (umode & S_IFMT))
goto out;
spin_lock(&inode->i_lock); spin_lock(&inode->i_lock);
/* /*
...@@ -1430,6 +1464,7 @@ int v9fs_refresh_inode(struct p9_fid *fid, struct inode *inode) ...@@ -1430,6 +1464,7 @@ int v9fs_refresh_inode(struct p9_fid *fid, struct inode *inode)
if (v9ses->cache) if (v9ses->cache)
inode->i_size = i_size; inode->i_size = i_size;
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
out:
p9stat_free(st); p9stat_free(st);
kfree(st); kfree(st);
return 0; return 0;
......
...@@ -153,7 +153,8 @@ static struct inode *v9fs_qid_iget_dotl(struct super_block *sb, ...@@ -153,7 +153,8 @@ static struct inode *v9fs_qid_iget_dotl(struct super_block *sb,
* later. * later.
*/ */
inode->i_ino = i_ino; inode->i_ino = i_ino;
retval = v9fs_init_inode(v9ses, inode, st->st_mode); retval = v9fs_init_inode(v9ses, inode,
st->st_mode, new_decode_dev(st->st_rdev));
if (retval) if (retval)
goto error; goto error;
...@@ -190,6 +191,58 @@ v9fs_inode_from_fid_dotl(struct v9fs_session_info *v9ses, struct p9_fid *fid, ...@@ -190,6 +191,58 @@ v9fs_inode_from_fid_dotl(struct v9fs_session_info *v9ses, struct p9_fid *fid,
return inode; return inode;
} }
struct dotl_openflag_map {
int open_flag;
int dotl_flag;
};
static int v9fs_mapped_dotl_flags(int flags)
{
int i;
int rflags = 0;
struct dotl_openflag_map dotl_oflag_map[] = {
{ O_CREAT, P9_DOTL_CREATE },
{ O_EXCL, P9_DOTL_EXCL },
{ O_NOCTTY, P9_DOTL_NOCTTY },
{ O_TRUNC, P9_DOTL_TRUNC },
{ O_APPEND, P9_DOTL_APPEND },
{ O_NONBLOCK, P9_DOTL_NONBLOCK },
{ O_DSYNC, P9_DOTL_DSYNC },
{ FASYNC, P9_DOTL_FASYNC },
{ O_DIRECT, P9_DOTL_DIRECT },
{ O_LARGEFILE, P9_DOTL_LARGEFILE },
{ O_DIRECTORY, P9_DOTL_DIRECTORY },
{ O_NOFOLLOW, P9_DOTL_NOFOLLOW },
{ O_NOATIME, P9_DOTL_NOATIME },
{ O_CLOEXEC, P9_DOTL_CLOEXEC },
{ O_SYNC, P9_DOTL_SYNC},
};
for (i = 0; i < ARRAY_SIZE(dotl_oflag_map); i++) {
if (flags & dotl_oflag_map[i].open_flag)
rflags |= dotl_oflag_map[i].dotl_flag;
}
return rflags;
}
/**
* v9fs_open_to_dotl_flags- convert Linux specific open flags to
* plan 9 open flag.
* @flags: flags to convert
*/
int v9fs_open_to_dotl_flags(int flags)
{
int rflags = 0;
/*
* We have same bits for P9_DOTL_READONLY, P9_DOTL_WRONLY
* and P9_DOTL_NOACCESS
*/
rflags |= flags & O_ACCMODE;
rflags |= v9fs_mapped_dotl_flags(flags);
return rflags;
}
/** /**
* v9fs_vfs_create_dotl - VFS hook to create files for 9P2000.L protocol. * v9fs_vfs_create_dotl - VFS hook to create files for 9P2000.L protocol.
* @dir: directory inode that is being created * @dir: directory inode that is being created
...@@ -258,7 +311,8 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int omode, ...@@ -258,7 +311,8 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int omode,
"Failed to get acl values in creat %d\n", err); "Failed to get acl values in creat %d\n", err);
goto error; goto error;
} }
err = p9_client_create_dotl(ofid, name, flags, mode, gid, &qid); err = p9_client_create_dotl(ofid, name, v9fs_open_to_dotl_flags(flags),
mode, gid, &qid);
if (err < 0) { if (err < 0) {
P9_DPRINTK(P9_DEBUG_VFS, P9_DPRINTK(P9_DEBUG_VFS,
"p9_client_open_dotl failed in creat %d\n", "p9_client_open_dotl failed in creat %d\n",
...@@ -281,10 +335,10 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int omode, ...@@ -281,10 +335,10 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int omode,
P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n", err); P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n", err);
goto error; goto error;
} }
d_instantiate(dentry, inode);
err = v9fs_fid_add(dentry, fid); err = v9fs_fid_add(dentry, fid);
if (err < 0) if (err < 0)
goto error; goto error;
d_instantiate(dentry, inode);
/* Now set the ACL based on the default value */ /* Now set the ACL based on the default value */
v9fs_set_create_acl(dentry, &dacl, &pacl); v9fs_set_create_acl(dentry, &dacl, &pacl);
...@@ -403,10 +457,10 @@ static int v9fs_vfs_mkdir_dotl(struct inode *dir, ...@@ -403,10 +457,10 @@ static int v9fs_vfs_mkdir_dotl(struct inode *dir,
err); err);
goto error; goto error;
} }
d_instantiate(dentry, inode);
err = v9fs_fid_add(dentry, fid); err = v9fs_fid_add(dentry, fid);
if (err < 0) if (err < 0)
goto error; goto error;
d_instantiate(dentry, inode);
fid = NULL; fid = NULL;
} else { } else {
/* /*
...@@ -414,7 +468,7 @@ static int v9fs_vfs_mkdir_dotl(struct inode *dir, ...@@ -414,7 +468,7 @@ static int v9fs_vfs_mkdir_dotl(struct inode *dir,
* inode with stat. We need to get an inode * inode with stat. We need to get an inode
* so that we can set the acl with dentry * so that we can set the acl with dentry
*/ */
inode = v9fs_get_inode(dir->i_sb, mode); inode = v9fs_get_inode(dir->i_sb, mode, 0);
if (IS_ERR(inode)) { if (IS_ERR(inode)) {
err = PTR_ERR(inode); err = PTR_ERR(inode);
goto error; goto error;
...@@ -540,6 +594,7 @@ int v9fs_vfs_setattr_dotl(struct dentry *dentry, struct iattr *iattr) ...@@ -540,6 +594,7 @@ int v9fs_vfs_setattr_dotl(struct dentry *dentry, struct iattr *iattr)
void void
v9fs_stat2inode_dotl(struct p9_stat_dotl *stat, struct inode *inode) v9fs_stat2inode_dotl(struct p9_stat_dotl *stat, struct inode *inode)
{ {
mode_t mode;
struct v9fs_inode *v9inode = V9FS_I(inode); struct v9fs_inode *v9inode = V9FS_I(inode);
if ((stat->st_result_mask & P9_STATS_BASIC) == P9_STATS_BASIC) { if ((stat->st_result_mask & P9_STATS_BASIC) == P9_STATS_BASIC) {
...@@ -552,11 +607,10 @@ v9fs_stat2inode_dotl(struct p9_stat_dotl *stat, struct inode *inode) ...@@ -552,11 +607,10 @@ v9fs_stat2inode_dotl(struct p9_stat_dotl *stat, struct inode *inode)
inode->i_uid = stat->st_uid; inode->i_uid = stat->st_uid;
inode->i_gid = stat->st_gid; inode->i_gid = stat->st_gid;
inode->i_nlink = stat->st_nlink; inode->i_nlink = stat->st_nlink;
inode->i_mode = stat->st_mode;
inode->i_rdev = new_decode_dev(stat->st_rdev);
if ((S_ISBLK(inode->i_mode)) || (S_ISCHR(inode->i_mode))) mode = stat->st_mode & S_IALLUGO;
init_special_inode(inode, inode->i_mode, inode->i_rdev); mode |= inode->i_mode & ~S_IALLUGO;
inode->i_mode = mode;
i_size_write(inode, stat->st_size); i_size_write(inode, stat->st_size);
inode->i_blocks = stat->st_blocks; inode->i_blocks = stat->st_blocks;
...@@ -657,14 +711,14 @@ v9fs_vfs_symlink_dotl(struct inode *dir, struct dentry *dentry, ...@@ -657,14 +711,14 @@ v9fs_vfs_symlink_dotl(struct inode *dir, struct dentry *dentry,
err); err);
goto error; goto error;
} }
d_instantiate(dentry, inode);
err = v9fs_fid_add(dentry, fid); err = v9fs_fid_add(dentry, fid);
if (err < 0) if (err < 0)
goto error; goto error;
d_instantiate(dentry, inode);
fid = NULL; fid = NULL;
} else { } else {
/* Not in cached mode. No need to populate inode with stat */ /* Not in cached mode. No need to populate inode with stat */
inode = v9fs_get_inode(dir->i_sb, S_IFLNK); inode = v9fs_get_inode(dir->i_sb, S_IFLNK, 0);
if (IS_ERR(inode)) { if (IS_ERR(inode)) {
err = PTR_ERR(inode); err = PTR_ERR(inode);
goto error; goto error;
...@@ -810,17 +864,17 @@ v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, int omode, ...@@ -810,17 +864,17 @@ v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, int omode,
err); err);
goto error; goto error;
} }
d_instantiate(dentry, inode);
err = v9fs_fid_add(dentry, fid); err = v9fs_fid_add(dentry, fid);
if (err < 0) if (err < 0)
goto error; goto error;
d_instantiate(dentry, inode);
fid = NULL; fid = NULL;
} else { } else {
/* /*
* Not in cached mode. No need to populate inode with stat. * Not in cached mode. No need to populate inode with stat.
* socket syscall returns a fd, so we need instantiate * socket syscall returns a fd, so we need instantiate
*/ */
inode = v9fs_get_inode(dir->i_sb, mode); inode = v9fs_get_inode(dir->i_sb, mode, rdev);
if (IS_ERR(inode)) { if (IS_ERR(inode)) {
err = PTR_ERR(inode); err = PTR_ERR(inode);
goto error; goto error;
...@@ -886,6 +940,11 @@ int v9fs_refresh_inode_dotl(struct p9_fid *fid, struct inode *inode) ...@@ -886,6 +940,11 @@ int v9fs_refresh_inode_dotl(struct p9_fid *fid, struct inode *inode)
st = p9_client_getattr_dotl(fid, P9_STATS_ALL); st = p9_client_getattr_dotl(fid, P9_STATS_ALL);
if (IS_ERR(st)) if (IS_ERR(st))
return PTR_ERR(st); return PTR_ERR(st);
/*
* Don't update inode if the file type is different
*/
if ((inode->i_mode & S_IFMT) != (st->st_mode & S_IFMT))
goto out;
spin_lock(&inode->i_lock); spin_lock(&inode->i_lock);
/* /*
...@@ -897,6 +956,7 @@ int v9fs_refresh_inode_dotl(struct p9_fid *fid, struct inode *inode) ...@@ -897,6 +956,7 @@ int v9fs_refresh_inode_dotl(struct p9_fid *fid, struct inode *inode)
if (v9ses->cache) if (v9ses->cache)
inode->i_size = i_size; inode->i_size = i_size;
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
out:
kfree(st); kfree(st);
return 0; return 0;
} }
......
...@@ -149,7 +149,7 @@ static struct dentry *v9fs_mount(struct file_system_type *fs_type, int flags, ...@@ -149,7 +149,7 @@ static struct dentry *v9fs_mount(struct file_system_type *fs_type, int flags,
else else
sb->s_d_op = &v9fs_dentry_operations; sb->s_d_op = &v9fs_dentry_operations;
inode = v9fs_get_inode(sb, S_IFDIR | mode); inode = v9fs_get_inode(sb, S_IFDIR | mode, 0);
if (IS_ERR(inode)) { if (IS_ERR(inode)) {
retval = PTR_ERR(inode); retval = PTR_ERR(inode);
goto release_sb; goto release_sb;
......
...@@ -288,6 +288,35 @@ enum p9_perm_t { ...@@ -288,6 +288,35 @@ enum p9_perm_t {
P9_DMSETVTX = 0x00010000, P9_DMSETVTX = 0x00010000,
}; };
/* 9p2000.L open flags */
#define P9_DOTL_RDONLY 00000000
#define P9_DOTL_WRONLY 00000001
#define P9_DOTL_RDWR 00000002
#define P9_DOTL_NOACCESS 00000003
#define P9_DOTL_CREATE 00000100
#define P9_DOTL_EXCL 00000200
#define P9_DOTL_NOCTTY 00000400
#define P9_DOTL_TRUNC 00001000
#define P9_DOTL_APPEND 00002000
#define P9_DOTL_NONBLOCK 00004000
#define P9_DOTL_DSYNC 00010000
#define P9_DOTL_FASYNC 00020000
#define P9_DOTL_DIRECT 00040000
#define P9_DOTL_LARGEFILE 00100000
#define P9_DOTL_DIRECTORY 00200000
#define P9_DOTL_NOFOLLOW 00400000
#define P9_DOTL_NOATIME 01000000
#define P9_DOTL_CLOEXEC 02000000
#define P9_DOTL_SYNC 04000000
/* 9p2000.L at flags */
#define P9_DOTL_AT_REMOVEDIR 0x200
/* 9p2000.L lock type */
#define P9_LOCK_TYPE_RDLCK 0
#define P9_LOCK_TYPE_WRLCK 1
#define P9_LOCK_TYPE_UNLCK 2
/** /**
* enum p9_qid_t - QID types * enum p9_qid_t - QID types
* @P9_QTDIR: directory * @P9_QTDIR: directory
......
...@@ -263,7 +263,6 @@ p9_virtio_request(struct p9_client *client, struct p9_req_t *req) ...@@ -263,7 +263,6 @@ p9_virtio_request(struct p9_client *client, struct p9_req_t *req)
{ {
int in, out, inp, outp; int in, out, inp, outp;
struct virtio_chan *chan = client->trans; struct virtio_chan *chan = client->trans;
char *rdata = (char *)req->rc+sizeof(struct p9_fcall);
unsigned long flags; unsigned long flags;
size_t pdata_off = 0; size_t pdata_off = 0;
struct trans_rpage_info *rpinfo = NULL; struct trans_rpage_info *rpinfo = NULL;
...@@ -346,7 +345,8 @@ p9_virtio_request(struct p9_client *client, struct p9_req_t *req) ...@@ -346,7 +345,8 @@ p9_virtio_request(struct p9_client *client, struct p9_req_t *req)
* Arrange in such a way that server places header in the * Arrange in such a way that server places header in the
* alloced memory and payload onto the user buffer. * alloced memory and payload onto the user buffer.
*/ */
inp = pack_sg_list(chan->sg, out, VIRTQUEUE_NUM, rdata, 11); inp = pack_sg_list(chan->sg, out,
VIRTQUEUE_NUM, req->rc->sdata, 11);
/* /*
* Running executables in the filesystem may result in * Running executables in the filesystem may result in
* a read request with kernel buffer as opposed to user buffer. * a read request with kernel buffer as opposed to user buffer.
...@@ -366,8 +366,8 @@ p9_virtio_request(struct p9_client *client, struct p9_req_t *req) ...@@ -366,8 +366,8 @@ p9_virtio_request(struct p9_client *client, struct p9_req_t *req)
} }
in += inp; in += inp;
} else { } else {
in = pack_sg_list(chan->sg, out, VIRTQUEUE_NUM, rdata, in = pack_sg_list(chan->sg, out, VIRTQUEUE_NUM,
req->rc->capacity); req->rc->sdata, req->rc->capacity);
} }
err = virtqueue_add_buf(chan->vq, chan->sg, out, in, req->tc); err = virtqueue_add_buf(chan->vq, chan->sg, out, in, req->tc);
...@@ -592,7 +592,14 @@ static struct p9_trans_module p9_virtio_trans = { ...@@ -592,7 +592,14 @@ static struct p9_trans_module p9_virtio_trans = {
.close = p9_virtio_close, .close = p9_virtio_close,
.request = p9_virtio_request, .request = p9_virtio_request,
.cancel = p9_virtio_cancel, .cancel = p9_virtio_cancel,
.maxsize = PAGE_SIZE*VIRTQUEUE_NUM,
/*
* We leave one entry for input and one entry for response
* headers. We also skip one more entry to accomodate, address
* that are not at page boundary, that can result in an extra
* page in zero copy.
*/
.maxsize = PAGE_SIZE * (VIRTQUEUE_NUM - 3),
.pref = P9_TRANS_PREF_PAYLOAD_SEP, .pref = P9_TRANS_PREF_PAYLOAD_SEP,
.def = 0, .def = 0,
.owner = THIS_MODULE, .owner = THIS_MODULE,
......
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