aboutsummaryrefslogtreecommitdiffstats
path: root/fs/fuse/inode.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/inode.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/inode.c')
-rw-r--r--fs/fuse/inode.c30
1 files changed, 11 insertions, 19 deletions
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
74struct fuse_forget_link *fuse_alloc_forget()
75{
76 return kzalloc(sizeof(struct fuse_forget_link), GFP_KERNEL);
77}
78
74static struct inode *fuse_alloc_inode(struct super_block *sb) 79static 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
112void 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
125static void fuse_evict_inode(struct inode *inode) 116static 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;