Skip to content

Commit

Permalink
Merge tag '9p-for-4.20' of git://github.com/martinetd/linux
Browse files Browse the repository at this point in the history
Pull 9p updates from Dominique Martinet:
 "Highlights this time around are the end of Matthew's work to remove
  the custom 9p request cache and use a slab directly for requests, with
  some extra patches on my end to not degrade performance, but it's a
  very good cleanup.

  Tomas and I fixed a few more syzkaller bugs (refcount is the big one),
  and I had a go at the coverity bugs and at some of the bugzilla
  reports we had open for a while.

  I'm a bit disappointed that I couldn't get much reviews for a few of
  my own patches, but the big ones got some and it's all been soaking in
  linux-next for quite a while so I think it should be OK.

  Summary:

   - Finish removing the custom 9p request cache mechanism

   - Embed part of the fcall in the request to have better slab
     performance (msize usually is power of two aligned)

   - syzkaller fixes:
      * add a refcount to 9p requests to avoid use after free
      * a few double free issues

   - A few coverity fixes

   - Some old patches that were in the bugzilla:
      * do not trust pdu content for size header
      * mount option for lock retry interval"

* tag '9p-for-4.20' of git://github.com/martinetd/linux: (21 commits)
  9p/trans_fd: put worker reqs on destroy
  9p/trans_fd: abort p9_read_work if req status changed
  9p: potential NULL dereference
  9p locks: fix glock.client_id leak in do_lock
  9p: p9dirent_read: check network-provided name length
  9p/rdma: remove useless check in cm_event_handler
  9p: acl: fix uninitialized iattr access
  9p locks: add mount option for lock retry interval
  9p: do not trust pdu content for stat item size
  9p: Rename req to rreq in trans_fd
  9p: fix spelling mistake in fall-through annotation
  9p/rdma: do not disconnect on down_interruptible EAGAIN
  9p: Add refcount to p9_req_t
  9p: rename p9_free_req() function
  9p: add a per-client fcall kmem_cache
  9p: embed fcall in req to round down buffer allocs
  9p: Remove p9_idpool
  9p: Use a slab for allocating requests
  9p: clear dangling pointers in p9stat_free
  v9fs_dir_readdir: fix double-free on p9stat_read error
  ...
  • Loading branch information
