Skip to content

Commit

Permalink
[PATCH] fuse: fix bitfield race
Browse files Browse the repository at this point in the history
Fix race in setting bitfields of fuse_conn.  Spotted by Andrew Morton.

The two fields ->connected and ->mounted were always changed with the
fuse_lock held.  But other bitfields in the same structure were changed
without the lock.  In theory this could lead to losing the assignment of
even the ones under lock.  The chosen solution is to change these two
fields to be a full unsigned type.  The other bitfields aren't "important"
enough to warrant the extra complexity of full locking or changing them to
bitops.

For all bitfields document why they are safe wrt. concurrent
assignments.

Also make the initialization of the 'num_waiting' atomic counter explicit.

Signed-off-by: Miklos Szeredi <miklos@szeredi.hu>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
  • Loading branch information
Miklos Szeredi authored and Linus Torvalds committed Jan 17, 2006
1 parent bacac38 commit 095da6c
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 3 deletions.
24 changes: 21 additions & 3 deletions fs/fuse/fuse_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,11 @@ struct fuse_out {
/** Header returned from userspace */
struct fuse_out_header h;

/*
* The following bitfields are not changed during the request
* processing
*/

/** Last argument is variable length (can be shorter than
arg->size) */
unsigned argvar:1;
Expand Down Expand Up @@ -136,6 +141,12 @@ struct fuse_req {
/** refcount */
atomic_t count;

/*
* The following bitfields are either set once before the
* request is queued or setting/clearing them is protected by
* fuse_lock
*/

/** True if the request has reply */
unsigned isreply:1;

Expand Down Expand Up @@ -250,15 +261,22 @@ struct fuse_conn {
u64 reqctr;

/** Mount is active */
unsigned mounted : 1;
unsigned mounted;

/** Connection established, cleared on umount, connection
abort and device release */
unsigned connected : 1;
unsigned connected;

/** Connection failed (version mismatch) */
/** Connection failed (version mismatch). Cannot race with
setting other bitfields since it is only set once in INIT
reply, before any other request, and never cleared */
unsigned conn_error : 1;

/*
* The following bitfields are only for optimization purposes
* and hence races in setting them will not cause malfunction
*/

/** Is fsync not implemented by fs? */
unsigned no_fsync : 1;

Expand Down
2 changes: 2 additions & 0 deletions fs/fuse/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,7 @@ static struct fuse_conn *new_conn(void)
init_rwsem(&fc->sbput_sem);
kobj_set_kset_s(fc, connections_subsys);
kobject_init(&fc->kobj);
atomic_set(&fc->num_waiting, 0);
for (i = 0; i < FUSE_MAX_OUTSTANDING; i++) {
struct fuse_req *req = fuse_request_alloc();
if (!req) {
Expand Down Expand Up @@ -492,6 +493,7 @@ static void fuse_send_init(struct fuse_conn *fc)
to be exactly one request available */
struct fuse_req *req = fuse_get_request(fc);
struct fuse_init_in *arg = &req->misc.init_in;

arg->major = FUSE_KERNEL_VERSION;
arg->minor = FUSE_KERNEL_MINOR_VERSION;
req->in.h.opcode = FUSE_INIT;
Expand Down

0 comments on commit 095da6c

Please sign in to comment.