diff options
| -rw-r--r-- | fs/fuse/dev.c | 86 | ||||
| -rw-r--r-- | fs/fuse/dir.c | 53 | ||||
| -rw-r--r-- | fs/fuse/fuse_i.h | 28 | ||||
| -rw-r--r-- | fs/fuse/inode.c | 30 |
4 files changed, 133 insertions, 64 deletions
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index 6e07696308dc..fed65303eeeb 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c | |||
| @@ -251,6 +251,20 @@ static void queue_request(struct fuse_conn *fc, struct fuse_req *req) | |||
| 251 | kill_fasync(&fc->fasync, SIGIO, POLL_IN); | 251 | kill_fasync(&fc->fasync, SIGIO, POLL_IN); |
| 252 | } | 252 | } |
| 253 | 253 | ||
| 254 | void fuse_queue_forget(struct fuse_conn *fc, struct fuse_forget_link *forget, | ||
| 255 | u64 nodeid, u64 nlookup) | ||
| 256 | { | ||
| 257 | forget->nodeid = nodeid; | ||
| 258 | forget->nlookup = nlookup; | ||
| 259 | |||
| 260 | spin_lock(&fc->lock); | ||
| 261 | fc->forget_list_tail->next = forget; | ||
| 262 | fc->forget_list_tail = forget; | ||
| 263 | wake_up(&fc->waitq); | ||
| 264 | kill_fasync(&fc->fasync, SIGIO, POLL_IN); | ||
| 265 | spin_unlock(&fc->lock); | ||
| 266 | } | ||
| 267 | |||
| 254 | static void flush_bg_queue(struct fuse_conn *fc) | 268 | static void flush_bg_queue(struct fuse_conn *fc) |
| 255 | { | 269 | { |
| 256 | while (fc->active_background < fc->max_background && | 270 | while (fc->active_background < fc->max_background && |
| @@ -438,12 +452,6 @@ static void fuse_request_send_nowait(struct fuse_conn *fc, struct fuse_req *req) | |||
| 438 | } | 452 | } |
| 439 | } | 453 | } |
| 440 | 454 | ||
| 441 | void fuse_request_send_noreply(struct fuse_conn *fc, struct fuse_req *req) | ||
| 442 | { | ||
| 443 | req->isreply = 0; | ||
| 444 | fuse_request_send_nowait(fc, req); | ||
| 445 | } | ||
| 446 | |||
| 447 | void fuse_request_send_background(struct fuse_conn *fc, struct fuse_req *req) | 455 | void fuse_request_send_background(struct fuse_conn *fc, struct fuse_req *req) |
| 448 | { | 456 | { |
| 449 | req->isreply = 1; | 457 | req->isreply = 1; |
| @@ -896,9 +904,15 @@ static int fuse_copy_args(struct fuse_copy_state *cs, unsigned numargs, | |||
| 896 | return err; | 904 | return err; |
| 897 | } | 905 | } |
| 898 | 906 | ||
| 907 | static int forget_pending(struct fuse_conn *fc) | ||
| 908 | { | ||
| 909 | return fc->forget_list_head.next != NULL; | ||
| 910 | } | ||
| 911 | |||
| 899 | static int request_pending(struct fuse_conn *fc) | 912 | static int request_pending(struct fuse_conn *fc) |
| 900 | { | 913 | { |
| 901 | return !list_empty(&fc->pending) || !list_empty(&fc->interrupts); | 914 | return !list_empty(&fc->pending) || !list_empty(&fc->interrupts) || |
| 915 | forget_pending(fc); | ||
| 902 | } | 916 | } |
| 903 | 917 | ||
| 904 | /* Wait until a request is available on the pending list */ | 918 | /* Wait until a request is available on the pending list */ |
| @@ -960,6 +974,50 @@ __releases(fc->lock) | |||
| 960 | return err ? err : reqsize; | 974 | return err ? err : reqsize; |
| 961 | } | 975 | } |
| 962 | 976 | ||
| 977 | static struct fuse_forget_link *dequeue_forget(struct fuse_conn *fc) | ||
| 978 | { | ||
| 979 | struct fuse_forget_link *forget = fc->forget_list_head.next; | ||
| 980 | |||
| 981 | fc->forget_list_head.next = forget->next; | ||
| 982 | if (fc->forget_list_head.next == NULL) | ||
| 983 | fc->forget_list_tail = &fc->forget_list_head; | ||
| 984 | |||
| 985 | return forget; | ||
| 986 | } | ||
| 987 | |||
| 988 | static int fuse_read_single_forget(struct fuse_conn *fc, | ||
| 989 | struct fuse_copy_state *cs, | ||
| 990 | size_t nbytes) | ||
| 991 | __releases(fc->lock) | ||
| 992 | { | ||
| 993 | int err; | ||
| 994 | struct fuse_forget_link *forget = dequeue_forget(fc); | ||
| 995 | struct fuse_forget_in arg = { | ||
| 996 | .nlookup = forget->nlookup, | ||
| 997 | }; | ||
| 998 | struct fuse_in_header ih = { | ||
| 999 | .opcode = FUSE_FORGET, | ||
| 1000 | .nodeid = forget->nodeid, | ||
| 1001 | .unique = fuse_get_unique(fc), | ||
| 1002 | .len = sizeof(ih) + sizeof(arg), | ||
| 1003 | }; | ||
| 1004 | |||
| 1005 | spin_unlock(&fc->lock); | ||
| 1006 | kfree(forget); | ||
| 1007 | if (nbytes < ih.len) | ||
| 1008 | return -EINVAL; | ||
| 1009 | |||
| 1010 | err = fuse_copy_one(cs, &ih, sizeof(ih)); | ||
| 1011 | if (!err) | ||
| 1012 | err = fuse_copy_one(cs, &arg, sizeof(arg)); | ||
| 1013 | fuse_copy_finish(cs); | ||
| 1014 | |||
| 1015 | if (err) | ||
| 1016 | return err; | ||
| 1017 | |||
| 1018 | return ih.len; | ||
| 1019 | } | ||
| 1020 | |||
| 963 | /* | 1021 | /* |
| 964 | * Read a single request into the userspace filesystem's buffer. This | 1022 | * Read a single request into the userspace filesystem's buffer. This |
| 965 | * function waits until a request is available, then removes it from | 1023 | * function waits until a request is available, then removes it from |
| @@ -998,6 +1056,14 @@ static ssize_t fuse_dev_do_read(struct fuse_conn *fc, struct file *file, | |||
| 998 | return fuse_read_interrupt(fc, cs, nbytes, req); | 1056 | return fuse_read_interrupt(fc, cs, nbytes, req); |
| 999 | } | 1057 | } |
| 1000 | 1058 | ||
| 1059 | if (forget_pending(fc)) { | ||
| 1060 | if (list_empty(&fc->pending) || fc->forget_batch-- > 0) | ||
| 1061 | return fuse_read_single_forget(fc, cs, nbytes); | ||
| 1062 | |||
| 1063 | if (fc->forget_batch <= -8) | ||
| 1064 | fc->forget_batch = 16; | ||
| 1065 | } | ||
| 1066 | |||
| 1001 | req = list_entry(fc->pending.next, struct fuse_req, list); | 1067 | req = list_entry(fc->pending.next, struct fuse_req, list); |
| 1002 | req->state = FUSE_REQ_READING; | 1068 | req->state = FUSE_REQ_READING; |
| 1003 | list_move(&req->list, &fc->io); | 1069 | list_move(&req->list, &fc->io); |
| @@ -1090,7 +1156,7 @@ static ssize_t fuse_dev_splice_read(struct file *in, loff_t *ppos, | |||
| 1090 | if (!fc) | 1156 | if (!fc) |
| 1091 | return -EPERM; | 1157 | return -EPERM; |
| 1092 | 1158 | ||
| 1093 | bufs = kmalloc(pipe->buffers * sizeof (struct pipe_buffer), GFP_KERNEL); | 1159 | bufs = kmalloc(pipe->buffers * sizeof(struct pipe_buffer), GFP_KERNEL); |
| 1094 | if (!bufs) | 1160 | if (!bufs) |
| 1095 | return -ENOMEM; | 1161 | return -ENOMEM; |
| 1096 | 1162 | ||
| @@ -1626,7 +1692,7 @@ static ssize_t fuse_dev_splice_write(struct pipe_inode_info *pipe, | |||
| 1626 | if (!fc) | 1692 | if (!fc) |
| 1627 | return -EPERM; | 1693 | return -EPERM; |
| 1628 | 1694 | ||
| 1629 | bufs = kmalloc(pipe->buffers * sizeof (struct pipe_buffer), GFP_KERNEL); | 1695 | bufs = kmalloc(pipe->buffers * sizeof(struct pipe_buffer), GFP_KERNEL); |
| 1630 | if (!bufs) | 1696 | if (!bufs) |
| 1631 | return -ENOMEM; | 1697 | return -ENOMEM; |
| 1632 | 1698 | ||
| @@ -1770,6 +1836,8 @@ __acquires(fc->lock) | |||
| 1770 | flush_bg_queue(fc); | 1836 | flush_bg_queue(fc); |
| 1771 | end_requests(fc, &fc->pending); | 1837 | end_requests(fc, &fc->pending); |
| 1772 | end_requests(fc, &fc->processing); | 1838 | end_requests(fc, &fc->processing); |
| 1839 | while (forget_pending(fc)) | ||
| 1840 | kfree(dequeue_forget(fc)); | ||
| 1773 | } | 1841 | } |
| 1774 | 1842 | ||
| 1775 | /* | 1843 | /* |
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index c9627c95482d..6ea42e98cb17 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c | |||
| @@ -10,9 +10,9 @@ | |||
| 10 | 10 | ||
| 11 | #include <linux/pagemap.h> | 11 | #include <linux/pagemap.h> |
| 12 | #include <linux/file.h> | 12 | #include <linux/file.h> |
| 13 | #include <linux/gfp.h> | ||
| 14 | #include <linux/sched.h> | 13 | #include <linux/sched.h> |
| 15 | #include <linux/namei.h> | 14 | #include <linux/namei.h> |
| 15 | #include <linux/slab.h> | ||
| 16 | 16 | ||
| 17 | #if BITS_PER_LONG >= 64 | 17 | #if BITS_PER_LONG >= 64 |
| 18 | static inline void fuse_dentry_settime(struct dentry *entry, u64 time) | 18 | static inline void fuse_dentry_settime(struct dentry *entry, u64 time) |
| @@ -165,7 +165,7 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd) | |||
| 165 | struct fuse_entry_out outarg; | 165 | struct fuse_entry_out outarg; |
| 166 | struct fuse_conn *fc; | 166 | struct fuse_conn *fc; |
| 167 | struct fuse_req *req; | 167 | struct fuse_req *req; |
| 168 | struct fuse_req *forget_req; | 168 | struct fuse_forget_link *forget; |
| 169 | struct dentry *parent; | 169 | struct dentry *parent; |
| 170 | u64 attr_version; | 170 | u64 attr_version; |
| 171 | 171 | ||
| @@ -178,8 +178,8 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd) | |||
| 178 | if (IS_ERR(req)) | 178 | if (IS_ERR(req)) |
| 179 | return 0; | 179 | return 0; |
| 180 | 180 | ||
| 181 | forget_req = fuse_get_req(fc); | 181 | forget = fuse_alloc_forget(); |
| 182 | if (IS_ERR(forget_req)) { | 182 | if (!forget) { |
| 183 | fuse_put_request(fc, req); | 183 | fuse_put_request(fc, req); |
| 184 | return 0; | 184 | return 0; |
| 185 | } | 185 | } |
| @@ -199,15 +199,14 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd) | |||
| 199 | if (!err) { | 199 | if (!err) { |
| 200 | struct fuse_inode *fi = get_fuse_inode(inode); | 200 | struct fuse_inode *fi = get_fuse_inode(inode); |
| 201 | if (outarg.nodeid != get_node_id(inode)) { | 201 | if (outarg.nodeid != get_node_id(inode)) { |
| 202 | fuse_send_forget(fc, forget_req, | 202 | fuse_queue_forget(fc, forget, outarg.nodeid, 1); |
| 203 | outarg.nodeid, 1); | ||
| 204 | return 0; | 203 | return 0; |
| 205 | } | 204 | } |
| 206 | spin_lock(&fc->lock); | 205 | spin_lock(&fc->lock); |
| 207 | fi->nlookup++; | 206 | fi->nlookup++; |
| 208 | spin_unlock(&fc->lock); | 207 | spin_unlock(&fc->lock); |
| 209 | } | 208 | } |
| 210 | fuse_put_request(fc, forget_req); | 209 | kfree(forget); |
| 211 | if (err || (outarg.attr.mode ^ inode->i_mode) & S_IFMT) | 210 | if (err || (outarg.attr.mode ^ inode->i_mode) & S_IFMT) |
| 212 | return 0; | 211 | return 0; |
| 213 | 212 | ||
| @@ -259,7 +258,7 @@ int fuse_lookup_name(struct super_block *sb, u64 nodeid, struct qstr *name, | |||
| 259 | { | 258 | { |
| 260 | struct fuse_conn *fc = get_fuse_conn_super(sb); | 259 | struct fuse_conn *fc = get_fuse_conn_super(sb); |
| 261 | struct fuse_req *req; | 260 | struct fuse_req *req; |
| 262 | struct fuse_req *forget_req; | 261 | struct fuse_forget_link *forget; |
| 263 | u64 attr_version; | 262 | u64 attr_version; |
| 264 | int err; | 263 | int err; |
| 265 | 264 | ||
| @@ -273,9 +272,9 @@ int fuse_lookup_name(struct super_block *sb, u64 nodeid, struct qstr *name, | |||
| 273 | if (IS_ERR(req)) | 272 | if (IS_ERR(req)) |
| 274 | goto out; | 273 | goto out; |
| 275 | 274 | ||
| 276 | forget_req = fuse_get_req(fc); | 275 | forget = fuse_alloc_forget(); |
| 277 | err = PTR_ERR(forget_req); | 276 | err = -ENOMEM; |
| 278 | if (IS_ERR(forget_req)) { | 277 | if (!forget) { |
| 279 | fuse_put_request(fc, req); | 278 | fuse_put_request(fc, req); |
| 280 | goto out; | 279 | goto out; |
| 281 | } | 280 | } |
| @@ -301,13 +300,13 @@ int fuse_lookup_name(struct super_block *sb, u64 nodeid, struct qstr *name, | |||
| 301 | attr_version); | 300 | attr_version); |
| 302 | err = -ENOMEM; | 301 | err = -ENOMEM; |
| 303 | if (!*inode) { | 302 | if (!*inode) { |
| 304 | fuse_send_forget(fc, forget_req, outarg->nodeid, 1); | 303 | fuse_queue_forget(fc, forget, outarg->nodeid, 1); |
| 305 | goto out; | 304 | goto out; |
| 306 | } | 305 | } |
| 307 | err = 0; | 306 | err = 0; |
| 308 | 307 | ||
| 309 | out_put_forget: | 308 | out_put_forget: |
| 310 | fuse_put_request(fc, forget_req); | 309 | kfree(forget); |
| 311 | out: | 310 | out: |
| 312 | return err; | 311 | return err; |
| 313 | } | 312 | } |
| @@ -374,7 +373,7 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode, | |||
| 374 | struct inode *inode; | 373 | struct inode *inode; |
| 375 | struct fuse_conn *fc = get_fuse_conn(dir); | 374 | struct fuse_conn *fc = get_fuse_conn(dir); |
| 376 | struct fuse_req *req; | 375 | struct fuse_req *req; |
| 377 | struct fuse_req *forget_req; | 376 | struct fuse_forget_link *forget; |
| 378 | struct fuse_create_in inarg; | 377 | struct fuse_create_in inarg; |
| 379 | struct fuse_open_out outopen; | 378 | struct fuse_open_out outopen; |
| 380 | struct fuse_entry_out outentry; | 379 | struct fuse_entry_out outentry; |
| @@ -388,9 +387,9 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode, | |||
| 388 | if (flags & O_DIRECT) | 387 | if (flags & O_DIRECT) |
| 389 | return -EINVAL; | 388 | return -EINVAL; |
| 390 | 389 | ||
| 391 | forget_req = fuse_get_req(fc); | 390 | forget = fuse_alloc_forget(); |
| 392 | if (IS_ERR(forget_req)) | 391 | if (!forget) |
| 393 | return PTR_ERR(forget_req); | 392 | return -ENOMEM; |
| 394 | 393 | ||
| 395 | req = fuse_get_req(fc); | 394 | req = fuse_get_req(fc); |
| 396 | err = PTR_ERR(req); | 395 | err = PTR_ERR(req); |
| @@ -448,10 +447,10 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode, | |||
| 448 | if (!inode) { | 447 | if (!inode) { |
| 449 | flags &= ~(O_CREAT | O_EXCL | O_TRUNC); | 448 | flags &= ~(O_CREAT | O_EXCL | O_TRUNC); |
| 450 | fuse_sync_release(ff, flags); | 449 | fuse_sync_release(ff, flags); |
| 451 | fuse_send_forget(fc, forget_req, outentry.nodeid, 1); | 450 | fuse_queue_forget(fc, forget, outentry.nodeid, 1); |
| 452 | return -ENOMEM; | 451 | return -ENOMEM; |
| 453 | } | 452 | } |
| 454 | fuse_put_request(fc, forget_req); | 453 | kfree(forget); |
| 455 | d_instantiate(entry, inode); | 454 | d_instantiate(entry, inode); |
| 456 | fuse_change_entry_timeout(entry, &outentry); | 455 | fuse_change_entry_timeout(entry, &outentry); |
| 457 | fuse_invalidate_attr(dir); | 456 | fuse_invalidate_attr(dir); |
| @@ -469,7 +468,7 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode, | |||
| 469 | out_put_request: | 468 | out_put_request: |
| 470 | fuse_put_request(fc, req); | 469 | fuse_put_request(fc, req); |
| 471 | out_put_forget_req: | 470 | out_put_forget_req: |
| 472 | fuse_put_request(fc, forget_req); | 471 | kfree(forget); |
| 473 | return err; | 472 | return err; |
| 474 | } | 473 | } |
| 475 | 474 | ||
| @@ -483,12 +482,12 @@ static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req, | |||
| 483 | struct fuse_entry_out outarg; | 482 | struct fuse_entry_out outarg; |
| 484 | struct inode *inode; | 483 | struct inode *inode; |
| 485 | int err; | 484 | int err; |
| 486 | struct fuse_req *forget_req; | 485 | struct fuse_forget_link *forget; |
| 487 | 486 | ||
| 488 | forget_req = fuse_get_req(fc); | 487 | forget = fuse_alloc_forget(); |
| 489 | if (IS_ERR(forget_req)) { | 488 | if (!forget) { |
| 490 | fuse_put_request(fc, req); | 489 | fuse_put_request(fc, req); |
| 491 | return PTR_ERR(forget_req); | 490 | return -ENOMEM; |
| 492 | } | 491 | } |
| 493 | 492 | ||
| 494 | memset(&outarg, 0, sizeof(outarg)); | 493 | memset(&outarg, 0, sizeof(outarg)); |
| @@ -515,10 +514,10 @@ static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req, | |||
| 515 | inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, | 514 | inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, |
| 516 | &outarg.attr, entry_attr_timeout(&outarg), 0); | 515 | &outarg.attr, entry_attr_timeout(&outarg), 0); |
| 517 | if (!inode) { | 516 | if (!inode) { |
| 518 | fuse_send_forget(fc, forget_req, outarg.nodeid, 1); | 517 | fuse_queue_forget(fc, forget, outarg.nodeid, 1); |
| 519 | return -ENOMEM; | 518 | return -ENOMEM; |
| 520 | } | 519 | } |
| 521 | fuse_put_request(fc, forget_req); | 520 | kfree(forget); |
| 522 | 521 | ||
| 523 | if (S_ISDIR(inode->i_mode)) { | 522 | if (S_ISDIR(inode->i_mode)) { |
| 524 | struct dentry *alias; | 523 | struct dentry *alias; |
| @@ -541,7 +540,7 @@ static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req, | |||
| 541 | return 0; | 540 | return 0; |
| 542 | 541 | ||
| 543 | out_put_forget_req: | 542 | out_put_forget_req: |
| 544 | fuse_put_request(fc, forget_req); | 543 | kfree(forget); |
| 545 | return err; | 544 | return err; |
| 546 | } | 545 | } |
| 547 | 546 | ||
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 57d4a3a0f102..33369c63a522 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h | |||
| @@ -53,6 +53,13 @@ extern struct mutex fuse_mutex; | |||
| 53 | extern unsigned max_user_bgreq; | 53 | extern unsigned max_user_bgreq; |
| 54 | extern unsigned max_user_congthresh; | 54 | extern unsigned max_user_congthresh; |
| 55 | 55 | ||
| 56 | /* One forget request */ | ||
| 57 | struct fuse_forget_link { | ||
| 58 | u64 nodeid; | ||
| 59 | u64 nlookup; | ||
| 60 | struct fuse_forget_link *next; | ||
| 61 | }; | ||
| 62 | |||
| 56 | /** FUSE inode */ | 63 | /** FUSE inode */ |
| 57 | struct fuse_inode { | 64 | struct fuse_inode { |
| 58 | /** Inode data */ | 65 | /** Inode data */ |
| @@ -66,7 +73,7 @@ struct fuse_inode { | |||
| 66 | u64 nlookup; | 73 | u64 nlookup; |
| 67 | 74 | ||
| 68 | /** The request used for sending the FORGET message */ | 75 | /** The request used for sending the FORGET message */ |
| 69 | struct fuse_req *forget_req; | 76 | struct fuse_forget_link *forget; |
| 70 | 77 | ||
| 71 | /** Time in jiffies until the file attributes are valid */ | 78 | /** Time in jiffies until the file attributes are valid */ |
| 72 | u64 i_time; | 79 | u64 i_time; |
| @@ -255,7 +262,6 @@ struct fuse_req { | |||
| 255 | 262 | ||
| 256 | /** Data for asynchronous requests */ | 263 | /** Data for asynchronous requests */ |
| 257 | union { | 264 | union { |
| 258 | struct fuse_forget_in forget_in; | ||
| 259 | struct { | 265 | struct { |
| 260 | struct fuse_release_in in; | 266 | struct fuse_release_in in; |
| 261 | struct path path; | 267 | struct path path; |
| @@ -369,6 +375,13 @@ struct fuse_conn { | |||
| 369 | /** Pending interrupts */ | 375 | /** Pending interrupts */ |
| 370 | struct list_head interrupts; | 376 | struct list_head interrupts; |
| 371 | 377 | ||
| 378 | /** Queue of pending forgets */ | ||
| 379 | struct fuse_forget_link forget_list_head; | ||
| 380 | struct fuse_forget_link *forget_list_tail; | ||
| 381 | |||
| 382 | /** Batching of FORGET requests (positive indicates FORGET batch) */ | ||
| 383 | int forget_batch; | ||
| 384 | |||
| 372 | /** Flag indicating if connection is blocked. This will be | 385 | /** Flag indicating if connection is blocked. This will be |
| 373 | the case before the INIT reply is received, and if there | 386 | the case before the INIT reply is received, and if there |
| 374 | are too many outstading backgrounds requests */ | 387 | are too many outstading backgrounds requests */ |
| @@ -543,8 +556,10 @@ int fuse_lookup_name(struct super_block *sb, u64 nodeid, struct qstr *name, | |||
| 543 | /** | 556 | /** |
| 544 | * Send FORGET command | 557 | * Send FORGET command |
| 545 | */ | 558 | */ |
| 546 | void fuse_send_forget(struct fuse_conn *fc, struct fuse_req *req, | 559 | void fuse_queue_forget(struct fuse_conn *fc, struct fuse_forget_link *forget, |
| 547 | u64 nodeid, u64 nlookup); | 560 | u64 nodeid, u64 nlookup); |
| 561 | |||
| 562 | struct fuse_forget_link *fuse_alloc_forget(void); | ||
| 548 | 563 | ||
| 549 | /** | 564 | /** |
| 550 | * Initialize READ or READDIR request | 565 | * Initialize READ or READDIR request |
| @@ -656,11 +671,6 @@ void fuse_put_request(struct fuse_conn *fc, struct fuse_req *req); | |||
| 656 | void fuse_request_send(struct fuse_conn *fc, struct fuse_req *req); | 671 | void fuse_request_send(struct fuse_conn *fc, struct fuse_req *req); |
| 657 | 672 | ||
| 658 | /** | 673 | /** |
| 659 | * Send a request with no reply | ||
| 660 | */ | ||
| 661 | void fuse_request_send_noreply(struct fuse_conn *fc, struct fuse_req *req); | ||
| 662 | |||
| 663 | /** | ||
| 664 | * Send a request in the background | 674 | * Send a request in the background |
| 665 | */ | 675 | */ |
| 666 | void fuse_request_send_background(struct fuse_conn *fc, struct fuse_req *req); | 676 | void fuse_request_send_background(struct fuse_conn *fc, struct fuse_req *req); |
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index cfce3ad86a92..7ba4d351da65 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c | |||
| @@ -71,6 +71,11 @@ struct fuse_mount_data { | |||
| 71 | unsigned blksize; | 71 | unsigned blksize; |
| 72 | }; | 72 | }; |
| 73 | 73 | ||
| 74 | struct fuse_forget_link *fuse_alloc_forget() | ||
| 75 | { | ||
| 76 | return kzalloc(sizeof(struct fuse_forget_link), GFP_KERNEL); | ||
| 77 | } | ||
| 78 | |||
| 74 | static struct inode *fuse_alloc_inode(struct super_block *sb) | 79 | static struct inode *fuse_alloc_inode(struct super_block *sb) |
| 75 | { | 80 | { |
| 76 | struct inode *inode; | 81 | struct inode *inode; |
| @@ -90,8 +95,8 @@ static struct inode *fuse_alloc_inode(struct super_block *sb) | |||
| 90 | INIT_LIST_HEAD(&fi->queued_writes); | 95 | INIT_LIST_HEAD(&fi->queued_writes); |
| 91 | INIT_LIST_HEAD(&fi->writepages); | 96 | INIT_LIST_HEAD(&fi->writepages); |
| 92 | init_waitqueue_head(&fi->page_waitq); | 97 | init_waitqueue_head(&fi->page_waitq); |
| 93 | fi->forget_req = fuse_request_alloc(); | 98 | fi->forget = fuse_alloc_forget(); |
| 94 | if (!fi->forget_req) { | 99 | if (!fi->forget) { |
| 95 | kmem_cache_free(fuse_inode_cachep, inode); | 100 | kmem_cache_free(fuse_inode_cachep, inode); |
| 96 | return NULL; | 101 | return NULL; |
| 97 | } | 102 | } |
| @@ -104,24 +109,10 @@ static void fuse_destroy_inode(struct inode *inode) | |||
| 104 | struct fuse_inode *fi = get_fuse_inode(inode); | 109 | struct fuse_inode *fi = get_fuse_inode(inode); |
| 105 | BUG_ON(!list_empty(&fi->write_files)); | 110 | BUG_ON(!list_empty(&fi->write_files)); |
| 106 | BUG_ON(!list_empty(&fi->queued_writes)); | 111 | BUG_ON(!list_empty(&fi->queued_writes)); |
| 107 | if (fi->forget_req) | 112 | kfree(fi->forget); |
| 108 | fuse_request_free(fi->forget_req); | ||
| 109 | kmem_cache_free(fuse_inode_cachep, inode); | 113 | kmem_cache_free(fuse_inode_cachep, inode); |
| 110 | } | 114 | } |
| 111 | 115 | ||
| 112 | void fuse_send_forget(struct fuse_conn *fc, struct fuse_req *req, | ||
| 113 | u64 nodeid, u64 nlookup) | ||
| 114 | { | ||
| 115 | struct fuse_forget_in *inarg = &req->misc.forget_in; | ||
| 116 | inarg->nlookup = nlookup; | ||
| 117 | req->in.h.opcode = FUSE_FORGET; | ||
| 118 | req->in.h.nodeid = nodeid; | ||
| 119 | req->in.numargs = 1; | ||
| 120 | req->in.args[0].size = sizeof(struct fuse_forget_in); | ||
| 121 | req->in.args[0].value = inarg; | ||
| 122 | fuse_request_send_noreply(fc, req); | ||
| 123 | } | ||
| 124 | |||
| 125 | static void fuse_evict_inode(struct inode *inode) | 116 | static void fuse_evict_inode(struct inode *inode) |
| 126 | { | 117 | { |
| 127 | truncate_inode_pages(&inode->i_data, 0); | 118 | truncate_inode_pages(&inode->i_data, 0); |
| @@ -129,8 +120,8 @@ static void fuse_evict_inode(struct inode *inode) | |||
| 129 | if (inode->i_sb->s_flags & MS_ACTIVE) { | 120 | if (inode->i_sb->s_flags & MS_ACTIVE) { |
| 130 | struct fuse_conn *fc = get_fuse_conn(inode); | 121 | struct fuse_conn *fc = get_fuse_conn(inode); |
| 131 | struct fuse_inode *fi = get_fuse_inode(inode); | 122 | struct fuse_inode *fi = get_fuse_inode(inode); |
| 132 | fuse_send_forget(fc, fi->forget_req, fi->nodeid, fi->nlookup); | 123 | fuse_queue_forget(fc, fi->forget, fi->nodeid, fi->nlookup); |
| 133 | fi->forget_req = NULL; | 124 | fi->forget = NULL; |
| 134 | } | 125 | } |
| 135 | } | 126 | } |
| 136 | 127 | ||
| @@ -534,6 +525,7 @@ void fuse_conn_init(struct fuse_conn *fc) | |||
| 534 | INIT_LIST_HEAD(&fc->interrupts); | 525 | INIT_LIST_HEAD(&fc->interrupts); |
| 535 | INIT_LIST_HEAD(&fc->bg_queue); | 526 | INIT_LIST_HEAD(&fc->bg_queue); |
| 536 | INIT_LIST_HEAD(&fc->entry); | 527 | INIT_LIST_HEAD(&fc->entry); |
| 528 | fc->forget_list_tail = &fc->forget_list_head; | ||
| 537 | atomic_set(&fc->num_waiting, 0); | 529 | atomic_set(&fc->num_waiting, 0); |
| 538 | fc->max_background = FUSE_DEFAULT_MAX_BACKGROUND; | 530 | fc->max_background = FUSE_DEFAULT_MAX_BACKGROUND; |
| 539 | fc->congestion_threshold = FUSE_DEFAULT_CONGESTION_THRESHOLD; | 531 | fc->congestion_threshold = FUSE_DEFAULT_CONGESTION_THRESHOLD; |