Linus Torvalds committed Oct 29, 2018
2 parents 673c790 + fb488fc commit 7da4221
Show file tree
Hide file tree
Showing 16 changed files with 482 additions and 551 deletions.
2 changes: 1 addition & 1 deletion fs/9p/acl.c
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ static int v9fs_xattr_set_acl(const struct xattr_handler *handler,
switch (handler->flags) {
case ACL_TYPE_ACCESS:
if (acl) {
struct iattr iattr;
struct iattr iattr = { 0 };
struct posix_acl *old_acl = acl;

retval = posix_acl_update_mode(inode, &iattr.ia_mode, &acl);
Expand Down
21 changes: 21 additions & 0 deletions fs/9p/v9fs.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ enum {
Opt_cache_loose, Opt_fscache, Opt_mmap,
/* Access options */
Opt_access, Opt_posixacl,
/* Lock timeout option */
Opt_locktimeout,
/* Error token */
Opt_err
};
Expand All @@ -80,6 +82,7 @@ static const match_table_t tokens = {
{Opt_cachetag, "cachetag=%s"},
{Opt_access, "access=%s"},
{Opt_posixacl, "posixacl"},
{Opt_locktimeout, "locktimeout=%u"},
{Opt_err, NULL}
};

Expand Down Expand Up @@ -187,6 +190,7 @@ static int v9fs_parse_options(struct v9fs_session_info *v9ses, char *opts)
#ifdef CONFIG_9P_FSCACHE
v9ses->cachetag = NULL;
#endif
v9ses->session_lock_timeout = P9_LOCK_TIMEOUT;

if (!opts)
return 0;
Expand Down Expand Up @@ -359,6 +363,23 @@ static int v9fs_parse_options(struct v9fs_session_info *v9ses, char *opts)
#endif
break;

case Opt_locktimeout:
r = match_int(&args[0], &option);
if (r < 0) {
p9_debug(P9_DEBUG_ERROR,
"integer field, but no integer?\n");
ret = r;
continue;
}
if (option < 1) {
p9_debug(P9_DEBUG_ERROR,
"locktimeout must be a greater than zero integer.\n");
ret = -EINVAL;
continue;
}
v9ses->session_lock_timeout = (long)option * HZ;
break;

default:
continue;
}
Expand Down
1 change: 1 addition & 0 deletions fs/9p/v9fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ struct v9fs_session_info {
struct p9_client *clnt; /* 9p client */
struct list_head slist; /* list of sessions registered with v9fs */
struct rw_semaphore rename_sem;
long session_lock_timeout; /* retry interval for blocking locks */
};

/* cache_validity flags */
Expand Down
19 changes: 3 additions & 16 deletions fs/9p/vfs_dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,15 +76,6 @@ static inline int dt_type(struct p9_wstat *mistat)
return rettype;
}

static void p9stat_init(struct p9_wstat *stbuf)
{
stbuf->name = NULL;
stbuf->uid = NULL;
stbuf->gid = NULL;
stbuf->muid = NULL;
stbuf->extension = NULL;
}

/**
* v9fs_alloc_rdir_buf - Allocate buffer used for read and readdir
* @filp: opened file structure
Expand Down Expand Up @@ -114,7 +105,6 @@ static int v9fs_dir_readdir(struct file *file, struct dir_context *ctx)
int err = 0;
struct p9_fid *fid;
int buflen;
int reclen = 0;
struct p9_rdir *rdir;
struct kvec kvec;

Expand Down Expand Up @@ -145,24 +135,21 @@ static int v9fs_dir_readdir(struct file *file, struct dir_context *ctx)
rdir->tail = n;
}
while (rdir->head < rdir->tail) {
p9stat_init(&st);
err = p9stat_read(fid->clnt, rdir->buf + rdir->head,
rdir->tail - rdir->head, &st);
if (err) {
if (err <= 0) {
p9_debug(P9_DEBUG_VFS, "returned %d\n", err);
p9stat_free(&st);
return -EIO;
}
reclen = st.size+2;

over = !dir_emit(ctx, st.name, strlen(st.name),
v9fs_qid2ino(&st.qid), dt_type(&st));
p9stat_free(&st);
if (over)
return 0;

rdir->head += reclen;
ctx->pos += reclen;
rdir->head += err;
ctx->pos += err;
}
}
}
Expand Down
24 changes: 20 additions & 4 deletions fs/9p/vfs_file.c
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ static int v9fs_file_do_lock(struct file *filp, int cmd, struct file_lock *fl)
uint8_t status = P9_LOCK_ERROR;
int res = 0;
unsigned char fl_type;
struct v9fs_session_info *v9ses;

fid = filp->private_data;
BUG_ON(fid == NULL);
Expand Down Expand Up @@ -189,6 +190,8 @@ static int v9fs_file_do_lock(struct file *filp, int cmd, struct file_lock *fl)
if (IS_SETLKW(cmd))
flock.flags = P9_LOCK_FLAGS_BLOCK;

v9ses = v9fs_inode2v9ses(file_inode(filp));

/*
* if its a blocked request and we get P9_LOCK_BLOCKED as the status
* for lock request, keep on trying
Expand All @@ -202,8 +205,17 @@ static int v9fs_file_do_lock(struct file *filp, int cmd, struct file_lock *fl)
break;
if (status == P9_LOCK_BLOCKED && !IS_SETLKW(cmd))
break;
if (schedule_timeout_interruptible(P9_LOCK_TIMEOUT) != 0)
if (schedule_timeout_interruptible(v9ses->session_lock_timeout)
!= 0)
break;
/*
* p9_client_lock_dotl overwrites flock.client_id with the
* server message, free and reuse the client name
*/
if (flock.client_id != fid->clnt->name) {
kfree(flock.client_id);
flock.client_id = fid->clnt->name;
}
}

