Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 825d6d33 authored by Miklos Szeredi's avatar Miklos Szeredi
Browse files

fuse: req use bitops



Finer grained locking will mean there's no single lock to protect
modification of bitfileds in fuse_req.

So move to using bitops.  Can use the non-atomic variants for those which
happen while the request definitely has only one reference.

Signed-off-by: default avatarMiklos Szeredi <mszeredi@suse.cz>
Reviewed-by: default avatarAshish Samant <ashish.samant@oracle.com>
parent 0d8e84b0
Loading
Loading
Loading
Loading
+36 −35
Original line number Diff line number Diff line
@@ -181,8 +181,10 @@ static struct fuse_req *__fuse_get_req(struct fuse_conn *fc, unsigned npages,
	}

	fuse_req_init_context(req);
	req->waiting = 1;
	req->background = for_background;
	__set_bit(FR_WAITING, &req->flags);
	if (for_background)
		__set_bit(FR_BACKGROUND, &req->flags);

	return req;

 out:
@@ -272,15 +274,15 @@ struct fuse_req *fuse_get_req_nofail_nopages(struct fuse_conn *fc,
		req = get_reserved_req(fc, file);

	fuse_req_init_context(req);
	req->waiting = 1;
	req->background = 0;
	__set_bit(FR_WAITING, &req->flags);
	__clear_bit(FR_BACKGROUND, &req->flags);
	return req;
}

