aboutsummaryrefslogtreecommitdiffstats
path: root/fs/fuse/dev.c
diff options
context:
space:
mode:
authorMiklos Szeredi <mszeredi@suse.cz>2010-12-07 14:16:56 -0500
committerMiklos Szeredi <mszeredi@suse.cz>2010-12-07 14:16:56 -0500
commit07e77dca8a1f17a724a9b7449f0ca02e70e9d057 (patch)
tree69186be641145fd997ce15e17a22598d9a264119 /fs/fuse/dev.c
parent8ac835056ca39b242d98332f46e4d65428a8b7db (diff)
fuse: separate queue for FORGET requests
Terje Malmedal reports that a fuse filesystem with 32 million inodes on a machine with lots of memory can go unresponsive for up to 30 minutes when all those inodes are evicted from the icache. The reason is that FORGET messages, sent when the inode is evicted, are queued up together with regular filesystem requests, and while the huge queue of FORGET messages are processed no other filesystem operation can proceed. Since a full fuse request structure is allocated for each inode, these take up quite a bit of memory as well. To solve these issues, create a slim 'fuse_forget_link' structure containing just the minimum of information required to send the FORGET request and chain these on a separate queue. When userspace is asking for a request make sure that FORGET and non-FORGET requests are selected fairly: for each 8 non-FORGET allow 16 FORGET requests. This will make sure FORGETs do not pile up, yet other requests are also allowed to proceed while the queued FORGETs are processed. Reported-by: Terje Malmedal <terje.malmedal@usit.uio.no> Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
Diffstat (limited to 'fs/fuse/dev.c')
-rw-r--r--fs/fuse/dev.c86
1 files changed, 77 insertions, 9 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
254void 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
254static void flush_bg_queue(struct fuse_conn *fc) 268static 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
441void 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
447void fuse_request_send_background(struct fuse_conn *fc, struct fuse_req *req) 455void 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
907static int forget_pending(struct fuse_conn *fc)
908{
909 return fc->forget_list_head.next != NULL;
910}
911
899static int request_pending(struct fuse_conn *fc) 912static 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
977static 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
988static 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/*