aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorMiklos Szeredi <miklos@szeredi.hu>2005-09-09 16:10:31 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2005-09-09 17:03:45 -0400
commit1e9a4ed9396e9c31139721b639550ffb1df17065 (patch)
tree213566cf1294f5dd8f6ff62ceb3557b5f5b6c59c /fs
parentb6aeadeda22a9aa322fdfcd3f4c69ccf0da5cbdd (diff)
[PATCH] FUSE - mount options
This patch adds miscellaneous mount options to the FUSE filesystem. The following mount options are added: o default_permissions: check permissions with generic_permission() o allow_other: allow other users to access files o allow_root: allow root to access files o kernel_cache: don't invalidate page cache on open 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')
-rw-r--r--fs/fuse/dev.c78
-rw-r--r--fs/fuse/dir.c35
-rw-r--r--fs/fuse/file.c2
-rw-r--r--fs/fuse/fuse_i.h45
-rw-r--r--fs/fuse/inode.c77
5 files changed, 170 insertions, 67 deletions
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index e8f3170946f1..ca6fc0e96d7c 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -26,7 +26,7 @@ static inline struct fuse_conn *fuse_get_conn(struct file *file)
26 struct fuse_conn *fc; 26 struct fuse_conn *fc;
27 spin_lock(&fuse_lock); 27 spin_lock(&fuse_lock);
28 fc = file->private_data; 28 fc = file->private_data;
29 if (fc && !fc->sb) 29 if (fc && !fc->mounted)
30 fc = NULL; 30 fc = NULL;
31 spin_unlock(&fuse_lock); 31 spin_unlock(&fuse_lock);
32 return fc; 32 return fc;
@@ -148,6 +148,17 @@ void fuse_put_request(struct fuse_conn *fc, struct fuse_req *req)
148 fuse_putback_request(fc, req); 148 fuse_putback_request(fc, req);
149} 149}
150 150
151void fuse_release_background(struct fuse_req *req)
152{
153 iput(req->inode);
154 iput(req->inode2);
155 if (req->file)
156 fput(req->file);
157 spin_lock(&fuse_lock);
158 list_del(&req->bg_entry);
159 spin_unlock(&fuse_lock);
160}
161
151/* 162/*
152 * This function is called when a request is finished. Either a reply 163 * This function is called when a request is finished. Either a reply
153 * has arrived or it was interrupted (and not yet sent) or some error 164 * has arrived or it was interrupted (and not yet sent) or some error
@@ -166,12 +177,10 @@ static void request_end(struct fuse_conn *fc, struct fuse_req *req)
166 putback = atomic_dec_and_test(&req->count); 177 putback = atomic_dec_and_test(&req->count);
167 spin_unlock(&fuse_lock); 178 spin_unlock(&fuse_lock);
168 if (req->background) { 179 if (req->background) {
169 if (req->inode) 180 down_read(&fc->sbput_sem);
170 iput(req->inode); 181 if (fc->mounted)
171 if (req->inode2) 182 fuse_release_background(req);
172 iput(req->inode2); 183 up_read(&fc->sbput_sem);
173 if (req->file)
174 fput(req->file);
175 } 184 }
176 wake_up(&req->waitq); 185 wake_up(&req->waitq);
177 if (req->in.h.opcode == FUSE_INIT) { 186 if (req->in.h.opcode == FUSE_INIT) {
@@ -191,11 +200,39 @@ static void request_end(struct fuse_conn *fc, struct fuse_req *req)
191 fuse_putback_request(fc, req); 200 fuse_putback_request(fc, req);
192} 201}
193 202
194static void background_request(struct fuse_req *req) 203/*
204 * Unfortunately request interruption not just solves the deadlock
205 * problem, it causes problems too. These stem from the fact, that an
206 * interrupted request is continued to be processed in userspace,
207 * while all the locks and object references (inode and file) held
208 * during the operation are released.
209 *
210 * To release the locks is exactly why there's a need to interrupt the
211 * request, so there's not a lot that can be done about this, except
212 * introduce additional locking in userspace.
213 *
214 * More important is to keep inode and file references until userspace
215 * has replied, otherwise FORGET and RELEASE could be sent while the
216 * inode/file is still used by the filesystem.
217 *
218 * For this reason the concept of "background" request is introduced.
219 * An interrupted request is backgrounded if it has been already sent
220 * to userspace. Backgrounding involves getting an extra reference to
221 * inode(s) or file used in the request, and adding the request to
222 * fc->background list. When a reply is received for a background
223 * request, the object references are released, and the request is
224 * removed from the list. If the filesystem is unmounted while there
225 * are still background requests, the list is walked and references
226 * are released as if a reply was received.
227 *
228 * There's one more use for a background request. The RELEASE message is
229 * always sent as background, since it doesn't return an error or
230 * data.
231 */
232static void background_request(struct fuse_conn *fc, struct fuse_req *req)
195{ 233{
196 /* Need to get hold of the inode(s) and/or file used in the
197 request, so FORGET and RELEASE are not sent too early */
198 req->background = 1; 234 req->background = 1;
235 list_add(&req->bg_entry, &fc->background);
199 if (req->inode) 236 if (req->inode)
200 req->inode = igrab(req->inode); 237 req->inode = igrab(req->inode);
201 if (req->inode2) 238 if (req->inode2)
@@ -215,7 +252,8 @@ static int request_wait_answer_nonint(struct fuse_req *req)
215} 252}
216 253
217/* Called with fuse_lock held. Releases, and then reacquires it. */ 254/* Called with fuse_lock held. Releases, and then reacquires it. */
218static void request_wait_answer(struct fuse_req *req, int interruptible) 255static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req,
256 int interruptible)
219{ 257{
220 int intr; 258 int intr;
221 259
@@ -255,7 +293,7 @@ static void request_wait_answer(struct fuse_req *req, int interruptible)
255 list_del(&req->list); 293 list_del(&req->list);
256 __fuse_put_request(req); 294 __fuse_put_request(req);
257 } else if (!req->finished && req->sent) 295 } else if (!req->finished && req->sent)
258 background_request(req); 296 background_request(fc, req);
259} 297}
260 298
261static unsigned len_args(unsigned numargs, struct fuse_arg *args) 299static unsigned len_args(unsigned numargs, struct fuse_arg *args)
@@ -297,7 +335,7 @@ static void request_send_wait(struct fuse_conn *fc, struct fuse_req *req,
297{ 335{
298 req->isreply = 1; 336 req->isreply = 1;
299 spin_lock(&fuse_lock); 337 spin_lock(&fuse_lock);
300 if (!fc->file) 338 if (!fc->connected)
301 req->out.h.error = -ENOTCONN; 339 req->out.h.error = -ENOTCONN;
302 else if (fc->conn_error) 340 else if (fc->conn_error)
303 req->out.h.error = -ECONNREFUSED; 341 req->out.h.error = -ECONNREFUSED;
@@ -307,7 +345,7 @@ static void request_send_wait(struct fuse_conn *fc, struct fuse_req *req,
307 after request_end() */ 345 after request_end() */
308 __fuse_get_request(req); 346 __fuse_get_request(req);
309 347
310 request_wait_answer(req, interruptible); 348 request_wait_answer(fc, req, interruptible);
311 } 349 }
312 spin_unlock(&fuse_lock); 350 spin_unlock(&fuse_lock);
313} 351}
@@ -330,7 +368,7 @@ void request_send_nonint(struct fuse_conn *fc, struct fuse_req *req)
330static void request_send_nowait(struct fuse_conn *fc, struct fuse_req *req) 368static void request_send_nowait(struct fuse_conn *fc, struct fuse_req *req)
331{ 369{
332 spin_lock(&fuse_lock); 370 spin_lock(&fuse_lock);
333 if (fc->file) { 371 if (fc->connected) {
334 queue_request(fc, req); 372 queue_request(fc, req);
335 spin_unlock(&fuse_lock); 373 spin_unlock(&fuse_lock);
336 } else { 374 } else {
@@ -348,7 +386,9 @@ void request_send_noreply(struct fuse_conn *fc, struct fuse_req *req)
348void request_send_background(struct fuse_conn *fc, struct fuse_req *req) 386void request_send_background(struct fuse_conn *fc, struct fuse_req *req)
349{ 387{
350 req->isreply = 1; 388 req->isreply = 1;
351 background_request(req); 389 spin_lock(&fuse_lock);
390 background_request(fc, req);
391 spin_unlock(&fuse_lock);
352 request_send_nowait(fc, req); 392 request_send_nowait(fc, req);
353} 393}
354 394
@@ -583,7 +623,7 @@ static void request_wait(struct fuse_conn *fc)
583 DECLARE_WAITQUEUE(wait, current); 623 DECLARE_WAITQUEUE(wait, current);
584 624
585 add_wait_queue_exclusive(&fc->waitq, &wait); 625 add_wait_queue_exclusive(&fc->waitq, &wait);
586 while (fc->sb && list_empty(&fc->pending)) { 626 while (fc->mounted && list_empty(&fc->pending)) {
587 set_current_state(TASK_INTERRUPTIBLE); 627 set_current_state(TASK_INTERRUPTIBLE);
588 if (signal_pending(current)) 628 if (signal_pending(current))
589 break; 629 break;
@@ -622,7 +662,7 @@ static ssize_t fuse_dev_readv(struct file *file, const struct iovec *iov,
622 goto err_unlock; 662 goto err_unlock;
623 request_wait(fc); 663 request_wait(fc);
624 err = -ENODEV; 664 err = -ENODEV;
625 if (!fc->sb) 665 if (!fc->mounted)
626 goto err_unlock; 666 goto err_unlock;
627 err = -ERESTARTSYS; 667 err = -ERESTARTSYS;
628 if (list_empty(&fc->pending)) 668 if (list_empty(&fc->pending))
@@ -839,7 +879,7 @@ static int fuse_dev_release(struct inode *inode, struct file *file)
839 spin_lock(&fuse_lock); 879 spin_lock(&fuse_lock);
840 fc = file->private_data; 880 fc = file->private_data;
841 if (fc) { 881 if (fc) {
842 fc->file = NULL; 882 fc->connected = 0;
843 end_requests(fc, &fc->pending); 883 end_requests(fc, &fc->pending);
844 end_requests(fc, &fc->processing); 884 end_requests(fc, &fc->processing);
845 fuse_release_conn(fc); 885 fuse_release_conn(fc);
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index 8adc1eed164b..0950455914dd 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -418,7 +418,8 @@ static int fuse_revalidate(struct dentry *entry)
418 struct fuse_conn *fc = get_fuse_conn(inode); 418 struct fuse_conn *fc = get_fuse_conn(inode);
419 419
420 if (get_node_id(inode) == FUSE_ROOT_ID) { 420 if (get_node_id(inode) == FUSE_ROOT_ID) {
421 if (current->fsuid != fc->user_id) 421 if (!(fc->flags & FUSE_ALLOW_OTHER) &&
422 current->fsuid != fc->user_id)
422 return -EACCES; 423 return -EACCES;
423 } else if (time_before_eq(jiffies, fi->i_time)) 424 } else if (time_before_eq(jiffies, fi->i_time))
424 return 0; 425 return 0;
@@ -430,9 +431,31 @@ static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd)
430{ 431{
431 struct fuse_conn *fc = get_fuse_conn(inode); 432 struct fuse_conn *fc = get_fuse_conn(inode);
432 433
433 if (current->fsuid != fc->user_id) 434 if (!(fc->flags & FUSE_ALLOW_OTHER) && current->fsuid != fc->user_id)
434 return -EACCES; 435 return -EACCES;
435 else { 436 else if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
437 int err = generic_permission(inode, mask, NULL);
438
439 /* If permission is denied, try to refresh file
440 attributes. This is also needed, because the root
441 node will at first have no permissions */
442 if (err == -EACCES) {
443 err = fuse_do_getattr(inode);
444 if (!err)
445 err = generic_permission(inode, mask, NULL);
446 }
447
448 /* FIXME: Need some mechanism to revoke permissions:
449 currently if the filesystem suddenly changes the
450 file mode, we will not be informed about it, and
451 continue to allow access to the file/directory.
452
453 This is actually not so grave, since the user can
454 simply keep access to the file/directory anyway by
455 keeping it open... */
456
457 return err;
458 } else {
436 int mode = inode->i_mode; 459 int mode = inode->i_mode;
437 if ((mask & MAY_WRITE) && IS_RDONLY(inode) && 460 if ((mask & MAY_WRITE) && IS_RDONLY(inode) &&
438 (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode))) 461 (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)))
@@ -636,6 +659,12 @@ static int fuse_setattr(struct dentry *entry, struct iattr *attr)
636 int err; 659 int err;
637 int is_truncate = 0; 660 int is_truncate = 0;
638 661
662 if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
663 err = inode_change_ok(inode, attr);
664 if (err)
665 return err;
666 }
667
639 if (attr->ia_valid & ATTR_SIZE) { 668 if (attr->ia_valid & ATTR_SIZE) {
640 unsigned long limit; 669 unsigned long limit;
641 is_truncate = 1; 670 is_truncate = 1;
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index de8c9c702461..96ea302db184 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -70,7 +70,7 @@ static int fuse_open(struct inode *inode, struct file *file)
70 else 70 else
71 request_send(fc, req); 71 request_send(fc, req);
72 err = req->out.h.error; 72 err = req->out.h.error;
73 if (!err) 73 if (!err && !(fc->flags & FUSE_KERNEL_CACHE))
74 invalidate_inode_pages(inode->i_mapping); 74 invalidate_inode_pages(inode->i_mapping);
75 if (err) { 75 if (err) {
76 fuse_request_free(ff->release_req); 76 fuse_request_free(ff->release_req);
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index b4aa8f7bc2c1..c8e6c87496e0 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -21,6 +21,19 @@
21/** If more requests are outstanding, then the operation will block */ 21/** If more requests are outstanding, then the operation will block */
22#define FUSE_MAX_OUTSTANDING 10 22#define FUSE_MAX_OUTSTANDING 10
23 23
24/** If the FUSE_DEFAULT_PERMISSIONS flag is given, the filesystem
25 module will check permissions based on the file mode. Otherwise no
26 permission checking is done in the kernel */
27#define FUSE_DEFAULT_PERMISSIONS (1 << 0)
28
29/** If the FUSE_ALLOW_OTHER flag is given, then not only the user
30 doing the mount will be allowed to access the filesystem */
31#define FUSE_ALLOW_OTHER (1 << 1)
32
33/** If the FUSE_KERNEL_CACHE flag is given, then cached data will not
34 be flushed on open */
35#define FUSE_KERNEL_CACHE (1 << 2)
36
24/** FUSE inode */ 37/** FUSE inode */
25struct fuse_inode { 38struct fuse_inode {
26 /** Inode data */ 39 /** Inode data */
@@ -109,6 +122,9 @@ struct fuse_req {
109 lists in fuse_conn */ 122 lists in fuse_conn */
110 struct list_head list; 123 struct list_head list;
111 124
125 /** Entry on the background list */
126 struct list_head bg_entry;
127
112 /** refcount */ 128 /** refcount */
113 atomic_t count; 129 atomic_t count;
114 130
@@ -176,15 +192,15 @@ struct fuse_req {
176 * unmounted. 192 * unmounted.
177 */ 193 */
178struct fuse_conn { 194struct fuse_conn {
179 /** The superblock of the mounted filesystem */ 195 /** Reference count */
180 struct super_block *sb; 196 int count;
181
182 /** The opened client device */
183 struct file *file;
184 197
185 /** The user id for this mount */ 198 /** The user id for this mount */
186 uid_t user_id; 199 uid_t user_id;
187 200
201 /** The fuse mount flags for this mount */
202 unsigned flags;
203
188 /** Readers of the connection are waiting on this */ 204 /** Readers of the connection are waiting on this */
189 wait_queue_head_t waitq; 205 wait_queue_head_t waitq;
190 206
@@ -194,6 +210,10 @@ struct fuse_conn {
194 /** The list of requests being processed */ 210 /** The list of requests being processed */
195 struct list_head processing; 211 struct list_head processing;
196 212
213 /** Requests put in the background (RELEASE or any other
214 interrupted request) */
215 struct list_head background;
216
197 /** Controls the maximum number of outstanding requests */ 217 /** Controls the maximum number of outstanding requests */
198 struct semaphore outstanding_sem; 218 struct semaphore outstanding_sem;
199 219
@@ -201,12 +221,21 @@ struct fuse_conn {
201 outstanding_sem would go negative */ 221 outstanding_sem would go negative */
202 unsigned outstanding_debt; 222 unsigned outstanding_debt;
203 223
224 /** RW semaphore for exclusion with fuse_put_super() */
225 struct rw_semaphore sbput_sem;
226
204 /** The list of unused requests */ 227 /** The list of unused requests */
205 struct list_head unused_list; 228 struct list_head unused_list;
206 229
207 /** The next unique request id */ 230 /** The next unique request id */
208 u64 reqctr; 231 u64 reqctr;
209 232
233 /** Mount is active */
234 unsigned mounted : 1;
235
236 /** Connection established */
237 unsigned connected : 1;
238
210 /** Connection failed (version mismatch) */ 239 /** Connection failed (version mismatch) */
211 unsigned conn_error : 1; 240 unsigned conn_error : 1;
212 241
@@ -261,6 +290,7 @@ extern struct file_operations fuse_dev_operations;
261 * - the private_data field of the device file 290 * - the private_data field of the device file
262 * - the s_fs_info field of the super block 291 * - the s_fs_info field of the super block
263 * - unused_list, pending, processing lists in fuse_conn 292 * - unused_list, pending, processing lists in fuse_conn
293 * - background list in fuse_conn
264 * - the unique request ID counter reqctr in fuse_conn 294 * - the unique request ID counter reqctr in fuse_conn
265 * - the sb (super_block) field in fuse_conn 295 * - the sb (super_block) field in fuse_conn
266 * - the file (device file) field in fuse_conn 296 * - the file (device file) field in fuse_conn
@@ -372,6 +402,11 @@ void request_send_noreply(struct fuse_conn *fc, struct fuse_req *req);
372void request_send_background(struct fuse_conn *fc, struct fuse_req *req); 402void request_send_background(struct fuse_conn *fc, struct fuse_req *req);
373 403
374/** 404/**
405 * Release inodes and file assiciated with background request
406 */
407void fuse_release_background(struct fuse_req *req);
408
409/**
375 * Get the attributes of a file 410 * Get the attributes of a file
376 */ 411 */
377int fuse_do_getattr(struct inode *inode); 412int fuse_do_getattr(struct inode *inode);
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index f229d6962643..458c62ca0fec 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -15,7 +15,6 @@
15#include <linux/seq_file.h> 15#include <linux/seq_file.h>
16#include <linux/init.h> 16#include <linux/init.h>
17#include <linux/module.h> 17#include <linux/module.h>
18#include <linux/moduleparam.h>
19#include <linux/parser.h> 18#include <linux/parser.h>
20#include <linux/statfs.h> 19#include <linux/statfs.h>
21 20
@@ -25,11 +24,6 @@ MODULE_LICENSE("GPL");
25 24
26spinlock_t fuse_lock; 25spinlock_t fuse_lock;
27static kmem_cache_t *fuse_inode_cachep; 26static kmem_cache_t *fuse_inode_cachep;
28static int mount_count;
29
30static int mount_max = 1000;
31module_param(mount_max, int, 0644);
32MODULE_PARM_DESC(mount_max, "Maximum number of FUSE mounts allowed, if -1 then unlimited (default: 1000)");
33 27
34#define FUSE_SUPER_MAGIC 0x65735546 28#define FUSE_SUPER_MAGIC 0x65735546
35 29
@@ -37,6 +31,7 @@ struct fuse_mount_data {
37 int fd; 31 int fd;
38 unsigned rootmode; 32 unsigned rootmode;
39 unsigned user_id; 33 unsigned user_id;
34 unsigned flags;
40}; 35};
41 36
42static struct inode *fuse_alloc_inode(struct super_block *sb) 37static struct inode *fuse_alloc_inode(struct super_block *sb)
@@ -89,8 +84,8 @@ void fuse_send_forget(struct fuse_conn *fc, struct fuse_req *req,
89 84
90static void fuse_clear_inode(struct inode *inode) 85static void fuse_clear_inode(struct inode *inode)
91{ 86{
92 struct fuse_conn *fc = get_fuse_conn(inode); 87 if (inode->i_sb->s_flags & MS_ACTIVE) {
93 if (fc) { 88 struct fuse_conn *fc = get_fuse_conn(inode);
94 struct fuse_inode *fi = get_fuse_inode(inode); 89 struct fuse_inode *fi = get_fuse_inode(inode);
95 fuse_send_forget(fc, fi->forget_req, fi->nodeid, fi->nlookup); 90 fuse_send_forget(fc, fi->forget_req, fi->nodeid, fi->nlookup);
96 fi->forget_req = NULL; 91 fi->forget_req = NULL;
@@ -195,14 +190,19 @@ static void fuse_put_super(struct super_block *sb)
195{ 190{
196 struct fuse_conn *fc = get_fuse_conn_super(sb); 191 struct fuse_conn *fc = get_fuse_conn_super(sb);
197 192
193 down_write(&fc->sbput_sem);
194 while (!list_empty(&fc->background))
195 fuse_release_background(list_entry(fc->background.next,
196 struct fuse_req, bg_entry));
197
198 spin_lock(&fuse_lock); 198 spin_lock(&fuse_lock);
199 mount_count --; 199 fc->mounted = 0;
200 fc->sb = NULL;
201 fc->user_id = 0; 200 fc->user_id = 0;
201 fc->flags = 0;
202 /* Flush all readers on this fs */ 202 /* Flush all readers on this fs */
203 wake_up_all(&fc->waitq); 203 wake_up_all(&fc->waitq);
204 up_write(&fc->sbput_sem);
204 fuse_release_conn(fc); 205 fuse_release_conn(fc);
205 *get_fuse_conn_super_p(sb) = NULL;
206 spin_unlock(&fuse_lock); 206 spin_unlock(&fuse_lock);
207} 207}
208 208
@@ -249,7 +249,6 @@ enum {
249 OPT_USER_ID, 249 OPT_USER_ID,
250 OPT_DEFAULT_PERMISSIONS, 250 OPT_DEFAULT_PERMISSIONS,
251 OPT_ALLOW_OTHER, 251 OPT_ALLOW_OTHER,
252 OPT_ALLOW_ROOT,
253 OPT_KERNEL_CACHE, 252 OPT_KERNEL_CACHE,
254 OPT_ERR 253 OPT_ERR
255}; 254};
@@ -260,7 +259,6 @@ static match_table_t tokens = {
260 {OPT_USER_ID, "user_id=%u"}, 259 {OPT_USER_ID, "user_id=%u"},
261 {OPT_DEFAULT_PERMISSIONS, "default_permissions"}, 260 {OPT_DEFAULT_PERMISSIONS, "default_permissions"},
262 {OPT_ALLOW_OTHER, "allow_other"}, 261 {OPT_ALLOW_OTHER, "allow_other"},
263 {OPT_ALLOW_ROOT, "allow_root"},
264 {OPT_KERNEL_CACHE, "kernel_cache"}, 262 {OPT_KERNEL_CACHE, "kernel_cache"},
265 {OPT_ERR, NULL} 263 {OPT_ERR, NULL}
266}; 264};
@@ -298,6 +296,18 @@ static int parse_fuse_opt(char *opt, struct fuse_mount_data *d)
298 d->user_id = value; 296 d->user_id = value;
299 break; 297 break;
300 298
299 case OPT_DEFAULT_PERMISSIONS:
300 d->flags |= FUSE_DEFAULT_PERMISSIONS;
301 break;
302
303 case OPT_ALLOW_OTHER:
304 d->flags |= FUSE_ALLOW_OTHER;
305 break;
306
307 case OPT_KERNEL_CACHE:
308 d->flags |= FUSE_KERNEL_CACHE;
309 break;
310
301 default: 311 default:
302 return 0; 312 return 0;
303 } 313 }
@@ -313,6 +323,12 @@ static int fuse_show_options(struct seq_file *m, struct vfsmount *mnt)
313 struct fuse_conn *fc = get_fuse_conn_super(mnt->mnt_sb); 323 struct fuse_conn *fc = get_fuse_conn_super(mnt->mnt_sb);
314 324
315 seq_printf(m, ",user_id=%u", fc->user_id); 325 seq_printf(m, ",user_id=%u", fc->user_id);
326 if (fc->flags & FUSE_DEFAULT_PERMISSIONS)
327 seq_puts(m, ",default_permissions");
328 if (fc->flags & FUSE_ALLOW_OTHER)
329 seq_puts(m, ",allow_other");
330 if (fc->flags & FUSE_KERNEL_CACHE)
331 seq_puts(m, ",kernel_cache");
316 return 0; 332 return 0;
317} 333}
318 334
@@ -330,7 +346,8 @@ static void free_conn(struct fuse_conn *fc)
330/* Must be called with the fuse lock held */ 346/* Must be called with the fuse lock held */
331void fuse_release_conn(struct fuse_conn *fc) 347void fuse_release_conn(struct fuse_conn *fc)
332{ 348{
333 if (!fc->sb && !fc->file) 349 fc->count--;
350 if (!fc->count)
334 free_conn(fc); 351 free_conn(fc);
335} 352}
336 353
@@ -342,14 +359,13 @@ static struct fuse_conn *new_conn(void)
342 if (fc != NULL) { 359 if (fc != NULL) {
343 int i; 360 int i;
344 memset(fc, 0, sizeof(*fc)); 361 memset(fc, 0, sizeof(*fc));
345 fc->sb = NULL;
346 fc->file = NULL;
347 fc->user_id = 0;
348 init_waitqueue_head(&fc->waitq); 362 init_waitqueue_head(&fc->waitq);
349 INIT_LIST_HEAD(&fc->pending); 363 INIT_LIST_HEAD(&fc->pending);
350 INIT_LIST_HEAD(&fc->processing); 364 INIT_LIST_HEAD(&fc->processing);
351 INIT_LIST_HEAD(&fc->unused_list); 365 INIT_LIST_HEAD(&fc->unused_list);
366 INIT_LIST_HEAD(&fc->background);
352 sema_init(&fc->outstanding_sem, 0); 367 sema_init(&fc->outstanding_sem, 0);
368 init_rwsem(&fc->sbput_sem);
353 for (i = 0; i < FUSE_MAX_OUTSTANDING; i++) { 369 for (i = 0; i < FUSE_MAX_OUTSTANDING; i++) {
354 struct fuse_req *req = fuse_request_alloc(); 370 struct fuse_req *req = fuse_request_alloc();
355 if (!req) { 371 if (!req) {
@@ -380,8 +396,10 @@ static struct fuse_conn *get_conn(struct file *file, struct super_block *sb)
380 fc = ERR_PTR(-EINVAL); 396 fc = ERR_PTR(-EINVAL);
381 } else { 397 } else {
382 file->private_data = fc; 398 file->private_data = fc;
383 fc->sb = sb; 399 *get_fuse_conn_super_p(sb) = fc;
384 fc->file = file; 400 fc->mounted = 1;
401 fc->connected = 1;
402 fc->count = 2;
385 } 403 }
386 spin_unlock(&fuse_lock); 404 spin_unlock(&fuse_lock);
387 return fc; 405 return fc;
@@ -407,17 +425,6 @@ static struct super_operations fuse_super_operations = {
407 .show_options = fuse_show_options, 425 .show_options = fuse_show_options,
408}; 426};
409 427
410static int inc_mount_count(void)
411{
412 int success = 0;
413 spin_lock(&fuse_lock);
414 mount_count ++;
415 if (mount_max == -1 || mount_count <= mount_max)
416 success = 1;
417 spin_unlock(&fuse_lock);
418 return success;
419}
420
421static int fuse_fill_super(struct super_block *sb, void *data, int silent) 428static int fuse_fill_super(struct super_block *sb, void *data, int silent)
422{ 429{
423 struct fuse_conn *fc; 430 struct fuse_conn *fc;
@@ -444,14 +451,9 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)
444 if (IS_ERR(fc)) 451 if (IS_ERR(fc))
445 return PTR_ERR(fc); 452 return PTR_ERR(fc);
446 453
454 fc->flags = d.flags;
447 fc->user_id = d.user_id; 455 fc->user_id = d.user_id;
448 456
449 *get_fuse_conn_super_p(sb) = fc;
450
451 err = -ENFILE;
452 if (!inc_mount_count() && current->uid != 0)
453 goto err;
454
455 err = -ENOMEM; 457 err = -ENOMEM;
456 root = get_root_inode(sb, d.rootmode); 458 root = get_root_inode(sb, d.rootmode);
457 if (root == NULL) 459 if (root == NULL)
@@ -467,11 +469,8 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)
467 469
468 err: 470 err:
469 spin_lock(&fuse_lock); 471 spin_lock(&fuse_lock);
470 mount_count --;
471 fc->sb = NULL;
472 fuse_release_conn(fc); 472 fuse_release_conn(fc);
473 spin_unlock(&fuse_lock); 473 spin_unlock(&fuse_lock);
474 *get_fuse_conn_super_p(sb) = NULL;
475 return err; 474 return err;
476} 475}
477 476