/* map 9p status to VFS status */
Expand All @@ -216,7 +228,7 @@ static int v9fs_file_do_lock(struct file *filp, int cmd, struct file_lock *fl)
break;
default:
WARN_ONCE(1, "unknown lock status code: %d\n", status);
/* fallthough */
/* fall through */
case P9_LOCK_ERROR:
case P9_LOCK_GRACE:
res = -ENOLCK;
Expand All @@ -235,6 +247,8 @@ static int v9fs_file_do_lock(struct file *filp, int cmd, struct file_lock *fl)
locks_lock_file_wait(filp, fl);
fl->fl_type = fl_type;
}
if (flock.client_id != fid->clnt->name)
kfree(flock.client_id);
out:
return res;
}
Expand Down Expand Up @@ -269,7 +283,7 @@ static int v9fs_file_getlock(struct file *filp, struct file_lock *fl)

res = p9_client_getlock_dotl(fid, &glock);
if (res < 0)
return res;
goto out;
/* map 9p lock type to os lock type */
switch (glock.type) {
case P9_LOCK_TYPE_RDLCK:
Expand All @@ -290,7 +304,9 @@ static int v9fs_file_getlock(struct file *filp, struct file_lock *fl)
fl->fl_end = glock.start + glock.length - 1;
fl->fl_pid = -glock.proc_id;
}
kfree(glock.client_id);
out:
if (glock.client_id != fid->clnt->name)
kfree(glock.client_id);
return res;
}

