aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/fuse/dev.c88
-rw-r--r--fs/fuse/file.c13
-rw-r--r--fs/fuse/fuse_i.h12
3 files changed, 99 insertions, 14 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
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index d9a8289297c0..ce759414cff9 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -48,8 +48,8 @@ struct fuse_file *fuse_file_alloc(void)
48 struct fuse_file *ff; 48 struct fuse_file *ff;
49 ff = kmalloc(sizeof(struct fuse_file), GFP_KERNEL); 49 ff = kmalloc(sizeof(struct fuse_file), GFP_KERNEL);
50 if (ff) { 50 if (ff) {
51 ff->release_req = fuse_request_alloc(); 51 ff->reserved_req = fuse_request_alloc();
52 if (!ff->release_req) { 52 if (!ff->reserved_req) {
53 kfree(ff); 53 kfree(ff);
54 ff = NULL; 54 ff = NULL;
55 } 55 }
@@ -59,7 +59,7 @@ struct fuse_file *fuse_file_alloc(void)
59 59
60void fuse_file_free(struct fuse_file *ff) 60void fuse_file_free(struct fuse_file *ff)
61{ 61{
62 fuse_request_free(ff->release_req); 62 fuse_request_free(ff->reserved_req);
63 kfree(ff); 63 kfree(ff);
64} 64}
65 65
@@ -115,7 +115,7 @@ int fuse_open_common(struct inode *inode, struct file *file, int isdir)
115struct fuse_req *fuse_release_fill(struct fuse_file *ff, u64 nodeid, int flags, 115struct fuse_req *fuse_release_fill(struct fuse_file *ff, u64 nodeid, int flags,
116 int opcode) 116 int opcode)
117{ 117{
118 struct fuse_req *req = ff->release_req; 118 struct fuse_req *req = ff->reserved_req;
119 struct fuse_release_in *inarg = &req->misc.release_in; 119 struct fuse_release_in *inarg = &req->misc.release_in;
120 120
121 inarg->fh = ff->fh; 121 inarg->fh = ff->fh;
@@ -187,10 +187,7 @@ static int fuse_flush(struct file *file, fl_owner_t id)
187 if (fc->no_flush) 187 if (fc->no_flush)
188 return 0; 188 return 0;
189 189
190 req = fuse_get_req(fc); 190 req = fuse_get_req_nofail(fc, file);
191 if (IS_ERR(req))
192 return PTR_ERR(req);
193
194 memset(&inarg, 0, sizeof(inarg)); 191 memset(&inarg, 0, sizeof(inarg));
195 inarg.fh = ff->fh; 192 inarg.fh = ff->fh;
196 inarg.lock_owner = fuse_lock_owner_id(id); 193 inarg.lock_owner = fuse_lock_owner_id(id);
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index eb3166625ca9..f7c74516f3a6 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -65,7 +65,7 @@ struct fuse_inode {
65/** FUSE specific file data */ 65/** FUSE specific file data */
66struct fuse_file { 66struct fuse_file {
67 /** Request reserved for flush and release */ 67 /** Request reserved for flush and release */
68 struct fuse_req *release_req; 68 struct fuse_req *reserved_req;
69 69
70 /** File handle used by userspace */ 70 /** File handle used by userspace */
71 u64 fh; 71 u64 fh;
@@ -213,6 +213,9 @@ struct fuse_req {
213 213
214 /** Request completion callback */ 214 /** Request completion callback */
215 void (*end)(struct fuse_conn *, struct fuse_req *); 215 void (*end)(struct fuse_conn *, struct fuse_req *);
216
217 /** Request is stolen from fuse_file->reserved_req */
218 struct file *stolen_file;
216}; 219};
217 220
218/** 221/**
@@ -456,11 +459,16 @@ struct fuse_req *fuse_request_alloc(void);
456void fuse_request_free(struct fuse_req *req); 459void fuse_request_free(struct fuse_req *req);
457 460
458/** 461/**
459 * Reserve a preallocated request 462 * Get a request, may fail with -ENOMEM
460 */ 463 */
461struct fuse_req *fuse_get_req(struct fuse_conn *fc); 464struct fuse_req *fuse_get_req(struct fuse_conn *fc);
462 465
463/** 466/**
467 * Gets a requests for a file operation, always succeeds
468 */
469struct fuse_req *fuse_get_req_nofail(struct fuse_conn *fc, struct file *file);
470
471/**
464 * Decrement reference count of a request. If count goes to zero free 472 * Decrement reference count of a request. If count goes to zero free
465 * the request. 473 * the request.
466 */ 474 */