Skip to content

Commit dfee9c2

Browse files
committed
Merge tag 'fuse-update-5.1' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse
Pull fuse updates from Miklos Szeredi: "Scalability and performance improvements, as well as minor bug fixes and cleanups" * tag 'fuse-update-5.1' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse: (25 commits) fuse: cache readdir calls if filesystem opts out of opendir fuse: support clients that don't implement 'opendir' fuse: lift bad inode checks into callers fuse: multiplex cached/direct_io file operations fuse add copy_file_range to direct io fops fuse: use iov_iter based generic splice helpers fuse: Switch to using async direct IO for FOPEN_DIRECT_IO fuse: use atomic64_t for khctr fuse: clean up aborted fuse: Protect ff->reserved_req via corresponding fi->lock fuse: Protect fi->nlookup with fi->lock fuse: Introduce fi->lock to protect write related fields fuse: Convert fc->attr_version into atomic64_t fuse: Add fuse_inode argument to fuse_prepare_release() fuse: Verify userspace asks to requeue interrupt that we really sent fuse: Do some refactoring in fuse_dev_do_write() fuse: Wake up req->waitq of only if not background fuse: Optimize request_end() by not taking fiq->waitq.lock fuse: Kill fasync only if interrupt is queued in queue_interrupt() fuse: Remove stale comment in end_requests() ...
2 parents 7b47a9e + fabf7e0 commit dfee9c2

File tree

9 files changed

+327
-260
lines changed

9 files changed

+327
-260
lines changed