void fuse_put_request(struct fuse_conn *fc, struct fuse_req *req)
{
	if (atomic_dec_and_test(&req->count)) {
		if (unlikely(req->background)) {
		if (test_bit(FR_BACKGROUND, &req->flags)) {
			/*
			 * We get here in the unlikely case that a background
			 * request was allocated but not sent
@@ -291,9 +293,9 @@ void fuse_put_request(struct fuse_conn *fc, struct fuse_req *req)
			spin_unlock(&fc->lock);
		}

		if (req->waiting) {
		if (test_bit(FR_WAITING, &req->flags)) {
			__clear_bit(FR_WAITING, &req->flags);
			atomic_dec(&fc->num_waiting);
			req->waiting = 0;
		}

		if (req->stolen_file)
@@ -385,9 +387,8 @@ __releases(fc->lock)
	list_del_init(&req->list);
	list_del_init(&req->intr_entry);
	req->state = FUSE_REQ_FINISHED;
	if (req->background) {
		req->background = 0;

	if (test_bit(FR_BACKGROUND, &req->flags)) {
		clear_bit(FR_BACKGROUND, &req->flags);
		if (fc->num_background == fc->max_background)
			fc->blocked = 0;

@@ -442,12 +443,12 @@ __acquires(fc->lock)
		if (req->state == FUSE_REQ_FINISHED)
			return;

		req->interrupted = 1;
		set_bit(FR_INTERRUPTED, &req->flags);
		if (req->state == FUSE_REQ_SENT)
			queue_interrupt(fc, req);
	}

	if (!req->force) {
	if (!test_bit(FR_FORCE, &req->flags)) {
		sigset_t oldset;

		/* Only fatal signals may interrupt this */
@@ -478,7 +479,7 @@ __acquires(fc->lock)

static void __fuse_request_send(struct fuse_conn *fc, struct fuse_req *req)
{
	BUG_ON(req->background);
	BUG_ON(test_bit(FR_BACKGROUND, &req->flags));
	spin_lock(&fc->lock);
	if (!fc->connected)
		req->out.h.error = -ENOTCONN;
@@ -496,9 +497,9 @@ static void __fuse_request_send(struct fuse_conn *fc, struct fuse_req *req)

void fuse_request_send(struct fuse_conn *fc, struct fuse_req *req)
{
	req->isreply = 1;
	if (!req->waiting) {
		req->waiting = 1;
	__set_bit(FR_ISREPLY, &req->flags);
	if (!test_bit(FR_WAITING, &req->flags)) {
		__set_bit(FR_WAITING, &req->flags);
		atomic_inc(&fc->num_waiting);
	}
	__fuse_request_send(fc, req);
@@ -578,12 +579,12 @@ ssize_t fuse_simple_request(struct fuse_conn *fc, struct fuse_args *args)
void fuse_request_send_background_locked(struct fuse_conn *fc,
					 struct fuse_req *req)
{
	BUG_ON(!req->background);
	if (!req->waiting) {
		req->waiting = 1;
	BUG_ON(!test_bit(FR_BACKGROUND, &req->flags));
	if (!test_bit(FR_WAITING, &req->flags)) {
		__set_bit(FR_WAITING, &req->flags);
		atomic_inc(&fc->num_waiting);
	}
	req->isreply = 1;
	__set_bit(FR_ISREPLY, &req->flags);
	fc->num_background++;
	if (fc->num_background == fc->max_background)
		fc->blocked = 1;
@@ -617,7 +618,7 @@ static int fuse_request_send_notify_reply(struct fuse_conn *fc,
{
	int err = -ENODEV;

	req->isreply = 0;
	__clear_bit(FR_ISREPLY, &req->flags);
	req->in.h.unique = unique;
	spin_lock(&fc->lock);
	if (fc->connected) {
@@ -644,7 +645,7 @@ void fuse_force_forget(struct file *file, u64 nodeid)
	req->in.numargs = 1;
	req->in.args[0].size = sizeof(inarg);
	req->in.args[0].value = &inarg;
	req->isreply = 0;
	__clear_bit(FR_ISREPLY, &req->flags);
	__fuse_request_send(fc, req);
	/* ignore errors */
	fuse_put_request(fc, req);
@@ -660,10 +661,10 @@ static int lock_request(struct fuse_conn *fc, struct fuse_req *req)
	int err = 0;
	if (req) {
		spin_lock(&fc->lock);
		if (req->aborted)
		if (test_bit(FR_ABORTED, &req->flags))
			err = -ENOENT;
		else
			req->locked = 1;
			set_bit(FR_LOCKED, &req->flags);
		spin_unlock(&fc->lock);
	}
	return err;
@@ -678,10 +679,10 @@ static int unlock_request(struct fuse_conn *fc, struct fuse_req *req)
	int err = 0;
	if (req) {
		spin_lock(&fc->lock);
		if (req->aborted)
		if (test_bit(FR_ABORTED, &req->flags))
			err = -ENOENT;
		else
			req->locked = 0;
			clear_bit(FR_LOCKED, &req->flags);
		spin_unlock(&fc->lock);
	}
	return err;
@@ -902,7 +903,7 @@ static int fuse_try_move_page(struct fuse_copy_state *cs, struct page **pagep)

	err = 0;
	spin_lock(&cs->fc->lock);
	if (cs->req->aborted)
	if (test_bit(FR_ABORTED, &cs->req->flags))
		err = -ENOENT;
	else
		*pagep = newpage;
@@ -1309,7 +1310,7 @@ static ssize_t fuse_dev_do_read(struct fuse_conn *fc, struct file *file,
				     (struct fuse_arg *) in->args, 0);
	fuse_copy_finish(cs);
	spin_lock(&fc->lock);
	req->locked = 0;
	clear_bit(FR_LOCKED, &req->flags);
	if (!fc->connected) {
		request_end(fc, req);
		return -ENODEV;
@@ -1319,12 +1320,12 @@ static ssize_t fuse_dev_do_read(struct fuse_conn *fc, struct file *file,
		request_end(fc, req);
		return err;
	}
	if (!req->isreply)
	if (!test_bit(FR_ISREPLY, &req->flags)) {
		request_end(fc, req);
	else {
	} else {
		req->state = FUSE_REQ_SENT;
		list_move_tail(&req->list, &fc->processing);
		if (req->interrupted)
		if (test_bit(FR_INTERRUPTED, &req->flags))
			queue_interrupt(fc, req);
		spin_unlock(&fc->lock);
	}
@@ -1921,7 +1922,7 @@ static ssize_t fuse_dev_do_write(struct fuse_conn *fc,
	req->state = FUSE_REQ_WRITING;
	list_move(&req->list, &fc->io);
	req->out.h = oh;
	req->locked = 1;
	set_bit(FR_LOCKED, &req->flags);
	cs->req = req;
	if (!req->out.page_replace)
		cs->move_pages = 0;
@@ -1931,7 +1932,7 @@ static ssize_t fuse_dev_do_write(struct fuse_conn *fc,
	fuse_copy_finish(cs);

	spin_lock(&fc->lock);
	req->locked = 0;
	clear_bit(FR_LOCKED, &req->flags);
	if (!fc->connected)
		err = -ENOENT;
	else if (err)
@@ -2097,8 +2098,8 @@ __acquires(fc->lock)

	list_for_each_entry_safe(req, next, &fc->io, list) {
		req->out.h.error = -ECONNABORTED;
		req->aborted = 1;
		if (!req->locked)
		set_bit(FR_ABORTED, &req->flags);
		if (!test_bit(FR_LOCKED, &req->flags))
			list_move(&req->list, &to_end);
	}
	while (!list_empty(&to_end)) {
+9 −8
Original line number Diff line number Diff line
@@ -96,17 +96,17 @@ static void fuse_file_put(struct fuse_file *ff, bool sync)
			 * Drop the release request when client does not
			 * implement 'open'
			 */
			req->background = 0;
			__clear_bit(FR_BACKGROUND, &req->flags);
			iput(req->misc.release.inode);
			fuse_put_request(ff->fc, req);
		} else if (sync) {
			req->background = 0;
			__clear_bit(FR_BACKGROUND, &req->flags);
			fuse_request_send(ff->fc, req);
			iput(req->misc.release.inode);
			fuse_put_request(ff->fc, req);
		} else {
			req->end = fuse_release_end;
			req->background = 1;
			__set_bit(FR_BACKGROUND, &req->flags);
			fuse_request_send_background(ff->fc, req);
		}
		kfree(ff);
@@ -299,8 +299,8 @@ void fuse_sync_release(struct fuse_file *ff, int flags)
{
	WARN_ON(atomic_read(&ff->count) > 1);
	fuse_prepare_release(ff, flags, FUSE_RELEASE);
	ff->reserved_req->force = 1;
	ff->reserved_req->background = 0;
	__set_bit(FR_FORCE, &ff->reserved_req->flags);
	__clear_bit(FR_BACKGROUND, &ff->reserved_req->flags);
	fuse_request_send(ff->fc, ff->reserved_req);
	fuse_put_request(ff->fc, ff->reserved_req);
	kfree(ff);
@@ -426,7 +426,7 @@ static int fuse_flush(struct file *file, fl_owner_t id)
	req->in.numargs = 1;
	req->in.args[0].size = sizeof(inarg);
	req->in.args[0].value = &inarg;
	req->force = 1;
	__set_bit(FR_FORCE, &req->flags);
	fuse_request_send(fc, req);
	err = req->out.h.error;
	fuse_put_request(fc, req);
@@ -1611,7 +1611,8 @@ static int fuse_writepage_locked(struct page *page)
	if (!req)
		goto err;

	req->background = 1; /* writeback always goes to bg_queue */
	/* writeback always goes to bg_queue */
	__set_bit(FR_BACKGROUND, &req->flags);
	tmp_page = alloc_page(GFP_NOFS | __GFP_HIGHMEM);
	if (!tmp_page)
		goto err_free;
@@ -1830,7 +1831,7 @@ static int fuse_writepages_fill(struct page *page,
		req->misc.write.in.write_flags |= FUSE_WRITE_CACHE;
		req->misc.write.next = NULL;
		req->in.argpages = 1;
		req->background = 1;
		__set_bit(FR_BACKGROUND, &req->flags);
		req->num_pages = 0;
		req->end = fuse_writepage_end;
		req->inode = inode;
+23 −26
Original line number Diff line number Diff line
@@ -266,6 +266,27 @@ struct fuse_io_priv {
	struct completion *done;
};

/**
 * Request flags
 *
 * FR_ISREPLY:		set if the request has reply
 * FR_FORCE:		force sending of the request even if interrupted
 * FR_BACKGROUND:	request is sent in the background
 * FR_WAITING:		request is counted as "waiting"
 * FR_ABORTED:		the request was aborted
 * FR_INTERRUPTED:	the request has been interrupted
 * FR_LOCKED:		data is being copied to/from the request
 */
enum fuse_req_flag {
	FR_ISREPLY,
	FR_FORCE,
	FR_BACKGROUND,
	FR_WAITING,
	FR_ABORTED,
	FR_INTERRUPTED,
	FR_LOCKED,
};

/**
 * A request to the client
 */
@@ -283,32 +304,8 @@ struct fuse_req {
	/** Unique ID for the interrupt request */
	u64 intr_unique;

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

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

	/** Force sending of the request even if interrupted */
	unsigned force:1;

	/** The request was aborted */
	unsigned aborted:1;

	/** Request is sent in the background */
	unsigned background:1;

	/** The request has been interrupted */
	unsigned interrupted:1;

	/** Data is being copied to/from the request */
	unsigned locked:1;

	/** Request is counted as "waiting" */
	unsigned waiting:1;
	/* Request flags, updated with test/set/clear_bit() */
	unsigned long flags;

	/** State of the request */
	enum fuse_req_state state;
+3 −3
Original line number Diff line number Diff line
@@ -362,8 +362,8 @@ static void fuse_send_destroy(struct fuse_conn *fc)
	if (req && fc->conn_init) {
		fc->destroy_req = NULL;
		req->in.h.opcode = FUSE_DESTROY;
		req->force = 1;
		req->background = 0;
		__set_bit(FR_FORCE, &req->flags);
		__clear_bit(FR_BACKGROUND, &req->flags);
		fuse_request_send(fc, req);
		fuse_put_request(fc, req);
	}
@@ -1060,7 +1060,7 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)
	init_req = fuse_request_alloc(0);
	if (!init_req)
		goto err_put_root;
	init_req->background = 1;
	__set_bit(FR_BACKGROUND, &init_req->flags);

	if (is_bdev) {
		fc->destroy_req = fuse_request_alloc(0);