Expand Down
12 changes: 4 additions & 8 deletions include/net/9p/9p.h
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,9 @@ enum p9_qid_t {
#define P9_NOFID (u32)(~0)
#define P9_MAXWELEM 16

/* Minimal header size: size[4] type[1] tag[2] */
#define P9_HDRSZ 7

/* ample room for Twrite/Rread header */
#define P9_IOHDRSZ 24

Expand Down Expand Up @@ -558,19 +561,12 @@ struct p9_fcall {
size_t offset;
size_t capacity;

struct kmem_cache *cache;
u8 *sdata;
};

struct p9_idpool;

int p9_errstr2errno(char *errstr, int len);

struct p9_idpool *p9_idpool_create(void);
void p9_idpool_destroy(struct p9_idpool *);
int p9_idpool_get(struct p9_idpool *p);
void p9_idpool_put(int id, struct p9_idpool *p);
int p9_idpool_check(int id, struct p9_idpool *p);

int p9_error_init(void);
int p9_trans_fd_init(void);
void p9_trans_fd_exit(void);
Expand Down
71 changes: 27 additions & 44 deletions include/net/9p/client.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,22 +64,15 @@ enum p9_trans_status {

/**
* enum p9_req_status_t - status of a request
* @REQ_STATUS_IDLE: request slot unused
* @REQ_STATUS_ALLOC: request has been allocated but not sent
* @REQ_STATUS_UNSENT: request waiting to be sent
* @REQ_STATUS_SENT: request sent to server
* @REQ_STATUS_RCVD: response received from server
* @REQ_STATUS_FLSHD: request has been flushed
* @REQ_STATUS_ERROR: request encountered an error on the client side
*
* The @REQ_STATUS_IDLE state is used to mark a request slot as unused
* but use is actually tracked by the idpool structure which handles tag
* id allocation.
*
*/

enum p9_req_status_t {
REQ_STATUS_IDLE,
REQ_STATUS_ALLOC,
REQ_STATUS_UNSENT,
REQ_STATUS_SENT,
Expand All @@ -92,70 +85,46 @@ enum p9_req_status_t {
* struct p9_req_t - request slots
* @status: status of this request slot
* @t_err: transport error
* @flush_tag: tag of request being flushed (for flush requests)
* @wq: wait_queue for the client to block on for this request
* @tc: the request fcall structure
* @rc: the response fcall structure
* @aux: transport specific data (provided for trans_fd migration)
* @req_list: link for higher level objects to chain requests
*
* Transport use an array to track outstanding requests
* instead of a list. While this may incurr overhead during initial
* allocation or expansion, it makes request lookup much easier as the
* tag id is a index into an array. (We use tag+1 so that we can accommodate
* the -1 tag for the T_VERSION request).
* This also has the nice effect of only having to allocate wait_queues
* once, instead of constantly allocating and freeing them. Its possible
* other resources could benefit from this scheme as well.
*
*/

struct p9_req_t {
int status;
int t_err;
struct kref refcount;
wait_queue_head_t wq;
struct p9_fcall *tc;
struct p9_fcall *rc;
struct p9_fcall tc;
struct p9_fcall rc;
void *aux;

struct list_head req_list;
};

/**
* struct p9_client - per client instance state
* @lock: protect @fidlist
* @lock: protect @fids and @reqs
* @msize: maximum data size negotiated by protocol
* @dotu: extension flags negotiated by protocol
* @proto_version: 9P protocol version to use
* @trans_mod: module API instantiated with this client
* @status: connection state
* @trans: tranport instance state and API
* @fids: All active FID handles
* @tagpool - transaction id accounting for session
* @reqs - 2D array of requests
* @max_tag - current maximum tag id allocated
* @name - node name used as client id
* @reqs: All active requests.
* @name: node name used as client id
*
* The client structure is used to keep track of various per-client
* state that has been instantiated.
* In order to minimize per-transaction overhead we use a
* simple array to lookup requests instead of a hash table
* or linked list. In order to support larger number of
* transactions, we make this a 2D array, allocating new rows
* when we need to grow the total number of the transactions.
*
* Each row is 256 requests and we'll support up to 256 rows for
* a total of 64k concurrent requests per session.
*
* Bugs: duplicated data and potentially unnecessary elements.
*/

struct p9_client {
spinlock_t lock; /* protect client structure */
spinlock_t lock;
unsigned int msize;
unsigned char proto_version;
struct p9_trans_module *trans_mod;
enum p9_trans_status status;
void *trans;
struct kmem_cache *fcall_cache;

union {
struct {
Expand All @@ -170,10 +139,7 @@ struct p9_client {
} trans_opts;

struct idr fids;

struct p9_idpool *tagpool;
struct p9_req_t *reqs[P9_ROW_MAXTAG];
int max_tag;
struct idr reqs;

char name[__NEW_UTS_LEN + 1];
};
Expand Down Expand Up @@ -266,7 +232,21 @@ int p9_client_mkdir_dotl(struct p9_fid *fid, const char *name, int mode,
kgid_t gid, struct p9_qid *);
int p9_client_lock_dotl(struct p9_fid *fid, struct p9_flock *flock, u8 *status);
int p9_client_getlock_dotl(struct p9_fid *fid, struct p9_getlock *fl);
void p9_fcall_fini(struct p9_fcall *fc);
struct p9_req_t *p9_tag_lookup(struct p9_client *, u16);

static inline void p9_req_get(struct p9_req_t *r)
{
kref_get(&r->refcount);
}

static inline int p9_req_try_get(struct p9_req_t *r)
{
return kref_get_unless_zero(&r->refcount);
}

int p9_req_put(struct p9_req_t *r);

void p9_client_cb(struct p9_client *c, struct p9_req_t *req, int status);

int p9_parse_header(struct p9_fcall *, int32_t *, int8_t *, int16_t *, int);
Expand All @@ -279,4 +259,7 @@ struct p9_fid *p9_client_xattrwalk(struct p9_fid *, const char *, u64 *);
int p9_client_xattrcreate(struct p9_fid *, const char *, u64, int);
int p9_client_readlink(struct p9_fid *fid, char **target);

int p9_client_init(void);
void p9_client_exit(void);

#endif /* NET_9P_CLIENT_H */
1 change: 0 additions & 1 deletion net/9p/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ obj-$(CONFIG_NET_9P_RDMA) += 9pnet_rdma.o
mod.o \
client.o \
error.o \
util.o \
protocol.o \
trans_fd.o \
trans_common.o \
Expand Down
Loading

0 comments on commit 7da4221

Please sign in to comment.