Commit ab70a1d7 authored by Linus Torvalds's avatar Linus Torvalds

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

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ericvh/v9fs:
  [net/9p]: Introduce basic flow-control for VirtIO transport.
  9p: use the updated offset given by generic_write_checks
  [net/9p] Don't re-pin pages on retrying virtqueue_add_buf().
  [net/9p] Set the condition just before waking up.
  [net/9p] unconditional wake_up to proc waiting for space on VirtIO ring
  fs/9p: Add v9fs_dentry2v9ses
  fs/9p: Attach writeback_fid on first open with WR flag
  fs/9p: Open writeback fid in O_SYNC mode
  fs/9p: Use truncate_setsize instead of vmtruncate
  net/9p: Fix compile warning
  net/9p: Convert the in the 9p rpc call path to GFP_NOFS
  fs/9p: Fix race in initializing writeback fid
parents 0adfc56c 68da9ba4
...@@ -262,7 +262,7 @@ static int v9fs_xattr_get_acl(struct dentry *dentry, const char *name, ...@@ -262,7 +262,7 @@ static int v9fs_xattr_get_acl(struct dentry *dentry, const char *name,
if (strcmp(name, "") != 0) if (strcmp(name, "") != 0)
return -EINVAL; return -EINVAL;
v9ses = v9fs_inode2v9ses(dentry->d_inode); v9ses = v9fs_dentry2v9ses(dentry);
/* /*
* We allow set/get/list of acl when access=client is not specified * We allow set/get/list of acl when access=client is not specified
*/ */
...@@ -312,7 +312,7 @@ static int v9fs_xattr_set_acl(struct dentry *dentry, const char *name, ...@@ -312,7 +312,7 @@ static int v9fs_xattr_set_acl(struct dentry *dentry, const char *name,
if (strcmp(name, "") != 0) if (strcmp(name, "") != 0)
return -EINVAL; return -EINVAL;
v9ses = v9fs_inode2v9ses(dentry->d_inode); v9ses = v9fs_dentry2v9ses(dentry);
/* /*
* set the attribute on the remote. Without even looking at the * set the attribute on the remote. Without even looking at the
* xattr value. We leave it to the server to validate * xattr value. We leave it to the server to validate
......
...@@ -134,7 +134,7 @@ static struct p9_fid *v9fs_fid_lookup_with_uid(struct dentry *dentry, ...@@ -134,7 +134,7 @@ static struct p9_fid *v9fs_fid_lookup_with_uid(struct dentry *dentry,
struct v9fs_session_info *v9ses; struct v9fs_session_info *v9ses;
struct p9_fid *fid, *old_fid = NULL; struct p9_fid *fid, *old_fid = NULL;
v9ses = v9fs_inode2v9ses(dentry->d_inode); v9ses = v9fs_dentry2v9ses(dentry);
access = v9ses->flags & V9FS_ACCESS_MASK; access = v9ses->flags & V9FS_ACCESS_MASK;
fid = v9fs_fid_find(dentry, uid, any); fid = v9fs_fid_find(dentry, uid, any);
if (fid) if (fid)
...@@ -237,7 +237,7 @@ struct p9_fid *v9fs_fid_lookup(struct dentry *dentry) ...@@ -237,7 +237,7 @@ struct p9_fid *v9fs_fid_lookup(struct dentry *dentry)
int any, access; int any, access;
struct v9fs_session_info *v9ses; struct v9fs_session_info *v9ses;
v9ses = v9fs_inode2v9ses(dentry->d_inode); v9ses = v9fs_dentry2v9ses(dentry);
access = v9ses->flags & V9FS_ACCESS_MASK; access = v9ses->flags & V9FS_ACCESS_MASK;
switch (access) { switch (access) {
case V9FS_ACCESS_SINGLE: case V9FS_ACCESS_SINGLE:
...@@ -286,9 +286,11 @@ static struct p9_fid *v9fs_fid_clone_with_uid(struct dentry *dentry, uid_t uid) ...@@ -286,9 +286,11 @@ static struct p9_fid *v9fs_fid_clone_with_uid(struct dentry *dentry, uid_t uid)
struct p9_fid *v9fs_writeback_fid(struct dentry *dentry) struct p9_fid *v9fs_writeback_fid(struct dentry *dentry)
{ {
int err; int err, flags;
struct p9_fid *fid; struct p9_fid *fid;
struct v9fs_session_info *v9ses;
v9ses = v9fs_dentry2v9ses(dentry);
fid = v9fs_fid_clone_with_uid(dentry, 0); fid = v9fs_fid_clone_with_uid(dentry, 0);
if (IS_ERR(fid)) if (IS_ERR(fid))
goto error_out; goto error_out;
...@@ -297,8 +299,17 @@ struct p9_fid *v9fs_writeback_fid(struct dentry *dentry) ...@@ -297,8 +299,17 @@ struct p9_fid *v9fs_writeback_fid(struct dentry *dentry)
* dirty pages. We always request for the open fid in read-write * dirty pages. We always request for the open fid in read-write
* mode so that a partial page write which result in page * mode so that a partial page write which result in page
* read can work. * read can work.
*
* we don't have a tsyncfs operation for older version
* of protocol. So make sure the write back fid is
* opened in O_SYNC mode.
*/ */
err = p9_client_open(fid, O_RDWR); if (!v9fs_proto_dotl(v9ses))
flags = O_RDWR | O_SYNC;
else
flags = O_RDWR;
err = p9_client_open(fid, flags);
if (err < 0) { if (err < 0) {
p9_client_clunk(fid); p9_client_clunk(fid);
fid = ERR_PTR(err); fid = ERR_PTR(err);
......
...@@ -130,6 +130,7 @@ struct v9fs_inode { ...@@ -130,6 +130,7 @@ struct v9fs_inode {
#endif #endif
unsigned int cache_validity; unsigned int cache_validity;
struct p9_fid *writeback_fid; struct p9_fid *writeback_fid;
struct mutex v_mutex;
struct inode vfs_inode; struct inode vfs_inode;
}; };
...@@ -173,6 +174,11 @@ static inline struct v9fs_session_info *v9fs_inode2v9ses(struct inode *inode) ...@@ -173,6 +174,11 @@ static inline struct v9fs_session_info *v9fs_inode2v9ses(struct inode *inode)
return (inode->i_sb->s_fs_info); return (inode->i_sb->s_fs_info);
} }
static inline struct v9fs_session_info *v9fs_dentry2v9ses(struct dentry *dentry)
{
return dentry->d_sb->s_fs_info;
}
static inline int v9fs_proto_dotu(struct v9fs_session_info *v9ses) static inline int v9fs_proto_dotu(struct v9fs_session_info *v9ses)
{ {
return v9ses->flags & V9FS_PROTO_2000U; return v9ses->flags & V9FS_PROTO_2000U;
......
...@@ -90,7 +90,9 @@ int v9fs_file_open(struct inode *inode, struct file *file) ...@@ -90,7 +90,9 @@ int v9fs_file_open(struct inode *inode, struct file *file)
} }
file->private_data = fid; file->private_data = fid;
if (v9ses->cache && !v9inode->writeback_fid) { mutex_lock(&v9inode->v_mutex);
if (v9ses->cache && !v9inode->writeback_fid &&
((file->f_flags & O_ACCMODE) != O_RDONLY)) {
/* /*
* clone a fid and add it to writeback_fid * clone a fid and add it to writeback_fid
* we do it during open time instead of * we do it during open time instead of
...@@ -101,10 +103,12 @@ int v9fs_file_open(struct inode *inode, struct file *file) ...@@ -101,10 +103,12 @@ int v9fs_file_open(struct inode *inode, struct file *file)
fid = v9fs_writeback_fid(file->f_path.dentry); fid = v9fs_writeback_fid(file->f_path.dentry);
if (IS_ERR(fid)) { if (IS_ERR(fid)) {
err = PTR_ERR(fid); err = PTR_ERR(fid);
mutex_unlock(&v9inode->v_mutex);
goto out_error; goto out_error;
} }
v9inode->writeback_fid = (void *) fid; v9inode->writeback_fid = (void *) fid;
} }
mutex_unlock(&v9inode->v_mutex);
#ifdef CONFIG_9P_FSCACHE #ifdef CONFIG_9P_FSCACHE
if (v9ses->cache) if (v9ses->cache)
v9fs_cache_inode_set_cookie(inode, file); v9fs_cache_inode_set_cookie(inode, file);
...@@ -504,9 +508,12 @@ v9fs_file_write(struct file *filp, const char __user * data, ...@@ -504,9 +508,12 @@ v9fs_file_write(struct file *filp, const char __user * data,
if (!count) if (!count)
goto out; goto out;
return v9fs_file_write_internal(filp->f_path.dentry->d_inode, retval = v9fs_file_write_internal(filp->f_path.dentry->d_inode,
filp->private_data, filp->private_data,
data, count, offset, 1); data, count, &origin, 1);
/* update offset on successful write */
if (retval > 0)
*offset = origin;
out: out:
return retval; return retval;
} }
......
...@@ -221,6 +221,7 @@ struct inode *v9fs_alloc_inode(struct super_block *sb) ...@@ -221,6 +221,7 @@ struct inode *v9fs_alloc_inode(struct super_block *sb)
#endif #endif
v9inode->writeback_fid = NULL; v9inode->writeback_fid = NULL;
v9inode->cache_validity = 0; v9inode->cache_validity = 0;
mutex_init(&v9inode->v_mutex);
return &v9inode->vfs_inode; return &v9inode->vfs_inode;
} }
...@@ -650,7 +651,9 @@ v9fs_vfs_create(struct inode *dir, struct dentry *dentry, int mode, ...@@ -650,7 +651,9 @@ v9fs_vfs_create(struct inode *dir, struct dentry *dentry, int mode,
/* if we are opening a file, assign the open fid to the file */ /* if we are opening a file, assign the open fid to the file */
if (nd && nd->flags & LOOKUP_OPEN) { if (nd && nd->flags & LOOKUP_OPEN) {
v9inode = V9FS_I(dentry->d_inode); v9inode = V9FS_I(dentry->d_inode);
if (v9ses->cache && !v9inode->writeback_fid) { mutex_lock(&v9inode->v_mutex);
if (v9ses->cache && !v9inode->writeback_fid &&
((flags & O_ACCMODE) != O_RDONLY)) {
/* /*
* clone a fid and add it to writeback_fid * clone a fid and add it to writeback_fid
* we do it during open time instead of * we do it during open time instead of
...@@ -661,10 +664,12 @@ v9fs_vfs_create(struct inode *dir, struct dentry *dentry, int mode, ...@@ -661,10 +664,12 @@ v9fs_vfs_create(struct inode *dir, struct dentry *dentry, int mode,
inode_fid = v9fs_writeback_fid(dentry); inode_fid = v9fs_writeback_fid(dentry);
if (IS_ERR(inode_fid)) { if (IS_ERR(inode_fid)) {
err = PTR_ERR(inode_fid); err = PTR_ERR(inode_fid);
mutex_unlock(&v9inode->v_mutex);
goto error; goto error;
} }
v9inode->writeback_fid = (void *) inode_fid; v9inode->writeback_fid = (void *) inode_fid;
} }
mutex_unlock(&v9inode->v_mutex);
filp = lookup_instantiate_filp(nd, dentry, generic_file_open); filp = lookup_instantiate_filp(nd, dentry, generic_file_open);
if (IS_ERR(filp)) { if (IS_ERR(filp)) {
err = PTR_ERR(filp); err = PTR_ERR(filp);
...@@ -931,7 +936,7 @@ v9fs_vfs_getattr(struct vfsmount *mnt, struct dentry *dentry, ...@@ -931,7 +936,7 @@ v9fs_vfs_getattr(struct vfsmount *mnt, struct dentry *dentry,
P9_DPRINTK(P9_DEBUG_VFS, "dentry: %p\n", dentry); P9_DPRINTK(P9_DEBUG_VFS, "dentry: %p\n", dentry);
err = -EPERM; err = -EPERM;
v9ses = v9fs_inode2v9ses(dentry->d_inode); v9ses = v9fs_dentry2v9ses(dentry);
if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) { if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) {
generic_fillattr(dentry->d_inode, stat); generic_fillattr(dentry->d_inode, stat);
return 0; return 0;
...@@ -967,8 +972,12 @@ static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr) ...@@ -967,8 +972,12 @@ static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr)
struct p9_wstat wstat; struct p9_wstat wstat;
P9_DPRINTK(P9_DEBUG_VFS, "\n"); P9_DPRINTK(P9_DEBUG_VFS, "\n");
retval = inode_change_ok(dentry->d_inode, iattr);
if (retval)
return retval;
retval = -EPERM; retval = -EPERM;
v9ses = v9fs_inode2v9ses(dentry->d_inode); v9ses = v9fs_dentry2v9ses(dentry);
fid = v9fs_fid_lookup(dentry); fid = v9fs_fid_lookup(dentry);
if(IS_ERR(fid)) if(IS_ERR(fid))
return PTR_ERR(fid); return PTR_ERR(fid);
...@@ -993,12 +1002,7 @@ static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr) ...@@ -993,12 +1002,7 @@ static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr)
if (iattr->ia_valid & ATTR_GID) if (iattr->ia_valid & ATTR_GID)
wstat.n_gid = iattr->ia_gid; wstat.n_gid = iattr->ia_gid;
} }
if ((iattr->ia_valid & ATTR_SIZE) &&
iattr->ia_size != i_size_read(dentry->d_inode)) {
retval = vmtruncate(dentry->d_inode, iattr->ia_size);
if (retval)
return retval;
}
/* Write all dirty data */ /* Write all dirty data */
if (S_ISREG(dentry->d_inode->i_mode)) if (S_ISREG(dentry->d_inode->i_mode))
filemap_write_and_wait(dentry->d_inode->i_mapping); filemap_write_and_wait(dentry->d_inode->i_mapping);
...@@ -1006,6 +1010,11 @@ static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr) ...@@ -1006,6 +1010,11 @@ static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr)
retval = p9_client_wstat(fid, &wstat); retval = p9_client_wstat(fid, &wstat);
if (retval < 0) if (retval < 0)
return retval; return retval;
if ((iattr->ia_valid & ATTR_SIZE) &&
iattr->ia_size != i_size_read(dentry->d_inode))
truncate_setsize(dentry->d_inode, iattr->ia_size);
v9fs_invalidate_inode_attr(dentry->d_inode); v9fs_invalidate_inode_attr(dentry->d_inode);
setattr_copy(dentry->d_inode, iattr); setattr_copy(dentry->d_inode, iattr);
...@@ -1130,7 +1139,7 @@ static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen) ...@@ -1130,7 +1139,7 @@ static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen)
P9_DPRINTK(P9_DEBUG_VFS, " %s\n", dentry->d_name.name); P9_DPRINTK(P9_DEBUG_VFS, " %s\n", dentry->d_name.name);
retval = -EPERM; retval = -EPERM;
v9ses = v9fs_inode2v9ses(dentry->d_inode); v9ses = v9fs_dentry2v9ses(dentry);
fid = v9fs_fid_lookup(dentry); fid = v9fs_fid_lookup(dentry);
if (IS_ERR(fid)) if (IS_ERR(fid))
return PTR_ERR(fid); return PTR_ERR(fid);
......
...@@ -245,7 +245,9 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int omode, ...@@ -245,7 +245,9 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int omode,
v9fs_set_create_acl(dentry, dacl, pacl); v9fs_set_create_acl(dentry, dacl, pacl);
v9inode = V9FS_I(inode); v9inode = V9FS_I(inode);
if (v9ses->cache && !v9inode->writeback_fid) { mutex_lock(&v9inode->v_mutex);
if (v9ses->cache && !v9inode->writeback_fid &&
((flags & O_ACCMODE) != O_RDONLY)) {
/* /*
* clone a fid and add it to writeback_fid * clone a fid and add it to writeback_fid
* we do it during open time instead of * we do it during open time instead of
...@@ -256,10 +258,12 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int omode, ...@@ -256,10 +258,12 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int omode,
inode_fid = v9fs_writeback_fid(dentry); inode_fid = v9fs_writeback_fid(dentry);
if (IS_ERR(inode_fid)) { if (IS_ERR(inode_fid)) {
err = PTR_ERR(inode_fid); err = PTR_ERR(inode_fid);
mutex_unlock(&v9inode->v_mutex);
goto error; goto error;
} }
v9inode->writeback_fid = (void *) inode_fid; v9inode->writeback_fid = (void *) inode_fid;
} }
mutex_unlock(&v9inode->v_mutex);
/* Since we are opening a file, assign the open fid to the file */ /* Since we are opening a file, assign the open fid to the file */
filp = lookup_instantiate_filp(nd, dentry, generic_file_open); filp = lookup_instantiate_filp(nd, dentry, generic_file_open);
if (IS_ERR(filp)) { if (IS_ERR(filp)) {
...@@ -391,7 +395,7 @@ v9fs_vfs_getattr_dotl(struct vfsmount *mnt, struct dentry *dentry, ...@@ -391,7 +395,7 @@ v9fs_vfs_getattr_dotl(struct vfsmount *mnt, struct dentry *dentry,
P9_DPRINTK(P9_DEBUG_VFS, "dentry: %p\n", dentry); P9_DPRINTK(P9_DEBUG_VFS, "dentry: %p\n", dentry);
err = -EPERM; err = -EPERM;
v9ses = v9fs_inode2v9ses(dentry->d_inode); v9ses = v9fs_dentry2v9ses(dentry);
if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) { if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) {
generic_fillattr(dentry->d_inode, stat); generic_fillattr(dentry->d_inode, stat);
return 0; return 0;
...@@ -448,17 +452,11 @@ int v9fs_vfs_setattr_dotl(struct dentry *dentry, struct iattr *iattr) ...@@ -448,17 +452,11 @@ int v9fs_vfs_setattr_dotl(struct dentry *dentry, struct iattr *iattr)
p9attr.mtime_nsec = iattr->ia_mtime.tv_nsec; p9attr.mtime_nsec = iattr->ia_mtime.tv_nsec;
retval = -EPERM; retval = -EPERM;
v9ses = v9fs_inode2v9ses(dentry->d_inode); v9ses = v9fs_dentry2v9ses(dentry);
fid = v9fs_fid_lookup(dentry); fid = v9fs_fid_lookup(dentry);
if (IS_ERR(fid)) if (IS_ERR(fid))
return PTR_ERR(fid); return PTR_ERR(fid);
if ((iattr->ia_valid & ATTR_SIZE) &&
iattr->ia_size != i_size_read(dentry->d_inode)) {
retval = vmtruncate(dentry->d_inode, iattr->ia_size);
if (retval)
return retval;
}
/* Write all dirty data */ /* Write all dirty data */
if (S_ISREG(dentry->d_inode->i_mode)) if (S_ISREG(dentry->d_inode->i_mode))
filemap_write_and_wait(dentry->d_inode->i_mapping); filemap_write_and_wait(dentry->d_inode->i_mapping);
...@@ -466,8 +464,12 @@ int v9fs_vfs_setattr_dotl(struct dentry *dentry, struct iattr *iattr) ...@@ -466,8 +464,12 @@ int v9fs_vfs_setattr_dotl(struct dentry *dentry, struct iattr *iattr)
retval = p9_client_setattr(fid, &p9attr); retval = p9_client_setattr(fid, &p9attr);
if (retval < 0) if (retval < 0)
return retval; return retval;
v9fs_invalidate_inode_attr(dentry->d_inode);
if ((iattr->ia_valid & ATTR_SIZE) &&
iattr->ia_size != i_size_read(dentry->d_inode))
truncate_setsize(dentry->d_inode, iattr->ia_size);
v9fs_invalidate_inode_attr(dentry->d_inode);
setattr_copy(dentry->d_inode, iattr); setattr_copy(dentry->d_inode, iattr);
mark_inode_dirty(dentry->d_inode); mark_inode_dirty(dentry->d_inode);
if (iattr->ia_valid & ATTR_MODE) { if (iattr->ia_valid & ATTR_MODE) {
......
...@@ -262,7 +262,7 @@ static int v9fs_statfs(struct dentry *dentry, struct kstatfs *buf) ...@@ -262,7 +262,7 @@ static int v9fs_statfs(struct dentry *dentry, struct kstatfs *buf)
goto done; goto done;
} }
v9ses = v9fs_inode2v9ses(dentry->d_inode); v9ses = v9fs_dentry2v9ses(dentry);
if (v9fs_proto_dotl(v9ses)) { if (v9fs_proto_dotl(v9ses)) {
res = p9_client_statfs(fid, &rs); res = p9_client_statfs(fid, &rs);
if (res == 0) { if (res == 0) {
......
...@@ -223,7 +223,7 @@ static struct p9_req_t *p9_tag_alloc(struct p9_client *c, u16 tag) ...@@ -223,7 +223,7 @@ static struct p9_req_t *p9_tag_alloc(struct p9_client *c, u16 tag)
req = &c->reqs[row][col]; req = &c->reqs[row][col];
if (!req->tc) { if (!req->tc) {
req->wq = kmalloc(sizeof(wait_queue_head_t), GFP_KERNEL); req->wq = kmalloc(sizeof(wait_queue_head_t), GFP_NOFS);
if (!req->wq) { if (!req->wq) {
printk(KERN_ERR "Couldn't grow tag array\n"); printk(KERN_ERR "Couldn't grow tag array\n");
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
...@@ -233,17 +233,17 @@ static struct p9_req_t *p9_tag_alloc(struct p9_client *c, u16 tag) ...@@ -233,17 +233,17 @@ static struct p9_req_t *p9_tag_alloc(struct p9_client *c, u16 tag)
P9_TRANS_PREF_PAYLOAD_SEP) { P9_TRANS_PREF_PAYLOAD_SEP) {
int alloc_msize = min(c->msize, 4096); int alloc_msize = min(c->msize, 4096);
req->tc = kmalloc(sizeof(struct p9_fcall)+alloc_msize, req->tc = kmalloc(sizeof(struct p9_fcall)+alloc_msize,
GFP_KERNEL); GFP_NOFS);
req->tc->capacity = alloc_msize; req->tc->capacity = alloc_msize;
req->rc = kmalloc(sizeof(struct p9_fcall)+alloc_msize, req->rc = kmalloc(sizeof(struct p9_fcall)+alloc_msize,
GFP_KERNEL); GFP_NOFS);
req->rc->capacity = alloc_msize; req->rc->capacity = alloc_msize;
} else { } else {
req->tc = kmalloc(sizeof(struct p9_fcall)+c->msize, req->tc = kmalloc(sizeof(struct p9_fcall)+c->msize,
GFP_KERNEL); GFP_NOFS);
req->tc->capacity = c->msize; req->tc->capacity = c->msize;
req->rc = kmalloc(sizeof(struct p9_fcall)+c->msize, req->rc = kmalloc(sizeof(struct p9_fcall)+c->msize,
GFP_KERNEL); GFP_NOFS);
req->rc->capacity = c->msize; req->rc->capacity = c->msize;
} }
if ((!req->tc) || (!req->rc)) { if ((!req->tc) || (!req->rc)) {
......
...@@ -205,7 +205,7 @@ p9pdu_vreadf(struct p9_fcall *pdu, int proto_version, const char *fmt, ...@@ -205,7 +205,7 @@ p9pdu_vreadf(struct p9_fcall *pdu, int proto_version, const char *fmt,
if (errcode) if (errcode)
break; break;
*sptr = kmalloc(len + 1, GFP_KERNEL); *sptr = kmalloc(len + 1, GFP_NOFS);
if (*sptr == NULL) { if (*sptr == NULL) {
errcode = -EFAULT; errcode = -EFAULT;
break; break;
...@@ -273,7 +273,7 @@ p9pdu_vreadf(struct p9_fcall *pdu, int proto_version, const char *fmt, ...@@ -273,7 +273,7 @@ p9pdu_vreadf(struct p9_fcall *pdu, int proto_version, const char *fmt,
if (!errcode) { if (!errcode) {
*wnames = *wnames =
kmalloc(sizeof(char *) * *nwname, kmalloc(sizeof(char *) * *nwname,
GFP_KERNEL); GFP_NOFS);
if (!*wnames) if (!*wnames)
errcode = -ENOMEM; errcode = -ENOMEM;
} }
...@@ -317,7 +317,7 @@ p9pdu_vreadf(struct p9_fcall *pdu, int proto_version, const char *fmt, ...@@ -317,7 +317,7 @@ p9pdu_vreadf(struct p9_fcall *pdu, int proto_version, const char *fmt,
*wqids = *wqids =
kmalloc(*nwqid * kmalloc(*nwqid *
sizeof(struct p9_qid), sizeof(struct p9_qid),
GFP_KERNEL); GFP_NOFS);
if (*wqids == NULL) if (*wqids == NULL)
errcode = -ENOMEM; errcode = -ENOMEM;
} }
......
...@@ -41,9 +41,9 @@ EXPORT_SYMBOL(p9_release_req_pages); ...@@ -41,9 +41,9 @@ EXPORT_SYMBOL(p9_release_req_pages);
int int
p9_nr_pages(struct p9_req_t *req) p9_nr_pages(struct p9_req_t *req)
{ {
int start_page, end_page; unsigned long start_page, end_page;
start_page = (unsigned long long)req->tc->pubuf >> PAGE_SHIFT; start_page = (unsigned long)req->tc->pubuf >> PAGE_SHIFT;
end_page = ((unsigned long long)req->tc->pubuf + req->tc->pbuf_size + end_page = ((unsigned long)req->tc->pubuf + req->tc->pbuf_size +
PAGE_SIZE - 1) >> PAGE_SHIFT; PAGE_SIZE - 1) >> PAGE_SHIFT;
return end_page - start_page; return end_page - start_page;
} }
...@@ -69,8 +69,8 @@ p9_payload_gup(struct p9_req_t *req, size_t *pdata_off, int *pdata_len, ...@@ -69,8 +69,8 @@ p9_payload_gup(struct p9_req_t *req, size_t *pdata_off, int *pdata_len,
*pdata_off = (size_t)req->tc->pubuf & (PAGE_SIZE-1); *pdata_off = (size_t)req->tc->pubuf & (PAGE_SIZE-1);
if (*pdata_off) if (*pdata_off)
first_page_bytes = min((PAGE_SIZE - *pdata_off), first_page_bytes = min(((size_t)PAGE_SIZE - *pdata_off),
req->tc->pbuf_size); req->tc->pbuf_size);
rpinfo = req->tc->private; rpinfo = req->tc->private;
pdata_mapped_pages = get_user_pages_fast((unsigned long)req->tc->pubuf, pdata_mapped_pages = get_user_pages_fast((unsigned long)req->tc->pubuf,
......
...@@ -350,7 +350,7 @@ static void p9_read_work(struct work_struct *work) ...@@ -350,7 +350,7 @@ static void p9_read_work(struct work_struct *work)
if (m->req->rc == NULL) { if (m->req->rc == NULL) {
m->req->rc = kmalloc(sizeof(struct p9_fcall) + m->req->rc = kmalloc(sizeof(struct p9_fcall) +
m->client->msize, GFP_KERNEL); m->client->msize, GFP_NOFS);
if (!m->req->rc) { if (!m->req->rc) {
m->req = NULL; m->req = NULL;
err = -ENOMEM; err = -ENOMEM;
......
...@@ -424,7 +424,7 @@ static int rdma_request(struct p9_client *client, struct p9_req_t *req) ...@@ -424,7 +424,7 @@ static int rdma_request(struct p9_client *client, struct p9_req_t *req)
struct p9_rdma_context *rpl_context = NULL; struct p9_rdma_context *rpl_context = NULL;
/* Allocate an fcall for the reply */ /* Allocate an fcall for the reply */
rpl_context = kmalloc(sizeof *rpl_context, GFP_KERNEL); rpl_context = kmalloc(sizeof *rpl_context, GFP_NOFS);
if (!rpl_context) { if (!rpl_context) {
err = -ENOMEM; err = -ENOMEM;
goto err_close; goto err_close;
...@@ -437,7 +437,7 @@ static int rdma_request(struct p9_client *client, struct p9_req_t *req) ...@@ -437,7 +437,7 @@ static int rdma_request(struct p9_client *client, struct p9_req_t *req)
*/ */
if (!req->rc) { if (!req->rc) {
req->rc = kmalloc(sizeof(struct p9_fcall)+client->msize, req->rc = kmalloc(sizeof(struct p9_fcall)+client->msize,
GFP_KERNEL); GFP_NOFS);
if (req->rc) { if (req->rc) {
req->rc->sdata = (char *) req->rc + req->rc->sdata = (char *) req->rc +
sizeof(struct p9_fcall); sizeof(struct p9_fcall);
...@@ -468,7 +468,7 @@ static int rdma_request(struct p9_client *client, struct p9_req_t *req) ...@@ -468,7 +468,7 @@ static int rdma_request(struct p9_client *client, struct p9_req_t *req)
req->rc = NULL; req->rc = NULL;
/* Post the request */ /* Post the request */
c = kmalloc(sizeof *c, GFP_KERNEL); c = kmalloc(sizeof *c, GFP_NOFS);
if (!c) { if (!c) {
err = -ENOMEM; err = -ENOMEM;
goto err_free1; goto err_free1;
......
...@@ -43,6 +43,7 @@ ...@@ -43,6 +43,7 @@
#include <net/9p/client.h> #include <net/9p/client.h>
#include <net/9p/transport.h> #include <net/9p/transport.h>
#include <linux/scatterlist.h> #include <linux/scatterlist.h>
#include <linux/swap.h>
#include <linux/virtio.h> #include <linux/virtio.h>
#include <linux/virtio_9p.h> #include <linux/virtio_9p.h>
#include "trans_common.h" #include "trans_common.h"
...@@ -51,6 +52,8 @@ ...@@ -51,6 +52,8 @@
/* a single mutex to manage channel initialization and attachment */ /* a single mutex to manage channel initialization and attachment */
static DEFINE_MUTEX(virtio_9p_lock); static DEFINE_MUTEX(virtio_9p_lock);
static DECLARE_WAIT_QUEUE_HEAD(vp_wq);
static atomic_t vp_pinned = ATOMIC_INIT(0);
/** /**
* struct virtio_chan - per-instance transport information * struct virtio_chan - per-instance transport information
...@@ -78,7 +81,10 @@ struct virtio_chan { ...@@ -78,7 +81,10 @@ struct virtio_chan {
struct virtqueue *vq; struct virtqueue *vq;
int ring_bufs_avail; int ring_bufs_avail;
wait_queue_head_t *vc_wq; wait_queue_head_t *vc_wq;
/* This is global limit. Since we don't have a global structure,
* will be placing it in each channel.
*/
int p9_max_pages;
/* Scatterlist: can be too big for stack. */ /* Scatterlist: can be too big for stack. */
struct scatterlist sg[VIRTQUEUE_NUM]; struct scatterlist sg[VIRTQUEUE_NUM];
...@@ -141,34 +147,36 @@ static void req_done(struct virtqueue *vq) ...@@ -141,34 +147,36 @@ static void req_done(struct virtqueue *vq)
P9_DPRINTK(P9_DEBUG_TRANS, ": request done\n"); P9_DPRINTK(P9_DEBUG_TRANS, ": request done\n");
do { while (1) {
spin_lock_irqsave(&chan->lock, flags); spin_lock_irqsave(&chan->lock, flags);
rc = virtqueue_get_buf(chan->vq, &len); rc = virtqueue_get_buf(chan->vq, &len);
if (rc != NULL) { if (rc == NULL) {
if (!chan->ring_bufs_avail) {
chan->ring_bufs_avail = 1;
wake_up(chan->vc_wq);
}
spin_unlock_irqrestore(&chan->lock, flags);
P9_DPRINTK(P9_DEBUG_TRANS, ": rc %p\n", rc);
P9_DPRINTK(P9_DEBUG_TRANS, ": lookup tag %d\n",
rc->tag);
req = p9_tag_lookup(chan->client, rc->tag);
req->status = REQ_STATUS_RCVD;
if (req->tc->private) {
struct trans_rpage_info *rp = req->tc->private;
/*Release pages */
p9_release_req_pages(rp);
if (rp->rp_alloc)
kfree(rp);
req->tc->private = NULL;
}
p9_client_cb(chan->client, req);
} else {
spin_unlock_irqrestore(&chan->lock, flags); spin_unlock_irqrestore(&chan->lock, flags);
break;
}
chan->ring_bufs_avail = 1;
spin_unlock_irqrestore(&chan->lock, flags);
/* Wakeup if anyone waiting for VirtIO ring space. */
wake_up(chan->vc_wq);
P9_DPRINTK(P9_DEBUG_TRANS, ": rc %p\n", rc);
P9_DPRINTK(P9_DEBUG_TRANS, ": lookup tag %d\n", rc->tag);
req = p9_tag_lookup(chan->client, rc->tag);
if (req->tc->private) {
struct trans_rpage_info *rp = req->tc->private;
int p = rp->rp_nr_pages;
/*Release pages */
p9_release_req_pages(rp);
atomic_sub(p, &vp_pinned);
wake_up(&vp_wq);
if (rp->rp_alloc)
kfree(rp);
req->tc->private = NULL;
} }
} while (rc != NULL); req->status = REQ_STATUS_RCVD;
p9_client_cb(chan->client, req);
}
} }
/** /**
...@@ -263,7 +271,6 @@ p9_virtio_request(struct p9_client *client, struct p9_req_t *req) ...@@ -263,7 +271,6 @@ p9_virtio_request(struct p9_client *client, struct p9_req_t *req)
P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio request\n"); P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio request\n");
req_retry:
req->status = REQ_STATUS_SENT; req->status = REQ_STATUS_SENT;
if (req->tc->pbuf_size && (req->tc->pubuf && P9_IS_USER_CONTEXT)) { if (req->tc->pbuf_size && (req->tc->pubuf && P9_IS_USER_CONTEXT)) {
...@@ -271,6 +278,14 @@ p9_virtio_request(struct p9_client *client, struct p9_req_t *req) ...@@ -271,6 +278,14 @@ p9_virtio_request(struct p9_client *client, struct p9_req_t *req)
int rpinfo_size = sizeof(struct trans_rpage_info) + int rpinfo_size = sizeof(struct trans_rpage_info) +
sizeof(struct page *) * nr_pages; sizeof(struct page *) * nr_pages;
if (atomic_read(&vp_pinned) >= chan->p9_max_pages) {
err = wait_event_interruptible(vp_wq,
atomic_read(&vp_pinned) < chan->p9_max_pages);
if (err == -ERESTARTSYS)
return err;
P9_DPRINTK(P9_DEBUG_TRANS, "9p: May gup pages now.\n");
}
if (rpinfo_size <= (req->tc->capacity - req->tc->size)) { if (rpinfo_size <= (req->tc->capacity - req->tc->size)) {
/* We can use sdata */ /* We can use sdata */
req->tc->private = req->tc->sdata + req->tc->size; req->tc->private = req->tc->sdata + req->tc->size;
...@@ -293,9 +308,12 @@ p9_virtio_request(struct p9_client *client, struct p9_req_t *req) ...@@ -293,9 +308,12 @@ p9_virtio_request(struct p9_client *client, struct p9_req_t *req)
if (rpinfo->rp_alloc) if (rpinfo->rp_alloc)
kfree(rpinfo); kfree(rpinfo);
return err; return err;
} else {
atomic_add(rpinfo->rp_nr_pages, &vp_pinned);
} }
} }
req_retry_pinned:
spin_lock_irqsave(&chan->lock, flags); spin_lock_irqsave(&chan->lock, flags);
/* Handle out VirtIO ring buffers */ /* Handle out VirtIO ring buffers */
...@@ -356,7 +374,7 @@ p9_virtio_request(struct p9_client *client, struct p9_req_t *req) ...@@ -356,7 +374,7 @@ p9_virtio_request(struct p9_client *client, struct p9_req_t *req)
return err; return err;
P9_DPRINTK(P9_DEBUG_TRANS, "9p:Retry virtio request\n"); P9_DPRINTK(P9_DEBUG_TRANS, "9p:Retry virtio request\n");
goto req_retry; goto req_retry_pinned;
} else { } else {
spin_unlock_irqrestore(&chan->lock, flags); spin_unlock_irqrestore(&chan->lock, flags);
P9_DPRINTK(P9_DEBUG_TRANS, P9_DPRINTK(P9_DEBUG_TRANS,
...@@ -453,6 +471,8 @@ static int p9_virtio_probe(struct virtio_device *vdev) ...@@ -453,6 +471,8 @@ static int p9_virtio_probe(struct virtio_device *vdev)
} }
init_waitqueue_head(chan->vc_wq); init_waitqueue_head(chan->vc_wq);
chan->ring_bufs_avail = 1; chan->ring_bufs_avail = 1;
/* Ceiling limit to avoid denial of service attacks */
chan->p9_max_pages = nr_free_buffer_pages()/4;
mutex_lock(&virtio_9p_lock); mutex_lock(&virtio_9p_lock);
list_add_tail(&chan->chan_list, &virtio_chan_list); list_add_tail(&chan->chan_list, &virtio_chan_list);
......
...@@ -92,7 +92,7 @@ int p9_idpool_get(struct p9_idpool *p) ...@@ -92,7 +92,7 @@ int p9_idpool_get(struct p9_idpool *p)
unsigned long flags; unsigned long flags;
retry: retry:
if (idr_pre_get(&p->pool, GFP_KERNEL) == 0) if (idr_pre_get(&p->pool, GFP_NOFS) == 0)
return 0; return 0;
spin_lock_irqsave(&p->lock, flags); spin_lock_irqsave(&p->lock, flags);
......
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