aboutsummaryrefslogtreecommitdiffstats
path: root/fs/fuse/dev.c
diff options
context:
space:
mode:
authorMiklos Szeredi <miklos@szeredi.hu>2006-06-25 08:48:52 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-06-25 13:01:19 -0400
commit33649c91a3df57c1090a657637d44b896de367e7 (patch)
tree1ee4871a65f2b37a931c796463eb39737a32cbaa /fs/fuse/dev.c
parent7142125937e1482ad3ae4366594c6586153dfc86 (diff)
[PATCH] fuse: ensure FLUSH reaches userspace
All POSIX locks owned by the current task are removed on close(). If the FLUSH request resulting initiated by close() fails to reach userspace, there might be locks remaining, which cannot be removed. The only reason it could fail, is if allocating the request fails. In this case use the request reserved for RELEASE, or if that is currently used by another FLUSH, wait for it to become available. Signed-off-by: Miklos Szeredi <miklos@szeredi.hu> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'fs/fuse/dev.c')
-rw-r--r--fs/fuse/dev.c88
1 files changed, 84 insertions, 4 deletions
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index fe3adf589174..ae26f37e53a1 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -76,6 +76,13 @@ static void __fuse_put_request(struct fuse_req *req)
76 atomic_dec(&req->count); 76 atomic_dec(&req->count);
77} 77}
78 78
79static void fuse_req_init_context(struct fuse_req *req)
80{
81 req->in.h.uid = current->fsuid;
82 req->in.h.gid = current->fsgid;
83 req->in.h.pid = current->pid;
84}
85
79struct fuse_req *fuse_get_req(struct fuse_conn *fc) 86struct fuse_req *fuse_get_req(struct fuse_conn *fc)
80{ 87{
81 struct fuse_req *req; 88 struct fuse_req *req;
@@ -100,9 +107,7 @@ struct fuse_req *fuse_get_req(struct fuse_conn *fc)
100 if (!req) 107 if (!req)
101 goto out; 108 goto out;
102 109
103 req->in.h.uid = current->fsuid; 110 fuse_req_init_context(req);
104 req->in.h.gid = current->fsgid;
105 req->in.h.pid = current->pid;
106 req->waiting = 1; 111 req->waiting = 1;
107 return req; 112 return req;
108 113
@@ -111,12 +116,87 @@ struct fuse_req *fuse_get_req(struct fuse_conn *fc)
111 return ERR_PTR(err); 116 return ERR_PTR(err);
112} 117}
113 118
119/*
120 * Return request in fuse_file->reserved_req. However that may
121 * currently be in use. If that is the case, wait for it to become
122 * available.
123 */
124static struct fuse_req *get_reserved_req(struct fuse_conn *fc,
125 struct file *file)
126{
127 struct fuse_req *req = NULL;
128 struct fuse_file *ff = file->private_data;
129
130 do {
131 wait_event(fc->blocked_waitq, ff->reserved_req);
132 spin_lock(&fc->lock);
133 if (ff->reserved_req) {
134 req = ff->reserved_req;
135 ff->reserved_req = NULL;
136 get_file(file);
137 req->stolen_file = file;
138 }
139 spin_unlock(&fc->lock);
140 } while (!req);
141
142 return req;
143}
144
145/*
146 * Put stolen request back into fuse_file->reserved_req
147 */
148static void put_reserved_req(struct fuse_conn *fc, struct fuse_req *req)
149{
150 struct file *file = req->stolen_file;
151 struct fuse_file *ff = file->private_data;
152
153 spin_lock(&fc->lock);
154 fuse_request_init(req);
155 BUG_ON(ff->reserved_req);
156 ff->reserved_req = req;
157 wake_up(&fc->blocked_waitq);
158 spin_unlock(&fc->lock);
159 fput(file);
160}
161
162/*
163 * Gets a requests for a file operation, always succeeds
164 *
165 * This is used for sending the FLUSH request, which must get to
166 * userspace, due to POSIX locks which may need to be unlocked.
167 *
168 * If allocation fails due to OOM, use the reserved request in
169 * fuse_file.
170 *
171 * This is very unlikely to deadlock accidentally, since the
172 * filesystem should not have it's own file open. If deadlock is
173 * intentional, it can still be broken by "aborting" the filesystem.
174 */
175struct fuse_req *fuse_get_req_nofail(struct fuse_conn *fc, struct file *file)
176{
177 struct fuse_req *req;
178
179 atomic_inc(&fc->num_waiting);
180 wait_event(fc->blocked_waitq, !fc->blocked);
181 req = fuse_request_alloc();
182 if (!req)
183 req = get_reserved_req(fc, file);
184
185 fuse_req_init_context(req);
186 req->waiting = 1;
187 return req;
188}
189
114void fuse_put_request(struct fuse_conn *fc, struct fuse_req *req) 190void fuse_put_request(struct fuse_conn *fc, struct fuse_req *req)
115{ 191{
116 if (atomic_dec_and_test(&req->count)) { 192 if (atomic_dec_and_test(&req->count)) {
117 if (req->waiting) 193 if (req->waiting)
118 atomic_dec(&fc->num_waiting); 194 atomic_dec(&fc->num_waiting);
119 fuse_request_free(req); 195
196 if (req->stolen_file)
197 put_reserved_req(fc, req);
198 else
199 fuse_request_free(req);
120 } 200 }
121} 201}
122 202