aboutsummaryrefslogtreecommitdiffstats
path: root/fs/fuse/dev.c
diff options
context:
space:
mode:
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