fs/fuse/control.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,9 @@ static ssize_t fuse_conn_abort_write(struct file *file, const char __user *buf,
3535
{
3636
struct fuse_conn *fc = fuse_ctl_file_conn_get(file);
3737
if (fc) {
38-
fuse_abort_conn(fc, true);
38+
if (fc->abort_err)
39+
fc->aborted = true;
40+
fuse_abort_conn(fc);
3941
fuse_conn_put(fc);
4042
}
4143
return count;

fs/fuse/cuse.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -141,10 +141,11 @@ static int cuse_open(struct inode *inode, struct file *file)
141141

142142
static int cuse_release(struct inode *inode, struct file *file)
143143
{
144+
struct fuse_inode *fi = get_fuse_inode(inode);
144145
struct fuse_file *ff = file->private_data;
145146
struct fuse_conn *fc = ff->fc;
146147

147-
fuse_sync_release(ff, file->f_flags);
148+
fuse_sync_release(fi, ff, file->f_flags);
148149
fuse_conn_put(fc);
149150

150151
return 0;
@@ -407,7 +408,7 @@ static void cuse_process_init_reply(struct fuse_conn *fc, struct fuse_req *req)
407408
err_region:
408409
unregister_chrdev_region(devt, 1);
409410
err:
410-
fuse_abort_conn(fc, false);
411+
fuse_abort_conn(fc);
411412
goto out;
412413
}
413414

@@ -586,7 +587,7 @@ static ssize_t cuse_class_abort_store(struct device *dev,
586587
{
587588
struct cuse_conn *cc = dev_get_drvdata(dev);
588589

589-
fuse_abort_conn(&cc->fc, false);
590+
fuse_abort_conn(&cc->fc);
590591
return count;
591592
}
592593
static DEVICE_ATTR(abort, 0200, NULL, cuse_class_abort_store);

fs/fuse/dev.c

Lines changed: 66 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -251,17 +251,18 @@ static struct fuse_req *get_reserved_req(struct fuse_conn *fc,
251251
struct file *file)
252252
{
253253
struct fuse_req *req = NULL;
254+
struct fuse_inode *fi = get_fuse_inode(file_inode(file));
254255
struct fuse_file *ff = file->private_data;
255256

256257
do {
257258
wait_event(fc->reserved_req_waitq, ff->reserved_req);
258-
spin_lock(&fc->lock);
259+
spin_lock(&fi->lock);
259260
if (ff->reserved_req) {
260261
req = ff->reserved_req;
261262
ff->reserved_req = NULL;
262263
req->stolen_file = get_file(file);
263264
}
264-
spin_unlock(&fc->lock);
265+
spin_unlock(&fi->lock);
265266
} while (!req);
266267

267268
return req;
@@ -273,16 +274,17 @@ static struct fuse_req *get_reserved_req(struct fuse_conn *fc,
273274
static void put_reserved_req(struct fuse_conn *fc, struct fuse_req *req)
274275
{
275276
struct file *file = req->stolen_file;
277+
struct fuse_inode *fi = get_fuse_inode(file_inode(file));
276278
struct fuse_file *ff = file->private_data;
277279

278280
WARN_ON(req->max_pages);
279-
spin_lock(&fc->lock);
281+
spin_lock(&fi->lock);
280282
memset(req, 0, sizeof(*req));
281283
fuse_request_init(req, NULL, NULL, 0);
282284
BUG_ON(ff->reserved_req);
283285
ff->reserved_req = req;
284286
wake_up_all(&fc->reserved_req_waitq);
285-
spin_unlock(&fc->lock);
287+
spin_unlock(&fi->lock);
286288
fput(file);
287289
}
288290

@@ -431,10 +433,16 @@ static void request_end(struct fuse_conn *fc, struct fuse_req *req)
431433

432434
if (test_and_set_bit(FR_FINISHED, &req->flags))
433435
goto put_request;
434-
435-
spin_lock(&fiq->waitq.lock);
436-
list_del_init(&req->intr_entry);
437-
spin_unlock(&fiq->waitq.lock);
436+
/*
437+
* test_and_set_bit() implies smp_mb() between bit
438+
* changing and below intr_entry check. Pairs with
439+
* smp_mb() from queue_interrupt().
440+
*/
441+
if (!list_empty(&req->intr_entry)) {
442+
spin_lock(&fiq->waitq.lock);
443+
list_del_init(&req->intr_entry);
444+
spin_unlock(&fiq->waitq.lock);
445+
}
438446
WARN_ON(test_bit(FR_PENDING, &req->flags));
439447
WARN_ON(test_bit(FR_SENT, &req->flags));
440448
if (test_bit(FR_BACKGROUND, &req->flags)) {
@@ -462,27 +470,43 @@ static void request_end(struct fuse_conn *fc, struct fuse_req *req)
462470
fc->active_background--;
463471
flush_bg_queue(fc);
464472
spin_unlock(&fc->bg_lock);
473+
} else {
474+
/* Wake up waiter sleeping in request_wait_answer() */
475+
wake_up(&req->waitq);
465476
}
466-
wake_up(&req->waitq);
477+
467478
if (req->end)
468479
req->end(fc, req);
469480
put_request:
470481
fuse_put_request(fc, req);
471482
}
472483

473-
static void queue_interrupt(struct fuse_iqueue *fiq, struct fuse_req *req)
484+
static int queue_interrupt(struct fuse_iqueue *fiq, struct fuse_req *req)
474485
{
475486
spin_lock(&fiq->waitq.lock);
476-
if (test_bit(FR_FINISHED, &req->flags)) {
487+
/* Check for we've sent request to interrupt this req */
488+
if (unlikely(!test_bit(FR_INTERRUPTED, &req->flags))) {
477489
spin_unlock(&fiq->waitq.lock);
478-
return;
490+
return -EINVAL;
479491
}
492+
480493
if (list_empty(&req->intr_entry)) {
481494
list_add_tail(&req->intr_entry, &fiq->interrupts);
495+
/*
496+
* Pairs with smp_mb() implied by test_and_set_bit()
497+
* from request_end().
498+
*/
499+
smp_mb();
500+
if (test_bit(FR_FINISHED, &req->flags)) {
501+
list_del_init(&req->intr_entry);
502+
spin_unlock(&fiq->waitq.lock);
503+
return 0;
504+
}
482505
wake_up_locked(&fiq->waitq);
506+
kill_fasync(&fiq->fasync, SIGIO, POLL_IN);
483507
}
484508
spin_unlock(&fiq->waitq.lock);
485-
kill_fasync(&fiq->fasync, SIGIO, POLL_IN);
509+
return 0;
486510
}
487511

488512
static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req)
@@ -1306,7 +1330,7 @@ static ssize_t fuse_dev_do_read(struct fuse_dev *fud, struct file *file,
13061330
goto err_unlock;
13071331

13081332
if (!fiq->connected) {
1309-
err = (fc->aborted && fc->abort_err) ? -ECONNABORTED : -ENODEV;
1333+
err = fc->aborted ? -ECONNABORTED : -ENODEV;
13101334
goto err_unlock;
13111335
}
13121336

@@ -1353,7 +1377,7 @@ static ssize_t fuse_dev_do_read(struct fuse_dev *fud, struct file *file,
13531377
spin_lock(&fpq->lock);
13541378
clear_bit(FR_LOCKED, &req->flags);
13551379
if (!fpq->connected) {
1356-
err = (fc->aborted && fc->abort_err) ? -ECONNABORTED : -ENODEV;
1380+
err = fc->aborted ? -ECONNABORTED : -ENODEV;
13571381
goto out_end;
13581382
}
13591383
if (err) {
@@ -1900,58 +1924,58 @@ static ssize_t fuse_dev_do_write(struct fuse_dev *fud,
19001924
struct fuse_req *req;
19011925
struct fuse_out_header oh;
19021926

1927+
err = -EINVAL;
19031928
if (nbytes < sizeof(struct fuse_out_header))
1904-
return -EINVAL;
1929+
goto out;
19051930

19061931
err = fuse_copy_one(cs, &oh, sizeof(oh));
19071932
if (err)
1908-
goto err_finish;
1933+
goto copy_finish;
19091934

19101935
err = -EINVAL;
19111936
if (oh.len != nbytes)
1912-
goto err_finish;
1937+
goto copy_finish;
19131938

19141939
/*
19151940
* Zero oh.unique indicates unsolicited notification message
19161941
* and error contains notification code.
19171942
*/
19181943
if (!oh.unique) {
19191944
err = fuse_notify(fc, oh.error, nbytes - sizeof(oh), cs);
1920-
return err ? err : nbytes;
1945+
goto out;
19211946
}
19221947

19231948
err = -EINVAL;
19241949
if (oh.error <= -1000 || oh.error > 0)
1925-
goto err_finish;
1950+
goto copy_finish;
19261951

19271952
spin_lock(&fpq->lock);
1928-
err = -ENOENT;
1929-
if (!fpq->connected)
1930-
goto err_unlock_pq;
1953+
req = NULL;
1954+
if (fpq->connected)
1955+
req = request_find(fpq, oh.unique & ~FUSE_INT_REQ_BIT);
19311956

1932-
req = request_find(fpq, oh.unique & ~FUSE_INT_REQ_BIT);
1933-
if (!req)
1934-
goto err_unlock_pq;
1957+
err = -ENOENT;
1958+
if (!req) {
1959+
spin_unlock(&fpq->lock);
1960+
goto copy_finish;
1961+
}
19351962

19361963
/* Is it an interrupt reply ID? */
19371964
if (oh.unique & FUSE_INT_REQ_BIT) {
19381965
__fuse_get_request(req);
19391966
spin_unlock(&fpq->lock);
19401967

1941-
err = -EINVAL;
1942-
if (nbytes != sizeof(struct fuse_out_header)) {
1943-
fuse_put_request(fc, req);
1944-
goto err_finish;
1945-
}
1946-
1947-
if (oh.error == -ENOSYS)
1968+
err = 0;
1969+
if (nbytes != sizeof(struct fuse_out_header))
1970+
err = -EINVAL;
1971+
else if (oh.error == -ENOSYS)
19481972
fc->no_interrupt = 1;
19491973
else if (oh.error == -EAGAIN)
1950-
queue_interrupt(&fc->iq, req);
1974+
err = queue_interrupt(&fc->iq, req);
1975+
19511976
fuse_put_request(fc, req);
19521977

1953-
fuse_copy_finish(cs);
1954-
return nbytes;
1978+
goto copy_finish;
19551979
}
19561980

19571981
clear_bit(FR_SENT, &req->flags);
@@ -1977,14 +2001,12 @@ static ssize_t fuse_dev_do_write(struct fuse_dev *fud,
19772001
spin_unlock(&fpq->lock);
19782002

19792003
request_end(fc, req);
1980-
2004+
out:
19812005
return err ? err : nbytes;
19822006

1983-
err_unlock_pq:
1984-
spin_unlock(&fpq->lock);
1985-
err_finish:
2007+
copy_finish:
19862008
fuse_copy_finish(cs);
1987-
return err;
2009+
goto out;
19882010
}
19892011

19902012
static ssize_t fuse_dev_write(struct kiocb *iocb, struct iov_iter *from)
@@ -2109,11 +2131,7 @@ static __poll_t fuse_dev_poll(struct file *file, poll_table *wait)
21092131
return mask;
21102132
}
21112133

2112-
/*
2113-
* Abort all requests on the given list (pending or processing)
2114-
*
2115-
* This function releases and reacquires fc->lock
2116-
*/
2134+
/* Abort all requests on the given list (pending or processing) */
21172135
static void end_requests(struct fuse_conn *fc, struct list_head *head)
21182136
{
21192137
while (!list_empty(head)) {
@@ -2159,7 +2177,7 @@ static void end_polls(struct fuse_conn *fc)
21592177
* is OK, the request will in that case be removed from the list before we touch
21602178
* it.
21612179
*/
2162-
void fuse_abort_conn(struct fuse_conn *fc, bool is_abort)
2180+
void fuse_abort_conn(struct fuse_conn *fc)
21632181
{
21642182
struct fuse_iqueue *fiq = &fc->iq;
21652183

@@ -2175,7 +2193,6 @@ void fuse_abort_conn(struct fuse_conn *fc, bool is_abort)
21752193
fc->connected = 0;
21762194
spin_unlock(&fc->bg_lock);
21772195

2178-
fc->aborted = is_abort;
21792196
fuse_set_initialized(fc);
21802197
list_for_each_entry(fud, &fc->devices, entry) {
21812198
struct fuse_pqueue *fpq = &fud->pq;
@@ -2253,7 +2270,7 @@ int fuse_dev_release(struct inode *inode, struct file *file)
22532270
/* Are we the last open device? */
22542271
if (atomic_dec_and_test(&fc->dev_count)) {
22552272
WARN_ON(fc->iq.fasync != NULL);
2256-
fuse_abort_conn(fc, false);
2273+
fuse_abort_conn(fc);
22572274
}
22582275
fuse_dev_free(fud);
22592276
}

0 commit comments

Comments
 (0)