diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2019-03-12 17:46:26 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-03-12 17:46:26 -0400 |
commit | dfee9c257b102d7c0407629eef2ed32e152de0d2 (patch) | |
tree | 75b8b043241d4b00a6320ed1af07acbebff0bcfe | |
parent | 7b47a9e7c8f672b6fb0b77fca11a63a8a77f5a91 (diff) | |
parent | fabf7e0262d0bd57739d29aeac94c44b0542ff1f (diff) |
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()
...
-rw-r--r-- | fs/fuse/control.c | 4 | ||||
-rw-r--r-- | fs/fuse/cuse.c | 7 | ||||
-rw-r--r-- | fs/fuse/dev.c | 115 | ||||
-rw-r--r-- | fs/fuse/dir.c | 54 | ||||
-rw-r--r-- | fs/fuse/file.c | 342 | ||||
-rw-r--r-- | fs/fuse/fuse_i.h | 28 | ||||
-rw-r--r-- | fs/fuse/inode.c | 26 | ||||
-rw-r--r-- | fs/fuse/readdir.c | 4 | ||||
-rw-r--r-- | include/uapi/linux/fuse.h | 7 |
9 files changed, 327 insertions, 260 deletions
diff --git a/fs/fuse/control.c b/fs/fuse/control.c index 989df5accaee..fe80bea4ad89 100644 --- a/fs/fuse/control.c +++ b/fs/fuse/control.c | |||
@@ -35,7 +35,9 @@ static ssize_t fuse_conn_abort_write(struct file *file, const char __user *buf, | |||
35 | { | 35 | { |
36 | struct fuse_conn *fc = fuse_ctl_file_conn_get(file); | 36 | struct fuse_conn *fc = fuse_ctl_file_conn_get(file); |
37 | if (fc) { | 37 | if (fc) { |
38 | fuse_abort_conn(fc, true); | 38 | if (fc->abort_err) |
39 | fc->aborted = true; | ||
40 | fuse_abort_conn(fc); | ||
39 | fuse_conn_put(fc); | 41 | fuse_conn_put(fc); |
40 | } | 42 | } |
41 | return count; | 43 | return count; |
diff --git a/fs/fuse/cuse.c b/fs/fuse/cuse.c index 8f68181256c0..55a26f351467 100644 --- a/fs/fuse/cuse.c +++ b/fs/fuse/cuse.c | |||
@@ -141,10 +141,11 @@ static int cuse_open(struct inode *inode, struct file *file) | |||
141 | 141 | ||
142 | static int cuse_release(struct inode *inode, struct file *file) | 142 | static int cuse_release(struct inode *inode, struct file *file) |
143 | { | 143 | { |
144 | struct fuse_inode *fi = get_fuse_inode(inode); | ||
144 | struct fuse_file *ff = file->private_data; | 145 | struct fuse_file *ff = file->private_data; |
145 | struct fuse_conn *fc = ff->fc; | 146 | struct fuse_conn *fc = ff->fc; |
146 | 147 | ||
147 | fuse_sync_release(ff, file->f_flags); | 148 | fuse_sync_release(fi, ff, file->f_flags); |
148 | fuse_conn_put(fc); | 149 | fuse_conn_put(fc); |
149 | 150 | ||
150 | return 0; | 151 | return 0; |
@@ -407,7 +408,7 @@ err_unlock: | |||
407 | err_region: | 408 | err_region: |
408 | unregister_chrdev_region(devt, 1); | 409 | unregister_chrdev_region(devt, 1); |
409 | err: | 410 | err: |
410 | fuse_abort_conn(fc, false); | 411 | fuse_abort_conn(fc); |
411 | goto out; | 412 | goto out; |
412 | } | 413 | } |
413 | 414 | ||
@@ -586,7 +587,7 @@ static ssize_t cuse_class_abort_store(struct device *dev, | |||
586 | { | 587 | { |
587 | struct cuse_conn *cc = dev_get_drvdata(dev); | 588 | struct cuse_conn *cc = dev_get_drvdata(dev); |
588 | 589 | ||
589 | fuse_abort_conn(&cc->fc, false); | 590 | fuse_abort_conn(&cc->fc); |
590 | return count; | 591 | return count; |
591 | } | 592 | } |
592 | static DEVICE_ATTR(abort, 0200, NULL, cuse_class_abort_store); | 593 | static DEVICE_ATTR(abort, 0200, NULL, cuse_class_abort_store); |
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index 809c0f2f9942..8a63e52785e9 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c | |||
@@ -251,17 +251,18 @@ static struct fuse_req *get_reserved_req(struct fuse_conn *fc, | |||
251 | struct file *file) | 251 | struct file *file) |
252 | { | 252 | { |
253 | struct fuse_req *req = NULL; | 253 | struct fuse_req *req = NULL; |
254 | struct fuse_inode *fi = get_fuse_inode(file_inode(file)); | ||
254 | struct fuse_file *ff = file->private_data; | 255 | struct fuse_file *ff = file->private_data; |
255 | 256 | ||
256 | do { | 257 | do { |
257 | wait_event(fc->reserved_req_waitq, ff->reserved_req); | 258 | wait_event(fc->reserved_req_waitq, ff->reserved_req); |
258 | spin_lock(&fc->lock); | 259 | spin_lock(&fi->lock); |
259 | if (ff->reserved_req) { | 260 | if (ff->reserved_req) { |
260 | req = ff->reserved_req; | 261 | req = ff->reserved_req; |
261 | ff->reserved_req = NULL; | 262 | ff->reserved_req = NULL; |
262 | req->stolen_file = get_file(file); | 263 | req->stolen_file = get_file(file); |
263 | } | 264 | } |
264 | spin_unlock(&fc->lock); | 265 | spin_unlock(&fi->lock); |
265 | } while (!req); | 266 | } while (!req); |
266 | 267 | ||
267 | return req; | 268 | return req; |
@@ -273,16 +274,17 @@ static struct fuse_req *get_reserved_req(struct fuse_conn *fc, | |||
273 | static void put_reserved_req(struct fuse_conn *fc, struct fuse_req *req) | 274 | static void put_reserved_req(struct fuse_conn *fc, struct fuse_req *req) |
274 | { | 275 | { |
275 | struct file *file = req->stolen_file; | 276 | struct file *file = req->stolen_file; |
277 | struct fuse_inode *fi = get_fuse_inode(file_inode(file)); | ||
276 | struct fuse_file *ff = file->private_data; | 278 | struct fuse_file *ff = file->private_data; |
277 | 279 | ||
278 | WARN_ON(req->max_pages); | 280 | WARN_ON(req->max_pages); |
279 | spin_lock(&fc->lock); | 281 | spin_lock(&fi->lock); |
280 | memset(req, 0, sizeof(*req)); | 282 | memset(req, 0, sizeof(*req)); |
281 | fuse_request_init(req, NULL, NULL, 0); | 283 | fuse_request_init(req, NULL, NULL, 0); |
282 | BUG_ON(ff->reserved_req); | 284 | BUG_ON(ff->reserved_req); |
283 | ff->reserved_req = req; | 285 | ff->reserved_req = req; |
284 | wake_up_all(&fc->reserved_req_waitq); | 286 | wake_up_all(&fc->reserved_req_waitq); |
285 | spin_unlock(&fc->lock); | 287 | spin_unlock(&fi->lock); |
286 | fput(file); | 288 | fput(file); |
287 | } | 289 | } |
288 | 290 | ||
@@ -431,10 +433,16 @@ static void request_end(struct fuse_conn *fc, struct fuse_req *req) | |||
431 | 433 | ||
432 | if (test_and_set_bit(FR_FINISHED, &req->flags)) | 434 | if (test_and_set_bit(FR_FINISHED, &req->flags)) |
433 | goto put_request; | 435 | goto put_request; |
434 | 436 | /* | |
435 | spin_lock(&fiq->waitq.lock); | 437 | * test_and_set_bit() implies smp_mb() between bit |
436 | list_del_init(&req->intr_entry); | 438 | * changing and below intr_entry check. Pairs with |
437 | spin_unlock(&fiq->waitq.lock); | 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 | } | ||
438 | WARN_ON(test_bit(FR_PENDING, &req->flags)); | 446 | WARN_ON(test_bit(FR_PENDING, &req->flags)); |
439 | WARN_ON(test_bit(FR_SENT, &req->flags)); | 447 | WARN_ON(test_bit(FR_SENT, &req->flags)); |
440 | if (test_bit(FR_BACKGROUND, &req->flags)) { | 448 | if (test_bit(FR_BACKGROUND, &req->flags)) { |
@@ -462,27 +470,43 @@ static void request_end(struct fuse_conn *fc, struct fuse_req *req) | |||
462 | fc->active_background--; | 470 | fc->active_background--; |
463 | flush_bg_queue(fc); | 471 | flush_bg_queue(fc); |
464 | spin_unlock(&fc->bg_lock); | 472 | spin_unlock(&fc->bg_lock); |
473 | } else { | ||
474 | /* Wake up waiter sleeping in request_wait_answer() */ | ||
475 | wake_up(&req->waitq); | ||
465 | } | 476 | } |
466 | wake_up(&req->waitq); | 477 | |
467 | if (req->end) | 478 | if (req->end) |
468 | req->end(fc, req); | 479 | req->end(fc, req); |
469 | put_request: | 480 | put_request: |
470 | fuse_put_request(fc, req); | 481 | fuse_put_request(fc, req); |
471 | } | 482 | } |
472 | 483 | ||
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) |
474 | { | 485 | { |
475 | spin_lock(&fiq->waitq.lock); | 486 | 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))) { | ||
477 | spin_unlock(&fiq->waitq.lock); | 489 | spin_unlock(&fiq->waitq.lock); |
478 | return; | 490 | return -EINVAL; |
479 | } | 491 | } |
492 | |||
480 | if (list_empty(&req->intr_entry)) { | 493 | if (list_empty(&req->intr_entry)) { |
481 | list_add_tail(&req->intr_entry, &fiq->interrupts); | 494 | 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 | } | ||
482 | wake_up_locked(&fiq->waitq); | 505 | wake_up_locked(&fiq->waitq); |
506 | kill_fasync(&fiq->fasync, SIGIO, POLL_IN); | ||
483 | } | 507 | } |
484 | spin_unlock(&fiq->waitq.lock); | 508 | spin_unlock(&fiq->waitq.lock); |
485 | kill_fasync(&fiq->fasync, SIGIO, POLL_IN); | 509 | return 0; |
486 | } | 510 | } |
487 | 511 | ||
488 | static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req) | 512 | 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, | |||
1306 | goto err_unlock; | 1330 | goto err_unlock; |
1307 | 1331 | ||
1308 | if (!fiq->connected) { | 1332 | if (!fiq->connected) { |
1309 | err = (fc->aborted && fc->abort_err) ? -ECONNABORTED : -ENODEV; | 1333 | err = fc->aborted ? -ECONNABORTED : -ENODEV; |
1310 | goto err_unlock; | 1334 | goto err_unlock; |
1311 | } | 1335 | } |
1312 | 1336 | ||
@@ -1353,7 +1377,7 @@ static ssize_t fuse_dev_do_read(struct fuse_dev *fud, struct file *file, | |||
1353 | spin_lock(&fpq->lock); | 1377 | spin_lock(&fpq->lock); |
1354 | clear_bit(FR_LOCKED, &req->flags); | 1378 | clear_bit(FR_LOCKED, &req->flags); |
1355 | if (!fpq->connected) { | 1379 | if (!fpq->connected) { |
1356 | err = (fc->aborted && fc->abort_err) ? -ECONNABORTED : -ENODEV; | 1380 | err = fc->aborted ? -ECONNABORTED : -ENODEV; |
1357 | goto out_end; | 1381 | goto out_end; |
1358 | } | 1382 | } |
1359 | if (err) { | 1383 | if (err) { |
@@ -1900,16 +1924,17 @@ static ssize_t fuse_dev_do_write(struct fuse_dev *fud, | |||
1900 | struct fuse_req *req; | 1924 | struct fuse_req *req; |
1901 | struct fuse_out_header oh; | 1925 | struct fuse_out_header oh; |
1902 | 1926 | ||
1927 | err = -EINVAL; | ||
1903 | if (nbytes < sizeof(struct fuse_out_header)) | 1928 | if (nbytes < sizeof(struct fuse_out_header)) |
1904 | return -EINVAL; | 1929 | goto out; |
1905 | 1930 | ||
1906 | err = fuse_copy_one(cs, &oh, sizeof(oh)); | 1931 | err = fuse_copy_one(cs, &oh, sizeof(oh)); |
1907 | if (err) | 1932 | if (err) |
1908 | goto err_finish; | 1933 | goto copy_finish; |
1909 | 1934 | ||
1910 | err = -EINVAL; | 1935 | err = -EINVAL; |
1911 | if (oh.len != nbytes) | 1936 | if (oh.len != nbytes) |
1912 | goto err_finish; | 1937 | goto copy_finish; |
1913 | 1938 | ||
1914 | /* | 1939 | /* |
1915 | * Zero oh.unique indicates unsolicited notification message | 1940 | * Zero oh.unique indicates unsolicited notification message |
@@ -1917,41 +1942,40 @@ static ssize_t fuse_dev_do_write(struct fuse_dev *fud, | |||
1917 | */ | 1942 | */ |
1918 | if (!oh.unique) { | 1943 | if (!oh.unique) { |
1919 | err = fuse_notify(fc, oh.error, nbytes - sizeof(oh), cs); | 1944 | err = fuse_notify(fc, oh.error, nbytes - sizeof(oh), cs); |
1920 | return err ? err : nbytes; | 1945 | goto out; |
1921 | } | 1946 | } |
1922 | 1947 | ||
1923 | err = -EINVAL; | 1948 | err = -EINVAL; |
1924 | if (oh.error <= -1000 || oh.error > 0) | 1949 | if (oh.error <= -1000 || oh.error > 0) |
1925 | goto err_finish; | 1950 | goto copy_finish; |
1926 | 1951 | ||
1927 | spin_lock(&fpq->lock); | 1952 | spin_lock(&fpq->lock); |
1928 | err = -ENOENT; | 1953 | req = NULL; |
1929 | if (!fpq->connected) | 1954 | if (fpq->connected) |
1930 | goto err_unlock_pq; | 1955 | req = request_find(fpq, oh.unique & ~FUSE_INT_REQ_BIT); |
1931 | 1956 | ||
1932 | req = request_find(fpq, oh.unique & ~FUSE_INT_REQ_BIT); | 1957 | err = -ENOENT; |
1933 | if (!req) | 1958 | if (!req) { |
1934 | goto err_unlock_pq; | 1959 | spin_unlock(&fpq->lock); |
1960 | goto copy_finish; | ||
1961 | } | ||
1935 | 1962 | ||
1936 | /* Is it an interrupt reply ID? */ | 1963 | /* Is it an interrupt reply ID? */ |
1937 | if (oh.unique & FUSE_INT_REQ_BIT) { | 1964 | if (oh.unique & FUSE_INT_REQ_BIT) { |
1938 | __fuse_get_request(req); | 1965 | __fuse_get_request(req); |
1939 | spin_unlock(&fpq->lock); | 1966 | spin_unlock(&fpq->lock); |
1940 | 1967 | ||
1941 | err = -EINVAL; | 1968 | err = 0; |
1942 | if (nbytes != sizeof(struct fuse_out_header)) { | 1969 | if (nbytes != sizeof(struct fuse_out_header)) |
1943 | fuse_put_request(fc, req); | 1970 | err = -EINVAL; |
1944 | goto err_finish; | 1971 | else if (oh.error == -ENOSYS) |
1945 | } | ||
1946 | |||
1947 | if (oh.error == -ENOSYS) | ||
1948 | fc->no_interrupt = 1; | 1972 | fc->no_interrupt = 1; |
1949 | else if (oh.error == -EAGAIN) | 1973 | else if (oh.error == -EAGAIN) |
1950 | queue_interrupt(&fc->iq, req); | 1974 | err = queue_interrupt(&fc->iq, req); |
1975 | |||
1951 | fuse_put_request(fc, req); | 1976 | fuse_put_request(fc, req); |
1952 | 1977 | ||
1953 | fuse_copy_finish(cs); | 1978 | goto copy_finish; |
1954 | return nbytes; | ||
1955 | } | 1979 | } |
1956 | 1980 | ||
1957 | clear_bit(FR_SENT, &req->flags); | 1981 | clear_bit(FR_SENT, &req->flags); |
@@ -1977,14 +2001,12 @@ static ssize_t fuse_dev_do_write(struct fuse_dev *fud, | |||
1977 | spin_unlock(&fpq->lock); | 2001 | spin_unlock(&fpq->lock); |
1978 | 2002 | ||
1979 | request_end(fc, req); | 2003 | request_end(fc, req); |
1980 | 2004 | out: | |
1981 | return err ? err : nbytes; | 2005 | return err ? err : nbytes; |
1982 | 2006 | ||
1983 | err_unlock_pq: | 2007 | copy_finish: |
1984 | spin_unlock(&fpq->lock); | ||
1985 | err_finish: | ||
1986 | fuse_copy_finish(cs); | 2008 | fuse_copy_finish(cs); |
1987 | return err; | 2009 | goto out; |
1988 | } | 2010 | } |
1989 | 2011 | ||
1990 | static ssize_t fuse_dev_write(struct kiocb *iocb, struct iov_iter *from) | 2012 | 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) | |||
2109 | return mask; | 2131 | return mask; |
2110 | } | 2132 | } |
2111 | 2133 | ||
2112 | /* | 2134 | /* Abort all requests on the given list (pending or processing) */ |
2113 | * Abort all requests on the given list (pending or processing) | ||
2114 | * | ||
2115 | * This function releases and reacquires fc->lock | ||
2116 | */ | ||
2117 | static void end_requests(struct fuse_conn *fc, struct list_head *head) | 2135 | static void end_requests(struct fuse_conn *fc, struct list_head *head) |
2118 | { | 2136 | { |
2119 | while (!list_empty(head)) { | 2137 | while (!list_empty(head)) { |
@@ -2159,7 +2177,7 @@ static void end_polls(struct fuse_conn *fc) | |||
2159 | * is OK, the request will in that case be removed from the list before we touch | 2177 | * is OK, the request will in that case be removed from the list before we touch |
2160 | * it. | 2178 | * it. |
2161 | */ | 2179 | */ |
2162 | void fuse_abort_conn(struct fuse_conn *fc, bool is_abort) | 2180 | void fuse_abort_conn(struct fuse_conn *fc) |
2163 | { | 2181 | { |
2164 | struct fuse_iqueue *fiq = &fc->iq; | 2182 | struct fuse_iqueue *fiq = &fc->iq; |
2165 | 2183 | ||
@@ -2175,7 +2193,6 @@ void fuse_abort_conn(struct fuse_conn *fc, bool is_abort) | |||
2175 | fc->connected = 0; | 2193 | fc->connected = 0; |
2176 | spin_unlock(&fc->bg_lock); | 2194 | spin_unlock(&fc->bg_lock); |
2177 | 2195 | ||
2178 | fc->aborted = is_abort; | ||
2179 | fuse_set_initialized(fc); | 2196 | fuse_set_initialized(fc); |
2180 | list_for_each_entry(fud, &fc->devices, entry) { | 2197 | list_for_each_entry(fud, &fc->devices, entry) { |
2181 | struct fuse_pqueue *fpq = &fud->pq; | 2198 | struct fuse_pqueue *fpq = &fud->pq; |
@@ -2253,7 +2270,7 @@ int fuse_dev_release(struct inode *inode, struct file *file) | |||
2253 | /* Are we the last open device? */ | 2270 | /* Are we the last open device? */ |
2254 | if (atomic_dec_and_test(&fc->dev_count)) { | 2271 | if (atomic_dec_and_test(&fc->dev_count)) { |
2255 | WARN_ON(fc->iq.fasync != NULL); | 2272 | WARN_ON(fc->iq.fasync != NULL); |
2256 | fuse_abort_conn(fc, false); | 2273 | fuse_abort_conn(fc); |
2257 | } | 2274 | } |
2258 | fuse_dev_free(fud); | 2275 | fuse_dev_free(fud); |
2259 | } | 2276 | } |
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index e909678afa2d..dd0f64f7bc06 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c | |||
@@ -149,21 +149,6 @@ static void fuse_lookup_init(struct fuse_conn *fc, struct fuse_args *args, | |||
149 | args->out.args[0].value = outarg; | 149 | args->out.args[0].value = outarg; |
150 | } | 150 | } |
151 | 151 | ||
152 | u64 fuse_get_attr_version(struct fuse_conn *fc) | ||
153 | { | ||
154 | u64 curr_version; | ||
155 | |||
156 | /* | ||
157 | * The spin lock isn't actually needed on 64bit archs, but we | ||
158 | * don't yet care too much about such optimizations. | ||
159 | */ | ||
160 | spin_lock(&fc->lock); | ||
161 | curr_version = fc->attr_version; | ||
162 | spin_unlock(&fc->lock); | ||
163 | |||
164 | return curr_version; | ||
165 | } | ||
166 | |||
167 | /* | 152 | /* |
168 | * Check whether the dentry is still valid | 153 | * Check whether the dentry is still valid |
169 | * | 154 | * |
@@ -222,9 +207,9 @@ static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags) | |||
222 | fuse_queue_forget(fc, forget, outarg.nodeid, 1); | 207 | fuse_queue_forget(fc, forget, outarg.nodeid, 1); |
223 | goto invalid; | 208 | goto invalid; |
224 | } | 209 | } |
225 | spin_lock(&fc->lock); | 210 | spin_lock(&fi->lock); |
226 | fi->nlookup++; | 211 | fi->nlookup++; |
227 | spin_unlock(&fc->lock); | 212 | spin_unlock(&fi->lock); |
228 | } | 213 | } |
229 | kfree(forget); | 214 | kfree(forget); |
230 | if (ret == -ENOMEM) | 215 | if (ret == -ENOMEM) |
@@ -400,6 +385,7 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, | |||
400 | struct fuse_create_in inarg; | 385 | struct fuse_create_in inarg; |
401 | struct fuse_open_out outopen; | 386 | struct fuse_open_out outopen; |
402 | struct fuse_entry_out outentry; | 387 | struct fuse_entry_out outentry; |
388 | struct fuse_inode *fi; | ||
403 | struct fuse_file *ff; | 389 | struct fuse_file *ff; |
404 | 390 | ||
405 | /* Userspace expects S_IFREG in create mode */ | 391 | /* Userspace expects S_IFREG in create mode */ |
@@ -451,7 +437,7 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, | |||
451 | &outentry.attr, entry_attr_timeout(&outentry), 0); | 437 | &outentry.attr, entry_attr_timeout(&outentry), 0); |
452 | if (!inode) { | 438 | if (!inode) { |
453 | flags &= ~(O_CREAT | O_EXCL | O_TRUNC); | 439 | flags &= ~(O_CREAT | O_EXCL | O_TRUNC); |
454 | fuse_sync_release(ff, flags); | 440 | fuse_sync_release(NULL, ff, flags); |
455 | fuse_queue_forget(fc, forget, outentry.nodeid, 1); | 441 | fuse_queue_forget(fc, forget, outentry.nodeid, 1); |
456 | err = -ENOMEM; | 442 | err = -ENOMEM; |
457 | goto out_err; | 443 | goto out_err; |
@@ -462,7 +448,8 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, | |||
462 | fuse_dir_changed(dir); | 448 | fuse_dir_changed(dir); |
463 | err = finish_open(file, entry, generic_file_open); | 449 | err = finish_open(file, entry, generic_file_open); |
464 | if (err) { | 450 | if (err) { |
465 | fuse_sync_release(ff, flags); | 451 | fi = get_fuse_inode(inode); |
452 | fuse_sync_release(fi, ff, flags); | ||
466 | } else { | 453 | } else { |
467 | file->private_data = ff; | 454 | file->private_data = ff; |
468 | fuse_finish_open(inode, file); | 455 | fuse_finish_open(inode, file); |
@@ -671,8 +658,8 @@ static int fuse_unlink(struct inode *dir, struct dentry *entry) | |||
671 | struct inode *inode = d_inode(entry); | 658 | struct inode *inode = d_inode(entry); |
672 | struct fuse_inode *fi = get_fuse_inode(inode); | 659 | struct fuse_inode *fi = get_fuse_inode(inode); |
673 | 660 | ||
674 | spin_lock(&fc->lock); | 661 | spin_lock(&fi->lock); |
675 | fi->attr_version = ++fc->attr_version; | 662 | fi->attr_version = atomic64_inc_return(&fc->attr_version); |
676 | /* | 663 | /* |
677 | * If i_nlink == 0 then unlink doesn't make sense, yet this can | 664 | * If i_nlink == 0 then unlink doesn't make sense, yet this can |
678 | * happen if userspace filesystem is careless. It would be | 665 | * happen if userspace filesystem is careless. It would be |
@@ -681,7 +668,7 @@ static int fuse_unlink(struct inode *dir, struct dentry *entry) | |||
681 | */ | 668 | */ |
682 | if (inode->i_nlink > 0) | 669 | if (inode->i_nlink > 0) |
683 | drop_nlink(inode); | 670 | drop_nlink(inode); |
684 | spin_unlock(&fc->lock); | 671 | spin_unlock(&fi->lock); |
685 | fuse_invalidate_attr(inode); | 672 | fuse_invalidate_attr(inode); |
686 | fuse_dir_changed(dir); | 673 | fuse_dir_changed(dir); |
687 | fuse_invalidate_entry_cache(entry); | 674 | fuse_invalidate_entry_cache(entry); |
@@ -825,10 +812,10 @@ static int fuse_link(struct dentry *entry, struct inode *newdir, | |||
825 | if (!err) { | 812 | if (!err) { |
826 | struct fuse_inode *fi = get_fuse_inode(inode); | 813 | struct fuse_inode *fi = get_fuse_inode(inode); |
827 | 814 | ||
828 | spin_lock(&fc->lock); | 815 | spin_lock(&fi->lock); |
829 | fi->attr_version = ++fc->attr_version; | 816 | fi->attr_version = atomic64_inc_return(&fc->attr_version); |
830 | inc_nlink(inode); | 817 | inc_nlink(inode); |
831 | spin_unlock(&fc->lock); | 818 | spin_unlock(&fi->lock); |
832 | fuse_invalidate_attr(inode); | 819 | fuse_invalidate_attr(inode); |
833 | fuse_update_ctime(inode); | 820 | fuse_update_ctime(inode); |
834 | } else if (err == -EINTR) { | 821 | } else if (err == -EINTR) { |
@@ -1356,15 +1343,14 @@ static void iattr_to_fattr(struct fuse_conn *fc, struct iattr *iattr, | |||
1356 | */ | 1343 | */ |
1357 | void fuse_set_nowrite(struct inode *inode) | 1344 | void fuse_set_nowrite(struct inode *inode) |
1358 | { | 1345 | { |
1359 | struct fuse_conn *fc = get_fuse_conn(inode); | ||
1360 | struct fuse_inode *fi = get_fuse_inode(inode); | 1346 | struct fuse_inode *fi = get_fuse_inode(inode); |
1361 | 1347 | ||
1362 | BUG_ON(!inode_is_locked(inode)); | 1348 | BUG_ON(!inode_is_locked(inode)); |
1363 | 1349 | ||
1364 | spin_lock(&fc->lock); | 1350 | spin_lock(&fi->lock); |
1365 | BUG_ON(fi->writectr < 0); | 1351 | BUG_ON(fi->writectr < 0); |
1366 | fi->writectr += FUSE_NOWRITE; | 1352 | fi->writectr += FUSE_NOWRITE; |
1367 | spin_unlock(&fc->lock); | 1353 | spin_unlock(&fi->lock); |
1368 | wait_event(fi->page_waitq, fi->writectr == FUSE_NOWRITE); | 1354 | wait_event(fi->page_waitq, fi->writectr == FUSE_NOWRITE); |
1369 | } | 1355 | } |
1370 | 1356 | ||
@@ -1385,11 +1371,11 @@ static void __fuse_release_nowrite(struct inode *inode) | |||
1385 | 1371 | ||
1386 | void fuse_release_nowrite(struct inode *inode) | 1372 | void fuse_release_nowrite(struct inode *inode) |
1387 | { | 1373 | { |
1388 | struct fuse_conn *fc = get_fuse_conn(inode); | 1374 | struct fuse_inode *fi = get_fuse_inode(inode); |
1389 | 1375 | ||
1390 | spin_lock(&fc->lock); | 1376 | spin_lock(&fi->lock); |
1391 | __fuse_release_nowrite(inode); | 1377 | __fuse_release_nowrite(inode); |
1392 | spin_unlock(&fc->lock); | 1378 | spin_unlock(&fi->lock); |
1393 | } | 1379 | } |
1394 | 1380 | ||
1395 | static void fuse_setattr_fill(struct fuse_conn *fc, struct fuse_args *args, | 1381 | static void fuse_setattr_fill(struct fuse_conn *fc, struct fuse_args *args, |
@@ -1524,7 +1510,7 @@ int fuse_do_setattr(struct dentry *dentry, struct iattr *attr, | |||
1524 | goto error; | 1510 | goto error; |
1525 | } | 1511 | } |
1526 | 1512 | ||
1527 | spin_lock(&fc->lock); | 1513 | spin_lock(&fi->lock); |
1528 | /* the kernel maintains i_mtime locally */ | 1514 | /* the kernel maintains i_mtime locally */ |
1529 | if (trust_local_cmtime) { | 1515 | if (trust_local_cmtime) { |
1530 | if (attr->ia_valid & ATTR_MTIME) | 1516 | if (attr->ia_valid & ATTR_MTIME) |
@@ -1542,10 +1528,10 @@ int fuse_do_setattr(struct dentry *dentry, struct iattr *attr, | |||
1542 | i_size_write(inode, outarg.attr.size); | 1528 | i_size_write(inode, outarg.attr.size); |
1543 | 1529 | ||
1544 | if (is_truncate) { | 1530 | if (is_truncate) { |
1545 | /* NOTE: this may release/reacquire fc->lock */ | 1531 | /* NOTE: this may release/reacquire fi->lock */ |
1546 | __fuse_release_nowrite(inode); | 1532 | __fuse_release_nowrite(inode); |
1547 | } | 1533 | } |
1548 | spin_unlock(&fc->lock); | 1534 | spin_unlock(&fi->lock); |
1549 | 1535 | ||
1550 | /* | 1536 | /* |
1551 | * Only call invalidate_inode_pages2() after removing | 1537 | * Only call invalidate_inode_pages2() after removing |
diff --git a/fs/fuse/file.c b/fs/fuse/file.c index a59c16bd90ac..06096b60f1df 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c | |||
@@ -19,8 +19,6 @@ | |||
19 | #include <linux/falloc.h> | 19 | #include <linux/falloc.h> |
20 | #include <linux/uio.h> | 20 | #include <linux/uio.h> |
21 | 21 | ||
22 | static const struct file_operations fuse_direct_io_file_operations; | ||
23 | |||
24 | static int fuse_send_open(struct fuse_conn *fc, u64 nodeid, struct file *file, | 22 | static int fuse_send_open(struct fuse_conn *fc, u64 nodeid, struct file *file, |
25 | int opcode, struct fuse_open_out *outargp) | 23 | int opcode, struct fuse_open_out *outargp) |
26 | { | 24 | { |
@@ -64,9 +62,7 @@ struct fuse_file *fuse_file_alloc(struct fuse_conn *fc) | |||
64 | RB_CLEAR_NODE(&ff->polled_node); | 62 | RB_CLEAR_NODE(&ff->polled_node); |
65 | init_waitqueue_head(&ff->poll_wait); | 63 | init_waitqueue_head(&ff->poll_wait); |
66 | 64 | ||
67 | spin_lock(&fc->lock); | 65 | ff->kh = atomic64_inc_return(&fc->khctr); |
68 | ff->kh = ++fc->khctr; | ||
69 | spin_unlock(&fc->lock); | ||
70 | 66 | ||
71 | return ff; | 67 | return ff; |
72 | } | 68 | } |
@@ -94,7 +90,7 @@ static void fuse_file_put(struct fuse_file *ff, bool sync, bool isdir) | |||
94 | if (refcount_dec_and_test(&ff->count)) { | 90 | if (refcount_dec_and_test(&ff->count)) { |
95 | struct fuse_req *req = ff->reserved_req; | 91 | struct fuse_req *req = ff->reserved_req; |
96 | 92 | ||
97 | if (ff->fc->no_open && !isdir) { | 93 | if (isdir ? ff->fc->no_opendir : ff->fc->no_open) { |
98 | /* | 94 | /* |
99 | * Drop the release request when client does not | 95 | * Drop the release request when client does not |
100 | * implement 'open' | 96 | * implement 'open' |
@@ -128,8 +124,9 @@ int fuse_do_open(struct fuse_conn *fc, u64 nodeid, struct file *file, | |||
128 | return -ENOMEM; | 124 | return -ENOMEM; |
129 | 125 | ||
130 | ff->fh = 0; | 126 | ff->fh = 0; |
131 | ff->open_flags = FOPEN_KEEP_CACHE; /* Default for no-open */ | 127 | /* Default for no-open */ |
132 | if (!fc->no_open || isdir) { | 128 | ff->open_flags = FOPEN_KEEP_CACHE | (isdir ? FOPEN_CACHE_DIR : 0); |
129 | if (isdir ? !fc->no_opendir : !fc->no_open) { | ||
133 | struct fuse_open_out outarg; | 130 | struct fuse_open_out outarg; |
134 | int err; | 131 | int err; |
135 | 132 | ||
@@ -138,11 +135,14 @@ int fuse_do_open(struct fuse_conn *fc, u64 nodeid, struct file *file, | |||
138 | ff->fh = outarg.fh; | 135 | ff->fh = outarg.fh; |
139 | ff->open_flags = outarg.open_flags; | 136 | ff->open_flags = outarg.open_flags; |
140 | 137 | ||
141 | } else if (err != -ENOSYS || isdir) { | 138 | } else if (err != -ENOSYS) { |
142 | fuse_file_free(ff); | 139 | fuse_file_free(ff); |
143 | return err; | 140 | return err; |
144 | } else { | 141 | } else { |
145 | fc->no_open = 1; | 142 | if (isdir) |
143 | fc->no_opendir = 1; | ||
144 | else | ||
145 | fc->no_open = 1; | ||
146 | } | 146 | } |
147 | } | 147 | } |
148 | 148 | ||
@@ -159,17 +159,16 @@ EXPORT_SYMBOL_GPL(fuse_do_open); | |||
159 | static void fuse_link_write_file(struct file *file) | 159 | static void fuse_link_write_file(struct file *file) |
160 | { | 160 | { |
161 | struct inode *inode = file_inode(file); | 161 | struct inode *inode = file_inode(file); |
162 | struct fuse_conn *fc = get_fuse_conn(inode); | ||
163 | struct fuse_inode *fi = get_fuse_inode(inode); | 162 | struct fuse_inode *fi = get_fuse_inode(inode); |
164 | struct fuse_file *ff = file->private_data; | 163 | struct fuse_file *ff = file->private_data; |
165 | /* | 164 | /* |
166 | * file may be written through mmap, so chain it onto the | 165 | * file may be written through mmap, so chain it onto the |
167 | * inodes's write_file list | 166 | * inodes's write_file list |
168 | */ | 167 | */ |
169 | spin_lock(&fc->lock); | 168 | spin_lock(&fi->lock); |
170 | if (list_empty(&ff->write_entry)) | 169 | if (list_empty(&ff->write_entry)) |
171 | list_add(&ff->write_entry, &fi->write_files); | 170 | list_add(&ff->write_entry, &fi->write_files); |
172 | spin_unlock(&fc->lock); | 171 | spin_unlock(&fi->lock); |
173 | } | 172 | } |
174 | 173 | ||
175 | void fuse_finish_open(struct inode *inode, struct file *file) | 174 | void fuse_finish_open(struct inode *inode, struct file *file) |
@@ -177,8 +176,6 @@ void fuse_finish_open(struct inode *inode, struct file *file) | |||
177 | struct fuse_file *ff = file->private_data; | 176 | struct fuse_file *ff = file->private_data; |
178 | struct fuse_conn *fc = get_fuse_conn(inode); | 177 | struct fuse_conn *fc = get_fuse_conn(inode); |
179 | 178 | ||
180 | if (ff->open_flags & FOPEN_DIRECT_IO) | ||
181 | file->f_op = &fuse_direct_io_file_operations; | ||
182 | if (!(ff->open_flags & FOPEN_KEEP_CACHE)) | 179 | if (!(ff->open_flags & FOPEN_KEEP_CACHE)) |
183 | invalidate_inode_pages2(inode->i_mapping); | 180 | invalidate_inode_pages2(inode->i_mapping); |
184 | if (ff->open_flags & FOPEN_NONSEEKABLE) | 181 | if (ff->open_flags & FOPEN_NONSEEKABLE) |
@@ -186,10 +183,10 @@ void fuse_finish_open(struct inode *inode, struct file *file) | |||
186 | if (fc->atomic_o_trunc && (file->f_flags & O_TRUNC)) { | 183 | if (fc->atomic_o_trunc && (file->f_flags & O_TRUNC)) { |
187 | struct fuse_inode *fi = get_fuse_inode(inode); | 184 | struct fuse_inode *fi = get_fuse_inode(inode); |
188 | 185 | ||
189 | spin_lock(&fc->lock); | 186 | spin_lock(&fi->lock); |
190 | fi->attr_version = ++fc->attr_version; | 187 | fi->attr_version = atomic64_inc_return(&fc->attr_version); |
191 | i_size_write(inode, 0); | 188 | i_size_write(inode, 0); |
192 | spin_unlock(&fc->lock); | 189 | spin_unlock(&fi->lock); |
193 | fuse_invalidate_attr(inode); | 190 | fuse_invalidate_attr(inode); |
194 | if (fc->writeback_cache) | 191 | if (fc->writeback_cache) |
195 | file_update_time(file); | 192 | file_update_time(file); |
@@ -224,14 +221,20 @@ int fuse_open_common(struct inode *inode, struct file *file, bool isdir) | |||
224 | return err; | 221 | return err; |
225 | } | 222 | } |
226 | 223 | ||
227 | static void fuse_prepare_release(struct fuse_file *ff, int flags, int opcode) | 224 | static void fuse_prepare_release(struct fuse_inode *fi, struct fuse_file *ff, |
225 | int flags, int opcode) | ||
228 | { | 226 | { |
229 | struct fuse_conn *fc = ff->fc; | 227 | struct fuse_conn *fc = ff->fc; |
230 | struct fuse_req *req = ff->reserved_req; | 228 | struct fuse_req *req = ff->reserved_req; |
231 | struct fuse_release_in *inarg = &req->misc.release.in; | 229 | struct fuse_release_in *inarg = &req->misc.release.in; |
232 | 230 | ||
231 | /* Inode is NULL on error path of fuse_create_open() */ | ||
232 | if (likely(fi)) { | ||
233 | spin_lock(&fi->lock); | ||
234 | list_del(&ff->write_entry); | ||
235 | spin_unlock(&fi->lock); | ||
236 | } | ||
233 | spin_lock(&fc->lock); | 237 | spin_lock(&fc->lock); |
234 | list_del(&ff->write_entry); | ||
235 | if (!RB_EMPTY_NODE(&ff->polled_node)) | 238 | if (!RB_EMPTY_NODE(&ff->polled_node)) |
236 | rb_erase(&ff->polled_node, &fc->polled_files); | 239 | rb_erase(&ff->polled_node, &fc->polled_files); |
237 | spin_unlock(&fc->lock); | 240 | spin_unlock(&fc->lock); |
@@ -249,11 +252,12 @@ static void fuse_prepare_release(struct fuse_file *ff, int flags, int opcode) | |||
249 | 252 | ||
250 | void fuse_release_common(struct file *file, bool isdir) | 253 | void fuse_release_common(struct file *file, bool isdir) |
251 | { | 254 | { |
255 | struct fuse_inode *fi = get_fuse_inode(file_inode(file)); | ||
252 | struct fuse_file *ff = file->private_data; | 256 | struct fuse_file *ff = file->private_data; |
253 | struct fuse_req *req = ff->reserved_req; | 257 | struct fuse_req *req = ff->reserved_req; |
254 | int opcode = isdir ? FUSE_RELEASEDIR : FUSE_RELEASE; | 258 | int opcode = isdir ? FUSE_RELEASEDIR : FUSE_RELEASE; |
255 | 259 | ||
256 | fuse_prepare_release(ff, file->f_flags, opcode); | 260 | fuse_prepare_release(fi, ff, file->f_flags, opcode); |
257 | 261 | ||
258 | if (ff->flock) { | 262 | if (ff->flock) { |
259 | struct fuse_release_in *inarg = &req->misc.release.in; | 263 | struct fuse_release_in *inarg = &req->misc.release.in; |
@@ -295,10 +299,10 @@ static int fuse_release(struct inode *inode, struct file *file) | |||
295 | return 0; | 299 | return 0; |
296 | } | 300 | } |
297 | 301 | ||
298 | void fuse_sync_release(struct fuse_file *ff, int flags) | 302 | void fuse_sync_release(struct fuse_inode *fi, struct fuse_file *ff, int flags) |
299 | { | 303 | { |
300 | WARN_ON(refcount_read(&ff->count) > 1); | 304 | WARN_ON(refcount_read(&ff->count) > 1); |
301 | fuse_prepare_release(ff, flags, FUSE_RELEASE); | 305 | fuse_prepare_release(fi, ff, flags, FUSE_RELEASE); |
302 | /* | 306 | /* |
303 | * iput(NULL) is a no-op and since the refcount is 1 and everything's | 307 | * iput(NULL) is a no-op and since the refcount is 1 and everything's |
304 | * synchronous, we are fine with not doing igrab() here" | 308 | * synchronous, we are fine with not doing igrab() here" |
@@ -329,33 +333,39 @@ u64 fuse_lock_owner_id(struct fuse_conn *fc, fl_owner_t id) | |||
329 | return (u64) v0 + ((u64) v1 << 32); | 333 | return (u64) v0 + ((u64) v1 << 32); |
330 | } | 334 | } |
331 | 335 | ||
332 | /* | 336 | static struct fuse_req *fuse_find_writeback(struct fuse_inode *fi, |
333 | * Check if any page in a range is under writeback | 337 | pgoff_t idx_from, pgoff_t idx_to) |
334 | * | ||
335 | * This is currently done by walking the list of writepage requests | ||
336 | * for the inode, which can be pretty inefficient. | ||
337 | */ | ||
338 | static bool fuse_range_is_writeback(struct inode *inode, pgoff_t idx_from, | ||
339 | pgoff_t idx_to) | ||
340 | { | 338 | { |
341 | struct fuse_conn *fc = get_fuse_conn(inode); | ||
342 | struct fuse_inode *fi = get_fuse_inode(inode); | ||
343 | struct fuse_req *req; | 339 | struct fuse_req *req; |
344 | bool found = false; | ||
345 | 340 | ||
346 | spin_lock(&fc->lock); | ||
347 | list_for_each_entry(req, &fi->writepages, writepages_entry) { | 341 | list_for_each_entry(req, &fi->writepages, writepages_entry) { |
348 | pgoff_t curr_index; | 342 | pgoff_t curr_index; |
349 | 343 | ||
350 | BUG_ON(req->inode != inode); | 344 | WARN_ON(get_fuse_inode(req->inode) != fi); |
351 | curr_index = req->misc.write.in.offset >> PAGE_SHIFT; | 345 | curr_index = req->misc.write.in.offset >> PAGE_SHIFT; |
352 | if (idx_from < curr_index + req->num_pages && | 346 | if (idx_from < curr_index + req->num_pages && |
353 | curr_index <= idx_to) { | 347 | curr_index <= idx_to) { |
354 | found = true; | 348 | return req; |
355 | break; | ||
356 | } | 349 | } |
357 | } | 350 | } |
358 | spin_unlock(&fc->lock); | 351 | return NULL; |
352 | } | ||
353 | |||
354 | /* | ||
355 | * Check if any page in a range is under writeback | ||
356 | * | ||
357 | * This is currently done by walking the list of writepage requests | ||
358 | * for the inode, which can be pretty inefficient. | ||
359 | */ | ||
360 | static bool fuse_range_is_writeback(struct inode *inode, pgoff_t idx_from, | ||
361 | pgoff_t idx_to) | ||
362 | { | ||
363 | struct fuse_inode *fi = get_fuse_inode(inode); | ||
364 | bool found; | ||
365 | |||
366 | spin_lock(&fi->lock); | ||
367 | found = fuse_find_writeback(fi, idx_from, idx_to); | ||
368 | spin_unlock(&fi->lock); | ||
359 | 369 | ||
360 | return found; | 370 | return found; |
361 | } | 371 | } |
@@ -598,9 +608,9 @@ static void fuse_aio_complete(struct fuse_io_priv *io, int err, ssize_t pos) | |||
598 | struct fuse_conn *fc = get_fuse_conn(inode); | 608 | struct fuse_conn *fc = get_fuse_conn(inode); |
599 | struct fuse_inode *fi = get_fuse_inode(inode); | 609 | struct fuse_inode *fi = get_fuse_inode(inode); |
600 | 610 | ||
601 | spin_lock(&fc->lock); | 611 | spin_lock(&fi->lock); |
602 | fi->attr_version = ++fc->attr_version; | 612 | fi->attr_version = atomic64_inc_return(&fc->attr_version); |
603 | spin_unlock(&fc->lock); | 613 | spin_unlock(&fi->lock); |
604 | } | 614 | } |
605 | 615 | ||
606 | io->iocb->ki_complete(io->iocb, res, 0); | 616 | io->iocb->ki_complete(io->iocb, res, 0); |
@@ -675,13 +685,13 @@ static void fuse_read_update_size(struct inode *inode, loff_t size, | |||
675 | struct fuse_conn *fc = get_fuse_conn(inode); | 685 | struct fuse_conn *fc = get_fuse_conn(inode); |
676 | struct fuse_inode *fi = get_fuse_inode(inode); | 686 | struct fuse_inode *fi = get_fuse_inode(inode); |
677 | 687 | ||
678 | spin_lock(&fc->lock); | 688 | spin_lock(&fi->lock); |
679 | if (attr_ver == fi->attr_version && size < inode->i_size && | 689 | if (attr_ver == fi->attr_version && size < inode->i_size && |
680 | !test_bit(FUSE_I_SIZE_UNSTABLE, &fi->state)) { | 690 | !test_bit(FUSE_I_SIZE_UNSTABLE, &fi->state)) { |
681 | fi->attr_version = ++fc->attr_version; | 691 | fi->attr_version = atomic64_inc_return(&fc->attr_version); |
682 | i_size_write(inode, size); | 692 | i_size_write(inode, size); |
683 | } | 693 | } |
684 | spin_unlock(&fc->lock); | 694 | spin_unlock(&fi->lock); |
685 | } | 695 | } |
686 | 696 | ||
687 | static void fuse_short_read(struct fuse_req *req, struct inode *inode, | 697 | static void fuse_short_read(struct fuse_req *req, struct inode *inode, |
@@ -919,7 +929,7 @@ out: | |||
919 | return err; | 929 | return err; |
920 | } | 930 | } |
921 | 931 | ||
922 | static ssize_t fuse_file_read_iter(struct kiocb *iocb, struct iov_iter *to) | 932 | static ssize_t fuse_cache_read_iter(struct kiocb *iocb, struct iov_iter *to) |
923 | { | 933 | { |
924 | struct inode *inode = iocb->ki_filp->f_mapping->host; | 934 | struct inode *inode = iocb->ki_filp->f_mapping->host; |
925 | struct fuse_conn *fc = get_fuse_conn(inode); | 935 | struct fuse_conn *fc = get_fuse_conn(inode); |
@@ -996,13 +1006,13 @@ bool fuse_write_update_size(struct inode *inode, loff_t pos) | |||
996 | struct fuse_inode *fi = get_fuse_inode(inode); | 1006 | struct fuse_inode *fi = get_fuse_inode(inode); |
997 | bool ret = false; | 1007 | bool ret = false; |
998 | 1008 | ||
999 | spin_lock(&fc->lock); | 1009 | spin_lock(&fi->lock); |
1000 | fi->attr_version = ++fc->attr_version; | 1010 | fi->attr_version = atomic64_inc_return(&fc->attr_version); |
1001 | if (pos > inode->i_size) { | 1011 | if (pos > inode->i_size) { |
1002 | i_size_write(inode, pos); | 1012 | i_size_write(inode, pos); |
1003 | ret = true; | 1013 | ret = true; |
1004 | } | 1014 | } |
1005 | spin_unlock(&fc->lock); | 1015 | spin_unlock(&fi->lock); |
1006 | 1016 | ||
1007 | return ret; | 1017 | return ret; |
1008 | } | 1018 | } |
@@ -1125,9 +1135,6 @@ static ssize_t fuse_perform_write(struct kiocb *iocb, | |||
1125 | int err = 0; | 1135 | int err = 0; |
1126 | ssize_t res = 0; | 1136 | ssize_t res = 0; |
1127 | 1137 | ||
1128 | if (is_bad_inode(inode)) | ||
1129 | return -EIO; | ||
1130 | |||
1131 | if (inode->i_size < pos + iov_iter_count(ii)) | 1138 | if (inode->i_size < pos + iov_iter_count(ii)) |
1132 | set_bit(FUSE_I_SIZE_UNSTABLE, &fi->state); | 1139 | set_bit(FUSE_I_SIZE_UNSTABLE, &fi->state); |
1133 | 1140 | ||
@@ -1173,7 +1180,7 @@ static ssize_t fuse_perform_write(struct kiocb *iocb, | |||
1173 | return res > 0 ? res : err; | 1180 | return res > 0 ? res : err; |
1174 | } | 1181 | } |
1175 | 1182 | ||
1176 | static ssize_t fuse_file_write_iter(struct kiocb *iocb, struct iov_iter *from) | 1183 | static ssize_t fuse_cache_write_iter(struct kiocb *iocb, struct iov_iter *from) |
1177 | { | 1184 | { |
1178 | struct file *file = iocb->ki_filp; | 1185 | struct file *file = iocb->ki_filp; |
1179 | struct address_space *mapping = file->f_mapping; | 1186 | struct address_space *mapping = file->f_mapping; |
@@ -1416,9 +1423,6 @@ static ssize_t __fuse_direct_read(struct fuse_io_priv *io, | |||
1416 | ssize_t res; | 1423 | ssize_t res; |
1417 | struct inode *inode = file_inode(io->iocb->ki_filp); | 1424 | struct inode *inode = file_inode(io->iocb->ki_filp); |
1418 | 1425 | ||
1419 | if (is_bad_inode(inode)) | ||
1420 | return -EIO; | ||
1421 | |||
1422 | res = fuse_direct_io(io, iter, ppos, 0); | 1426 | res = fuse_direct_io(io, iter, ppos, 0); |
1423 | 1427 | ||
1424 | fuse_invalidate_atime(inode); | 1428 | fuse_invalidate_atime(inode); |
@@ -1426,10 +1430,21 @@ static ssize_t __fuse_direct_read(struct fuse_io_priv *io, | |||
1426 | return res; | 1430 | return res; |
1427 | } | 1431 | } |
1428 | 1432 | ||
1433 | static ssize_t fuse_direct_IO(struct kiocb *iocb, struct iov_iter *iter); | ||
1434 | |||
1429 | static ssize_t fuse_direct_read_iter(struct kiocb *iocb, struct iov_iter *to) | 1435 | static ssize_t fuse_direct_read_iter(struct kiocb *iocb, struct iov_iter *to) |
1430 | { | 1436 | { |
1431 | struct fuse_io_priv io = FUSE_IO_PRIV_SYNC(iocb); | 1437 | ssize_t res; |
1432 | return __fuse_direct_read(&io, to, &iocb->ki_pos); | 1438 | |
1439 | if (!is_sync_kiocb(iocb) && iocb->ki_flags & IOCB_DIRECT) { | ||
1440 | res = fuse_direct_IO(iocb, to); | ||
1441 | } else { | ||
1442 | struct fuse_io_priv io = FUSE_IO_PRIV_SYNC(iocb); | ||
1443 | |||
1444 | res = __fuse_direct_read(&io, to, &iocb->ki_pos); | ||
1445 | } | ||
1446 | |||
1447 | return res; | ||
1433 | } | 1448 | } |
1434 | 1449 | ||
1435 | static ssize_t fuse_direct_write_iter(struct kiocb *iocb, struct iov_iter *from) | 1450 | static ssize_t fuse_direct_write_iter(struct kiocb *iocb, struct iov_iter *from) |
@@ -1438,14 +1453,17 @@ static ssize_t fuse_direct_write_iter(struct kiocb *iocb, struct iov_iter *from) | |||
1438 | struct fuse_io_priv io = FUSE_IO_PRIV_SYNC(iocb); | 1453 | struct fuse_io_priv io = FUSE_IO_PRIV_SYNC(iocb); |
1439 | ssize_t res; | 1454 | ssize_t res; |
1440 | 1455 | ||
1441 | if (is_bad_inode(inode)) | ||
1442 | return -EIO; | ||
1443 | |||
1444 | /* Don't allow parallel writes to the same file */ | 1456 | /* Don't allow parallel writes to the same file */ |
1445 | inode_lock(inode); | 1457 | inode_lock(inode); |
1446 | res = generic_write_checks(iocb, from); | 1458 | res = generic_write_checks(iocb, from); |
1447 | if (res > 0) | 1459 | if (res > 0) { |
1448 | res = fuse_direct_io(&io, from, &iocb->ki_pos, FUSE_DIO_WRITE); | 1460 | if (!is_sync_kiocb(iocb) && iocb->ki_flags & IOCB_DIRECT) { |
1461 | res = fuse_direct_IO(iocb, from); | ||
1462 | } else { | ||
1463 | res = fuse_direct_io(&io, from, &iocb->ki_pos, | ||
1464 | FUSE_DIO_WRITE); | ||
1465 | } | ||
1466 | } | ||
1449 | fuse_invalidate_attr(inode); | 1467 | fuse_invalidate_attr(inode); |
1450 | if (res > 0) | 1468 | if (res > 0) |
1451 | fuse_write_update_size(inode, iocb->ki_pos); | 1469 | fuse_write_update_size(inode, iocb->ki_pos); |
@@ -1454,6 +1472,34 @@ static ssize_t fuse_direct_write_iter(struct kiocb *iocb, struct iov_iter *from) | |||
1454 | return res; | 1472 | return res; |
1455 | } | 1473 | } |
1456 | 1474 | ||
1475 | static ssize_t fuse_file_read_iter(struct kiocb *iocb, struct iov_iter *to) | ||
1476 | { | ||
1477 | struct file *file = iocb->ki_filp; | ||
1478 | struct fuse_file *ff = file->private_data; | ||
1479 | |||
1480 | if (is_bad_inode(file_inode(file))) | ||
1481 | return -EIO; | ||
1482 | |||
1483 | if (!(ff->open_flags & FOPEN_DIRECT_IO)) | ||
1484 | return fuse_cache_read_iter(iocb, to); | ||
1485 | else | ||
1486 | return fuse_direct_read_iter(iocb, to); | ||
1487 | } | ||
1488 | |||
1489 | static ssize_t fuse_file_write_iter(struct kiocb *iocb, struct iov_iter *from) | ||
1490 | { | ||
1491 | struct file *file = iocb->ki_filp; | ||
1492 | struct fuse_file *ff = file->private_data; | ||
1493 | |||
1494 | if (is_bad_inode(file_inode(file))) | ||
1495 | return -EIO; | ||
1496 | |||
1497 | if (!(ff->open_flags & FOPEN_DIRECT_IO)) | ||
1498 | return fuse_cache_write_iter(iocb, from); | ||
1499 | else | ||
1500 | return fuse_direct_write_iter(iocb, from); | ||
1501 | } | ||
1502 | |||
1457 | static void fuse_writepage_free(struct fuse_conn *fc, struct fuse_req *req) | 1503 | static void fuse_writepage_free(struct fuse_conn *fc, struct fuse_req *req) |
1458 | { | 1504 | { |
1459 | int i; | 1505 | int i; |
@@ -1481,20 +1527,18 @@ static void fuse_writepage_finish(struct fuse_conn *fc, struct fuse_req *req) | |||
1481 | wake_up(&fi->page_waitq); | 1527 | wake_up(&fi->page_waitq); |
1482 | } | 1528 | } |
1483 | 1529 | ||
1484 | /* Called under fc->lock, may release and reacquire it */ | 1530 | /* Called under fi->lock, may release and reacquire it */ |
1485 | static void fuse_send_writepage(struct fuse_conn *fc, struct fuse_req *req, | 1531 | static void fuse_send_writepage(struct fuse_conn *fc, struct fuse_req *req, |
1486 | loff_t size) | 1532 | loff_t size) |
1487 | __releases(fc->lock) | 1533 | __releases(fi->lock) |
1488 | __acquires(fc->lock) | 1534 | __acquires(fi->lock) |
1489 | { | 1535 | { |
1536 | struct fuse_req *aux, *next; | ||
1490 | struct fuse_inode *fi = get_fuse_inode(req->inode); | 1537 | struct fuse_inode *fi = get_fuse_inode(req->inode); |
1491 | struct fuse_write_in *inarg = &req->misc.write.in; | 1538 | struct fuse_write_in *inarg = &req->misc.write.in; |
1492 | __u64 data_size = req->num_pages * PAGE_SIZE; | 1539 | __u64 data_size = req->num_pages * PAGE_SIZE; |
1493 | bool queued; | 1540 | bool queued; |
1494 | 1541 | ||
1495 | if (!fc->connected) | ||
1496 | goto out_free; | ||
1497 | |||
1498 | if (inarg->offset + data_size <= size) { | 1542 | if (inarg->offset + data_size <= size) { |
1499 | inarg->size = data_size; | 1543 | inarg->size = data_size; |
1500 | } else if (inarg->offset < size) { | 1544 | } else if (inarg->offset < size) { |
@@ -1505,28 +1549,40 @@ __acquires(fc->lock) | |||
1505 | } | 1549 | } |
1506 | 1550 | ||
1507 | req->in.args[1].size = inarg->size; | 1551 | req->in.args[1].size = inarg->size; |
1508 | fi->writectr++; | ||
1509 | queued = fuse_request_queue_background(fc, req); | 1552 | queued = fuse_request_queue_background(fc, req); |
1510 | WARN_ON(!queued); | 1553 | /* Fails on broken connection only */ |
1554 | if (unlikely(!queued)) | ||
1555 | goto out_free; | ||
1556 | |||
1557 | fi->writectr++; | ||
1511 | return; | 1558 | return; |
1512 | 1559 | ||
1513 | out_free: | 1560 | out_free: |
1514 | fuse_writepage_finish(fc, req); | 1561 | fuse_writepage_finish(fc, req); |
1515 | spin_unlock(&fc->lock); | 1562 | spin_unlock(&fi->lock); |
1563 | |||
1564 | /* After fuse_writepage_finish() aux request list is private */ | ||
1565 | for (aux = req->misc.write.next; aux; aux = next) { | ||
1566 | next = aux->misc.write.next; | ||
1567 | aux->misc.write.next = NULL; | ||
1568 | fuse_writepage_free(fc, aux); | ||
1569 | fuse_put_request(fc, aux); | ||
1570 | } | ||
1571 | |||
1516 | fuse_writepage_free(fc, req); | 1572 | fuse_writepage_free(fc, req); |
1517 | fuse_put_request(fc, req); | 1573 | fuse_put_request(fc, req); |
1518 | spin_lock(&fc->lock); | 1574 | spin_lock(&fi->lock); |
1519 | } | 1575 | } |
1520 | 1576 | ||
1521 | /* | 1577 | /* |
1522 | * If fi->writectr is positive (no truncate or fsync going on) send | 1578 | * If fi->writectr is positive (no truncate or fsync going on) send |
1523 | * all queued writepage requests. | 1579 | * all queued writepage requests. |
1524 | * | 1580 | * |
1525 | * Called with fc->lock | 1581 | * Called with fi->lock |
1526 | */ | 1582 | */ |
1527 | void fuse_flush_writepages(struct inode *inode) | 1583 | void fuse_flush_writepages(struct inode *inode) |
1528 | __releases(fc->lock) | 1584 | __releases(fi->lock) |
1529 | __acquires(fc->lock) | 1585 | __acquires(fi->lock) |
1530 | { | 1586 | { |
1531 | struct fuse_conn *fc = get_fuse_conn(inode); | 1587 | struct fuse_conn *fc = get_fuse_conn(inode); |
1532 | struct fuse_inode *fi = get_fuse_inode(inode); | 1588 | struct fuse_inode *fi = get_fuse_inode(inode); |
@@ -1546,7 +1602,7 @@ static void fuse_writepage_end(struct fuse_conn *fc, struct fuse_req *req) | |||
1546 | struct fuse_inode *fi = get_fuse_inode(inode); | 1602 | struct fuse_inode *fi = get_fuse_inode(inode); |
1547 | 1603 | ||
1548 | mapping_set_error(inode->i_mapping, req->out.h.error); | 1604 | mapping_set_error(inode->i_mapping, req->out.h.error); |
1549 | spin_lock(&fc->lock); | 1605 | spin_lock(&fi->lock); |
1550 | while (req->misc.write.next) { | 1606 | while (req->misc.write.next) { |
1551 | struct fuse_conn *fc = get_fuse_conn(inode); | 1607 | struct fuse_conn *fc = get_fuse_conn(inode); |
1552 | struct fuse_write_in *inarg = &req->misc.write.in; | 1608 | struct fuse_write_in *inarg = &req->misc.write.in; |
@@ -1583,7 +1639,7 @@ static void fuse_writepage_end(struct fuse_conn *fc, struct fuse_req *req) | |||
1583 | } | 1639 | } |
1584 | fi->writectr--; | 1640 | fi->writectr--; |
1585 | fuse_writepage_finish(fc, req); | 1641 | fuse_writepage_finish(fc, req); |
1586 | spin_unlock(&fc->lock); | 1642 | spin_unlock(&fi->lock); |
1587 | fuse_writepage_free(fc, req); | 1643 | fuse_writepage_free(fc, req); |
1588 | } | 1644 | } |
1589 | 1645 | ||
@@ -1592,13 +1648,13 @@ static struct fuse_file *__fuse_write_file_get(struct fuse_conn *fc, | |||
1592 | { | 1648 | { |
1593 | struct fuse_file *ff = NULL; | 1649 | struct fuse_file *ff = NULL; |
1594 | 1650 | ||
1595 | spin_lock(&fc->lock); | 1651 | spin_lock(&fi->lock); |
1596 | if (!list_empty(&fi->write_files)) { | 1652 | if (!list_empty(&fi->write_files)) { |
1597 | ff = list_entry(fi->write_files.next, struct fuse_file, | 1653 | ff = list_entry(fi->write_files.next, struct fuse_file, |
1598 | write_entry); | 1654 | write_entry); |
1599 | fuse_file_get(ff); | 1655 | fuse_file_get(ff); |
1600 | } | 1656 | } |
1601 | spin_unlock(&fc->lock); | 1657 | spin_unlock(&fi->lock); |
1602 | 1658 | ||
1603 | return ff; | 1659 | return ff; |
1604 | } | 1660 | } |
@@ -1669,11 +1725,11 @@ static int fuse_writepage_locked(struct page *page) | |||
1669 | inc_wb_stat(&inode_to_bdi(inode)->wb, WB_WRITEBACK); | 1725 | inc_wb_stat(&inode_to_bdi(inode)->wb, WB_WRITEBACK); |
1670 | inc_node_page_state(tmp_page, NR_WRITEBACK_TEMP); | 1726 | inc_node_page_state(tmp_page, NR_WRITEBACK_TEMP); |
1671 | 1727 | ||
1672 | spin_lock(&fc->lock); | 1728 | spin_lock(&fi->lock); |
1673 | list_add(&req->writepages_entry, &fi->writepages); | 1729 | list_add(&req->writepages_entry, &fi->writepages); |
1674 | list_add_tail(&req->list, &fi->queued_writes); | 1730 | list_add_tail(&req->list, &fi->queued_writes); |
1675 | fuse_flush_writepages(inode); | 1731 | fuse_flush_writepages(inode); |
1676 | spin_unlock(&fc->lock); | 1732 | spin_unlock(&fi->lock); |
1677 | 1733 | ||
1678 | end_page_writeback(page); | 1734 | end_page_writeback(page); |
1679 | 1735 | ||
@@ -1722,21 +1778,27 @@ static void fuse_writepages_send(struct fuse_fill_wb_data *data) | |||
1722 | { | 1778 | { |
1723 | struct fuse_req *req = data->req; | 1779 | struct fuse_req *req = data->req; |
1724 | struct inode *inode = data->inode; | 1780 | struct inode *inode = data->inode; |
1725 | struct fuse_conn *fc = get_fuse_conn(inode); | ||
1726 | struct fuse_inode *fi = get_fuse_inode(inode); | 1781 | struct fuse_inode *fi = get_fuse_inode(inode); |
1727 | int num_pages = req->num_pages; | 1782 | int num_pages = req->num_pages; |
1728 | int i; | 1783 | int i; |
1729 | 1784 | ||
1730 | req->ff = fuse_file_get(data->ff); | 1785 | req->ff = fuse_file_get(data->ff); |
1731 | spin_lock(&fc->lock); | 1786 | spin_lock(&fi->lock); |
1732 | list_add_tail(&req->list, &fi->queued_writes); | 1787 | list_add_tail(&req->list, &fi->queued_writes); |
1733 | fuse_flush_writepages(inode); | 1788 | fuse_flush_writepages(inode); |
1734 | spin_unlock(&fc->lock); | 1789 | spin_unlock(&fi->lock); |
1735 | 1790 | ||
1736 | for (i = 0; i < num_pages; i++) | 1791 | for (i = 0; i < num_pages; i++) |
1737 | end_page_writeback(data->orig_pages[i]); | 1792 | end_page_writeback(data->orig_pages[i]); |
1738 | } | 1793 | } |
1739 | 1794 | ||
1795 | /* | ||
1796 | * First recheck under fi->lock if the offending offset is still under | ||
1797 | * writeback. If yes, then iterate auxiliary write requests, to see if there's | ||
1798 | * one already added for a page at this offset. If there's none, then insert | ||
1799 | * this new request onto the auxiliary list, otherwise reuse the existing one by | ||
1800 | * copying the new page contents over to the old temporary page. | ||
1801 | */ | ||
1740 | static bool fuse_writepage_in_flight(struct fuse_req *new_req, | 1802 | static bool fuse_writepage_in_flight(struct fuse_req *new_req, |
1741 | struct page *page) | 1803 | struct page *page) |
1742 | { | 1804 | { |
@@ -1744,57 +1806,50 @@ static bool fuse_writepage_in_flight(struct fuse_req *new_req, | |||
1744 | struct fuse_inode *fi = get_fuse_inode(new_req->inode); | 1806 | struct fuse_inode *fi = get_fuse_inode(new_req->inode); |
1745 | struct fuse_req *tmp; | 1807 | struct fuse_req *tmp; |
1746 | struct fuse_req *old_req; | 1808 | struct fuse_req *old_req; |
1747 | bool found = false; | ||
1748 | pgoff_t curr_index; | ||
1749 | 1809 | ||
1750 | BUG_ON(new_req->num_pages != 0); | 1810 | WARN_ON(new_req->num_pages != 0); |
1751 | 1811 | ||
1752 | spin_lock(&fc->lock); | 1812 | spin_lock(&fi->lock); |
1753 | list_del(&new_req->writepages_entry); | 1813 | list_del(&new_req->writepages_entry); |
1754 | list_for_each_entry(old_req, &fi->writepages, writepages_entry) { | 1814 | old_req = fuse_find_writeback(fi, page->index, page->index); |
1755 | BUG_ON(old_req->inode != new_req->inode); | 1815 | if (!old_req) { |
1756 | curr_index = old_req->misc.write.in.offset >> PAGE_SHIFT; | ||
1757 | if (curr_index <= page->index && | ||
1758 | page->index < curr_index + old_req->num_pages) { | ||
1759 | found = true; | ||
1760 | break; | ||
1761 | } | ||
1762 | } | ||
1763 | if (!found) { | ||
1764 | list_add(&new_req->writepages_entry, &fi->writepages); | 1816 | list_add(&new_req->writepages_entry, &fi->writepages); |
1765 | goto out_unlock; | 1817 | spin_unlock(&fi->lock); |
1818 | return false; | ||
1766 | } | 1819 | } |
1767 | 1820 | ||
1768 | new_req->num_pages = 1; | 1821 | new_req->num_pages = 1; |
1769 | for (tmp = old_req; tmp != NULL; tmp = tmp->misc.write.next) { | 1822 | for (tmp = old_req->misc.write.next; tmp; tmp = tmp->misc.write.next) { |
1770 | BUG_ON(tmp->inode != new_req->inode); | 1823 | pgoff_t curr_index; |
1824 | |||
1825 | WARN_ON(tmp->inode != new_req->inode); | ||
1771 | curr_index = tmp->misc.write.in.offset >> PAGE_SHIFT; | 1826 | curr_index = tmp->misc.write.in.offset >> PAGE_SHIFT; |
1772 | if (tmp->num_pages == 1 && | 1827 | if (curr_index == page->index) { |
1773 | curr_index == page->index) { | 1828 | WARN_ON(tmp->num_pages != 1); |
1774 | old_req = tmp; | 1829 | WARN_ON(!test_bit(FR_PENDING, &tmp->flags)); |
1830 | swap(tmp->pages[0], new_req->pages[0]); | ||
1831 | break; | ||
1775 | } | 1832 | } |
1776 | } | 1833 | } |
1777 | 1834 | ||
1778 | if (old_req->num_pages == 1 && test_bit(FR_PENDING, &old_req->flags)) { | 1835 | if (!tmp) { |
1779 | struct backing_dev_info *bdi = inode_to_bdi(page->mapping->host); | 1836 | new_req->misc.write.next = old_req->misc.write.next; |
1837 | old_req->misc.write.next = new_req; | ||
1838 | } | ||
1839 | |||
1840 | spin_unlock(&fi->lock); | ||
1780 | 1841 | ||
1781 | copy_highpage(old_req->pages[0], page); | 1842 | if (tmp) { |
1782 | spin_unlock(&fc->lock); | 1843 | struct backing_dev_info *bdi = inode_to_bdi(new_req->inode); |
1783 | 1844 | ||
1784 | dec_wb_stat(&bdi->wb, WB_WRITEBACK); | 1845 | dec_wb_stat(&bdi->wb, WB_WRITEBACK); |
1785 | dec_node_page_state(new_req->pages[0], NR_WRITEBACK_TEMP); | 1846 | dec_node_page_state(new_req->pages[0], NR_WRITEBACK_TEMP); |
1786 | wb_writeout_inc(&bdi->wb); | 1847 | wb_writeout_inc(&bdi->wb); |
1787 | fuse_writepage_free(fc, new_req); | 1848 | fuse_writepage_free(fc, new_req); |
1788 | fuse_request_free(new_req); | 1849 | fuse_request_free(new_req); |
1789 | goto out; | ||
1790 | } else { | ||
1791 | new_req->misc.write.next = old_req->misc.write.next; | ||
1792 | old_req->misc.write.next = new_req; | ||
1793 | } | 1850 | } |
1794 | out_unlock: | 1851 | |
1795 | spin_unlock(&fc->lock); | 1852 | return true; |
1796 | out: | ||
1797 | return found; | ||
1798 | } | 1853 | } |
1799 | 1854 | ||
1800 | static int fuse_writepages_fill(struct page *page, | 1855 | static int fuse_writepages_fill(struct page *page, |
@@ -1803,6 +1858,7 @@ static int fuse_writepages_fill(struct page *page, | |||
1803 | struct fuse_fill_wb_data *data = _data; | 1858 | struct fuse_fill_wb_data *data = _data; |
1804 | struct fuse_req *req = data->req; | 1859 | struct fuse_req *req = data->req; |
1805 | struct inode *inode = data->inode; | 1860 | struct inode *inode = data->inode; |
1861 | struct fuse_inode *fi = get_fuse_inode(inode); | ||
1806 | struct fuse_conn *fc = get_fuse_conn(inode); | 1862 | struct fuse_conn *fc = get_fuse_conn(inode); |
1807 | struct page *tmp_page; | 1863 | struct page *tmp_page; |
1808 | bool is_writeback; | 1864 | bool is_writeback; |
@@ -1873,9 +1929,9 @@ static int fuse_writepages_fill(struct page *page, | |||
1873 | req->end = fuse_writepage_end; | 1929 | req->end = fuse_writepage_end; |
1874 | req->inode = inode; | 1930 | req->inode = inode; |
1875 | 1931 | ||
1876 | spin_lock(&fc->lock); | 1932 | spin_lock(&fi->lock); |
1877 | list_add(&req->writepages_entry, &fi->writepages); | 1933 | list_add(&req->writepages_entry, &fi->writepages); |
1878 | spin_unlock(&fc->lock); | 1934 | spin_unlock(&fi->lock); |
1879 | 1935 | ||
1880 | data->req = req; | 1936 | data->req = req; |
1881 | } | 1937 | } |
@@ -1898,12 +1954,12 @@ static int fuse_writepages_fill(struct page *page, | |||
1898 | data->orig_pages[req->num_pages] = page; | 1954 | data->orig_pages[req->num_pages] = page; |
1899 | 1955 | ||
1900 | /* | 1956 | /* |
1901 | * Protected by fc->lock against concurrent access by | 1957 | * Protected by fi->lock against concurrent access by |
1902 | * fuse_page_is_writeback(). | 1958 | * fuse_page_is_writeback(). |
1903 | */ | 1959 | */ |
1904 | spin_lock(&fc->lock); | 1960 | spin_lock(&fi->lock); |
1905 | req->num_pages++; | 1961 | req->num_pages++; |
1906 | spin_unlock(&fc->lock); | 1962 | spin_unlock(&fi->lock); |
1907 | 1963 | ||
1908 | out_unlock: | 1964 | out_unlock: |
1909 | unlock_page(page); | 1965 | unlock_page(page); |
@@ -2087,6 +2143,18 @@ static const struct vm_operations_struct fuse_file_vm_ops = { | |||
2087 | 2143 | ||
2088 | static int fuse_file_mmap(struct file *file, struct vm_area_struct *vma) | 2144 | static int fuse_file_mmap(struct file *file, struct vm_area_struct *vma) |
2089 | { | 2145 | { |
2146 | struct fuse_file *ff = file->private_data; | ||
2147 | |||
2148 | if (ff->open_flags & FOPEN_DIRECT_IO) { | ||
2149 | /* Can't provide the coherency needed for MAP_SHARED */ | ||
2150 | if (vma->vm_flags & VM_MAYSHARE) | ||
2151 | return -ENODEV; | ||
2152 | |||
2153 | invalidate_inode_pages2(file->f_mapping); | ||
2154 | |||
2155 | return generic_file_mmap(file, vma); | ||
2156 | } | ||
2157 | |||
2090 | if ((vma->vm_flags & VM_SHARED) && (vma->vm_flags & VM_MAYWRITE)) | 2158 | if ((vma->vm_flags & VM_SHARED) && (vma->vm_flags & VM_MAYWRITE)) |
2091 | fuse_link_write_file(file); | 2159 | fuse_link_write_file(file); |
2092 | 2160 | ||
@@ -2095,17 +2163,6 @@ static int fuse_file_mmap(struct file *file, struct vm_area_struct *vma) | |||
2095 | return 0; | 2163 | return 0; |
2096 | } | 2164 | } |
2097 | 2165 | ||
2098 | static int fuse_direct_mmap(struct file *file, struct vm_area_struct *vma) | ||
2099 | { | ||
2100 | /* Can't provide the coherency needed for MAP_SHARED */ | ||
2101 | if (vma->vm_flags & VM_MAYSHARE) | ||
2102 | return -ENODEV; | ||
2103 | |||
2104 | invalidate_inode_pages2(file->f_mapping); | ||
2105 | |||
2106 | return generic_file_mmap(file, vma); | ||
2107 | } | ||
2108 | |||
2109 | static int convert_fuse_file_lock(struct fuse_conn *fc, | 2166 | static int convert_fuse_file_lock(struct fuse_conn *fc, |
2110 | const struct fuse_file_lock *ffl, | 2167 | const struct fuse_file_lock *ffl, |
2111 | struct file_lock *fl) | 2168 | struct file_lock *fl) |
@@ -3114,6 +3171,7 @@ static const struct file_operations fuse_file_operations = { | |||
3114 | .lock = fuse_file_lock, | 3171 | .lock = fuse_file_lock, |
3115 | .flock = fuse_file_flock, | 3172 | .flock = fuse_file_flock, |
3116 | .splice_read = generic_file_splice_read, | 3173 | .splice_read = generic_file_splice_read, |
3174 | .splice_write = iter_file_splice_write, | ||
3117 | .unlocked_ioctl = fuse_file_ioctl, | 3175 | .unlocked_ioctl = fuse_file_ioctl, |
3118 | .compat_ioctl = fuse_file_compat_ioctl, | 3176 | .compat_ioctl = fuse_file_compat_ioctl, |
3119 | .poll = fuse_file_poll, | 3177 | .poll = fuse_file_poll, |
@@ -3121,24 +3179,6 @@ static const struct file_operations fuse_file_operations = { | |||
3121 | .copy_file_range = fuse_copy_file_range, | 3179 | .copy_file_range = fuse_copy_file_range, |
3122 | }; | 3180 | }; |
3123 | 3181 | ||
3124 | static const struct file_operations fuse_direct_io_file_operations = { | ||
3125 | .llseek = fuse_file_llseek, | ||
3126 | .read_iter = fuse_direct_read_iter, | ||
3127 | .write_iter = fuse_direct_write_iter, | ||
3128 | .mmap = fuse_direct_mmap, | ||
3129 | .open = fuse_open, | ||
3130 | .flush = fuse_flush, | ||
3131 | .release = fuse_release, | ||
3132 | .fsync = fuse_fsync, | ||
3133 | .lock = fuse_file_lock, | ||
3134 | .flock = fuse_file_flock, | ||
3135 | .unlocked_ioctl = fuse_file_ioctl, | ||
3136 | .compat_ioctl = fuse_file_compat_ioctl, | ||
3137 | .poll = fuse_file_poll, | ||
3138 | .fallocate = fuse_file_fallocate, | ||
3139 | /* no splice_read */ | ||
3140 | }; | ||
3141 | |||
3142 | static const struct address_space_operations fuse_file_aops = { | 3182 | static const struct address_space_operations fuse_file_aops = { |
3143 | .readpage = fuse_readpage, | 3183 | .readpage = fuse_readpage, |
3144 | .writepage = fuse_writepage, | 3184 | .writepage = fuse_writepage, |
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 2f2c92e6f8cb..0920c0c032a0 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h | |||
@@ -96,7 +96,7 @@ struct fuse_inode { | |||
96 | union { | 96 | union { |
97 | /* Write related fields (regular file only) */ | 97 | /* Write related fields (regular file only) */ |
98 | struct { | 98 | struct { |
99 | /* Files usable in writepage. Protected by fc->lock */ | 99 | /* Files usable in writepage. Protected by fi->lock */ |
100 | struct list_head write_files; | 100 | struct list_head write_files; |
101 | 101 | ||
102 | /* Writepages pending on truncate or fsync */ | 102 | /* Writepages pending on truncate or fsync */ |
@@ -144,6 +144,9 @@ struct fuse_inode { | |||
144 | 144 | ||
145 | /** Lock for serializing lookup and readdir for back compatibility*/ | 145 | /** Lock for serializing lookup and readdir for back compatibility*/ |
146 | struct mutex mutex; | 146 | struct mutex mutex; |
147 | |||
148 | /** Lock to protect write related fields */ | ||
149 | spinlock_t lock; | ||
147 | }; | 150 | }; |
148 | 151 | ||
149 | /** FUSE inode state bits */ | 152 | /** FUSE inode state bits */ |
@@ -163,7 +166,10 @@ struct fuse_file { | |||
163 | /** Fuse connection for this file */ | 166 | /** Fuse connection for this file */ |
164 | struct fuse_conn *fc; | 167 | struct fuse_conn *fc; |
165 | 168 | ||
166 | /** Request reserved for flush and release */ | 169 | /* |
170 | * Request reserved for flush and release. | ||
171 | * Modified under relative fuse_inode::lock. | ||
172 | */ | ||
167 | struct fuse_req *reserved_req; | 173 | struct fuse_req *reserved_req; |
168 | 174 | ||
169 | /** Kernel file handle guaranteed to be unique */ | 175 | /** Kernel file handle guaranteed to be unique */ |
@@ -538,7 +544,7 @@ struct fuse_conn { | |||
538 | struct fuse_iqueue iq; | 544 | struct fuse_iqueue iq; |
539 | 545 | ||
540 | /** The next unique kernel file handle */ | 546 | /** The next unique kernel file handle */ |
541 | u64 khctr; | 547 | atomic64_t khctr; |
542 | 548 | ||
543 | /** rbtree of fuse_files waiting for poll events indexed by ph */ | 549 | /** rbtree of fuse_files waiting for poll events indexed by ph */ |
544 | struct rb_root polled_files; | 550 | struct rb_root polled_files; |
@@ -624,6 +630,9 @@ struct fuse_conn { | |||
624 | /** Is open/release not implemented by fs? */ | 630 | /** Is open/release not implemented by fs? */ |
625 | unsigned no_open:1; | 631 | unsigned no_open:1; |
626 | 632 | ||
633 | /** Is opendir/releasedir not implemented by fs? */ | ||
634 | unsigned no_opendir:1; | ||
635 | |||
627 | /** Is fsync not implemented by fs? */ | 636 | /** Is fsync not implemented by fs? */ |
628 | unsigned no_fsync:1; | 637 | unsigned no_fsync:1; |
629 | 638 | ||
@@ -730,7 +739,7 @@ struct fuse_conn { | |||
730 | struct fuse_req *destroy_req; | 739 | struct fuse_req *destroy_req; |
731 | 740 | ||
732 | /** Version counter for attribute changes */ | 741 | /** Version counter for attribute changes */ |
733 | u64 attr_version; | 742 | atomic64_t attr_version; |
734 | 743 | ||
735 | /** Called on final put */ | 744 | /** Called on final put */ |
736 | void (*release)(struct fuse_conn *); | 745 | void (*release)(struct fuse_conn *); |
@@ -770,6 +779,11 @@ static inline int invalid_nodeid(u64 nodeid) | |||
770 | return !nodeid || nodeid == FUSE_ROOT_ID; | 779 | return !nodeid || nodeid == FUSE_ROOT_ID; |
771 | } | 780 | } |
772 | 781 | ||
782 | static inline u64 fuse_get_attr_version(struct fuse_conn *fc) | ||
783 | { | ||
784 | return atomic64_read(&fc->attr_version); | ||
785 | } | ||
786 | |||
773 | /** Device operations */ | 787 | /** Device operations */ |
774 | extern const struct file_operations fuse_dev_operations; | 788 | extern const struct file_operations fuse_dev_operations; |
775 | 789 | ||
@@ -817,7 +831,7 @@ struct fuse_file *fuse_file_alloc(struct fuse_conn *fc); | |||
817 | void fuse_file_free(struct fuse_file *ff); | 831 | void fuse_file_free(struct fuse_file *ff); |
818 | void fuse_finish_open(struct inode *inode, struct file *file); | 832 | void fuse_finish_open(struct inode *inode, struct file *file); |
819 | 833 | ||
820 | void fuse_sync_release(struct fuse_file *ff, int flags); | 834 | void fuse_sync_release(struct fuse_inode *fi, struct fuse_file *ff, int flags); |
821 | 835 | ||
822 | /** | 836 | /** |
823 | * Send RELEASE or RELEASEDIR request | 837 | * Send RELEASE or RELEASEDIR request |
@@ -936,7 +950,7 @@ void fuse_request_send_background(struct fuse_conn *fc, struct fuse_req *req); | |||
936 | bool fuse_request_queue_background(struct fuse_conn *fc, struct fuse_req *req); | 950 | bool fuse_request_queue_background(struct fuse_conn *fc, struct fuse_req *req); |
937 | 951 | ||
938 | /* Abort all requests */ | 952 | /* Abort all requests */ |
939 | void fuse_abort_conn(struct fuse_conn *fc, bool is_abort); | 953 | void fuse_abort_conn(struct fuse_conn *fc); |
940 | void fuse_wait_aborted(struct fuse_conn *fc); | 954 | void fuse_wait_aborted(struct fuse_conn *fc); |
941 | 955 | ||
942 | /** | 956 | /** |
@@ -1000,8 +1014,6 @@ void fuse_flush_writepages(struct inode *inode); | |||
1000 | void fuse_set_nowrite(struct inode *inode); | 1014 | void fuse_set_nowrite(struct inode *inode); |
1001 | void fuse_release_nowrite(struct inode *inode); | 1015 | void fuse_release_nowrite(struct inode *inode); |
1002 | 1016 | ||
1003 | u64 fuse_get_attr_version(struct fuse_conn *fc); | ||
1004 | |||
1005 | /** | 1017 | /** |
1006 | * File-system tells the kernel to invalidate cache for the given node id. | 1018 | * File-system tells the kernel to invalidate cache for the given node id. |
1007 | */ | 1019 | */ |
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 16750ed591ae..ec5d9953dfb6 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c | |||
@@ -97,6 +97,7 @@ static struct inode *fuse_alloc_inode(struct super_block *sb) | |||
97 | fi->orig_ino = 0; | 97 | fi->orig_ino = 0; |
98 | fi->state = 0; | 98 | fi->state = 0; |
99 | mutex_init(&fi->mutex); | 99 | mutex_init(&fi->mutex); |
100 | spin_lock_init(&fi->lock); | ||
100 | fi->forget = fuse_alloc_forget(); | 101 | fi->forget = fuse_alloc_forget(); |
101 | if (!fi->forget) { | 102 | if (!fi->forget) { |
102 | kmem_cache_free(fuse_inode_cachep, inode); | 103 | kmem_cache_free(fuse_inode_cachep, inode); |
@@ -163,7 +164,9 @@ void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr, | |||
163 | struct fuse_conn *fc = get_fuse_conn(inode); | 164 | struct fuse_conn *fc = get_fuse_conn(inode); |
164 | struct fuse_inode *fi = get_fuse_inode(inode); | 165 | struct fuse_inode *fi = get_fuse_inode(inode); |
165 | 166 | ||
166 | fi->attr_version = ++fc->attr_version; | 167 | lockdep_assert_held(&fi->lock); |
168 | |||
169 | fi->attr_version = atomic64_inc_return(&fc->attr_version); | ||
167 | fi->i_time = attr_valid; | 170 | fi->i_time = attr_valid; |
168 | WRITE_ONCE(fi->inval_mask, 0); | 171 | WRITE_ONCE(fi->inval_mask, 0); |
169 | 172 | ||
@@ -209,10 +212,10 @@ void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr, | |||
209 | loff_t oldsize; | 212 | loff_t oldsize; |
210 | struct timespec64 old_mtime; | 213 | struct timespec64 old_mtime; |
211 | 214 | ||
212 | spin_lock(&fc->lock); | 215 | spin_lock(&fi->lock); |
213 | if ((attr_version != 0 && fi->attr_version > attr_version) || | 216 | if ((attr_version != 0 && fi->attr_version > attr_version) || |
214 | test_bit(FUSE_I_SIZE_UNSTABLE, &fi->state)) { | 217 | test_bit(FUSE_I_SIZE_UNSTABLE, &fi->state)) { |
215 | spin_unlock(&fc->lock); | 218 | spin_unlock(&fi->lock); |
216 | return; | 219 | return; |
217 | } | 220 | } |
218 | 221 | ||
@@ -227,7 +230,7 @@ void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr, | |||
227 | */ | 230 | */ |
228 | if (!is_wb || !S_ISREG(inode->i_mode)) | 231 | if (!is_wb || !S_ISREG(inode->i_mode)) |
229 | i_size_write(inode, attr->size); | 232 | i_size_write(inode, attr->size); |
230 | spin_unlock(&fc->lock); | 233 | spin_unlock(&fi->lock); |
231 | 234 | ||
232 | if (!is_wb && S_ISREG(inode->i_mode)) { | 235 | if (!is_wb && S_ISREG(inode->i_mode)) { |
233 | bool inval = false; | 236 | bool inval = false; |
@@ -322,9 +325,9 @@ struct inode *fuse_iget(struct super_block *sb, u64 nodeid, | |||
322 | } | 325 | } |
323 | 326 | ||
324 | fi = get_fuse_inode(inode); | 327 | fi = get_fuse_inode(inode); |
325 | spin_lock(&fc->lock); | 328 | spin_lock(&fi->lock); |
326 | fi->nlookup++; | 329 | fi->nlookup++; |
327 | spin_unlock(&fc->lock); | 330 | spin_unlock(&fi->lock); |
328 | fuse_change_attributes(inode, attr, attr_valid, attr_version); | 331 | fuse_change_attributes(inode, attr, attr_valid, attr_version); |
329 | 332 | ||
330 | return inode; | 333 | return inode; |
@@ -376,7 +379,7 @@ void fuse_unlock_inode(struct inode *inode, bool locked) | |||
376 | 379 | ||
377 | static void fuse_umount_begin(struct super_block *sb) | 380 | static void fuse_umount_begin(struct super_block *sb) |
378 | { | 381 | { |
379 | fuse_abort_conn(get_fuse_conn_super(sb), false); | 382 | fuse_abort_conn(get_fuse_conn_super(sb)); |
380 | } | 383 | } |
381 | 384 | ||
382 | static void fuse_send_destroy(struct fuse_conn *fc) | 385 | static void fuse_send_destroy(struct fuse_conn *fc) |
@@ -619,12 +622,12 @@ void fuse_conn_init(struct fuse_conn *fc, struct user_namespace *user_ns) | |||
619 | atomic_set(&fc->num_waiting, 0); | 622 | atomic_set(&fc->num_waiting, 0); |
620 | fc->max_background = FUSE_DEFAULT_MAX_BACKGROUND; | 623 | fc->max_background = FUSE_DEFAULT_MAX_BACKGROUND; |
621 | fc->congestion_threshold = FUSE_DEFAULT_CONGESTION_THRESHOLD; | 624 | fc->congestion_threshold = FUSE_DEFAULT_CONGESTION_THRESHOLD; |
622 | fc->khctr = 0; | 625 | atomic64_set(&fc->khctr, 0); |
623 | fc->polled_files = RB_ROOT; | 626 | fc->polled_files = RB_ROOT; |
624 | fc->blocked = 0; | 627 | fc->blocked = 0; |
625 | fc->initialized = 0; | 628 | fc->initialized = 0; |
626 | fc->connected = 1; | 629 | fc->connected = 1; |
627 | fc->attr_version = 1; | 630 | atomic64_set(&fc->attr_version, 1); |
628 | get_random_bytes(&fc->scramble_key, sizeof(fc->scramble_key)); | 631 | get_random_bytes(&fc->scramble_key, sizeof(fc->scramble_key)); |
629 | fc->pid_ns = get_pid_ns(task_active_pid_ns(current)); | 632 | fc->pid_ns = get_pid_ns(task_active_pid_ns(current)); |
630 | fc->user_ns = get_user_ns(user_ns); | 633 | fc->user_ns = get_user_ns(user_ns); |
@@ -969,7 +972,8 @@ static void fuse_send_init(struct fuse_conn *fc, struct fuse_req *req) | |||
969 | FUSE_DO_READDIRPLUS | FUSE_READDIRPLUS_AUTO | FUSE_ASYNC_DIO | | 972 | FUSE_DO_READDIRPLUS | FUSE_READDIRPLUS_AUTO | FUSE_ASYNC_DIO | |
970 | FUSE_WRITEBACK_CACHE | FUSE_NO_OPEN_SUPPORT | | 973 | FUSE_WRITEBACK_CACHE | FUSE_NO_OPEN_SUPPORT | |
971 | FUSE_PARALLEL_DIROPS | FUSE_HANDLE_KILLPRIV | FUSE_POSIX_ACL | | 974 | FUSE_PARALLEL_DIROPS | FUSE_HANDLE_KILLPRIV | FUSE_POSIX_ACL | |
972 | FUSE_ABORT_ERROR | FUSE_MAX_PAGES | FUSE_CACHE_SYMLINKS; | 975 | FUSE_ABORT_ERROR | FUSE_MAX_PAGES | FUSE_CACHE_SYMLINKS | |
976 | FUSE_NO_OPENDIR_SUPPORT; | ||
973 | req->in.h.opcode = FUSE_INIT; | 977 | req->in.h.opcode = FUSE_INIT; |
974 | req->in.numargs = 1; | 978 | req->in.numargs = 1; |
975 | req->in.args[0].size = sizeof(*arg); | 979 | req->in.args[0].size = sizeof(*arg); |
@@ -1242,7 +1246,7 @@ static void fuse_sb_destroy(struct super_block *sb) | |||
1242 | if (fc) { | 1246 | if (fc) { |
1243 | fuse_send_destroy(fc); | 1247 | fuse_send_destroy(fc); |
1244 | 1248 | ||
1245 | fuse_abort_conn(fc, false); | 1249 | fuse_abort_conn(fc); |
1246 | fuse_wait_aborted(fc); | 1250 | fuse_wait_aborted(fc); |
1247 | 1251 | ||
1248 | down_write(&fc->killsb); | 1252 | down_write(&fc->killsb); |
diff --git a/fs/fuse/readdir.c b/fs/fuse/readdir.c index ab18b78f4755..574d03f8a573 100644 --- a/fs/fuse/readdir.c +++ b/fs/fuse/readdir.c | |||
@@ -213,9 +213,9 @@ retry: | |||
213 | } | 213 | } |
214 | 214 | ||
215 | fi = get_fuse_inode(inode); | 215 | fi = get_fuse_inode(inode); |
216 | spin_lock(&fc->lock); | 216 | spin_lock(&fi->lock); |
217 | fi->nlookup++; | 217 | fi->nlookup++; |
218 | spin_unlock(&fc->lock); | 218 | spin_unlock(&fi->lock); |
219 | 219 | ||
220 | forget_all_cached_acls(inode); | 220 | forget_all_cached_acls(inode); |
221 | fuse_change_attributes(inode, &o->attr, | 221 | fuse_change_attributes(inode, &o->attr, |
diff --git a/include/uapi/linux/fuse.h b/include/uapi/linux/fuse.h index b4967d48bfda..2ac598614a8f 100644 --- a/include/uapi/linux/fuse.h +++ b/include/uapi/linux/fuse.h | |||
@@ -122,6 +122,9 @@ | |||
122 | * - add FOPEN_CACHE_DIR | 122 | * - add FOPEN_CACHE_DIR |
123 | * - add FUSE_MAX_PAGES, add max_pages to init_out | 123 | * - add FUSE_MAX_PAGES, add max_pages to init_out |
124 | * - add FUSE_CACHE_SYMLINKS | 124 | * - add FUSE_CACHE_SYMLINKS |
125 | * | ||
126 | * 7.29 | ||
127 | * - add FUSE_NO_OPENDIR_SUPPORT flag | ||
125 | */ | 128 | */ |
126 | 129 | ||
127 | #ifndef _LINUX_FUSE_H | 130 | #ifndef _LINUX_FUSE_H |
@@ -157,7 +160,7 @@ | |||
157 | #define FUSE_KERNEL_VERSION 7 | 160 | #define FUSE_KERNEL_VERSION 7 |
158 | 161 | ||
159 | /** Minor version number of this interface */ | 162 | /** Minor version number of this interface */ |
160 | #define FUSE_KERNEL_MINOR_VERSION 28 | 163 | #define FUSE_KERNEL_MINOR_VERSION 29 |
161 | 164 | ||
162 | /** The node ID of the root inode */ | 165 | /** The node ID of the root inode */ |
163 | #define FUSE_ROOT_ID 1 | 166 | #define FUSE_ROOT_ID 1 |
@@ -259,6 +262,7 @@ struct fuse_file_lock { | |||
259 | * FUSE_ABORT_ERROR: reading the device after abort returns ECONNABORTED | 262 | * FUSE_ABORT_ERROR: reading the device after abort returns ECONNABORTED |
260 | * FUSE_MAX_PAGES: init_out.max_pages contains the max number of req pages | 263 | * FUSE_MAX_PAGES: init_out.max_pages contains the max number of req pages |
261 | * FUSE_CACHE_SYMLINKS: cache READLINK responses | 264 | * FUSE_CACHE_SYMLINKS: cache READLINK responses |
265 | * FUSE_NO_OPENDIR_SUPPORT: kernel supports zero-message opendir | ||
262 | */ | 266 | */ |
263 | #define FUSE_ASYNC_READ (1 << 0) | 267 | #define FUSE_ASYNC_READ (1 << 0) |
264 | #define FUSE_POSIX_LOCKS (1 << 1) | 268 | #define FUSE_POSIX_LOCKS (1 << 1) |
@@ -284,6 +288,7 @@ struct fuse_file_lock { | |||
284 | #define FUSE_ABORT_ERROR (1 << 21) | 288 | #define FUSE_ABORT_ERROR (1 << 21) |
285 | #define FUSE_MAX_PAGES (1 << 22) | 289 | #define FUSE_MAX_PAGES (1 << 22) |
286 | #define FUSE_CACHE_SYMLINKS (1 << 23) | 290 | #define FUSE_CACHE_SYMLINKS (1 << 23) |
291 | #define FUSE_NO_OPENDIR_SUPPORT (1 << 24) | ||
287 | 292 | ||
288 | /** | 293 | /** |
289 | * CUSE INIT request/reply flags | 294 | * CUSE INIT request/reply flags |