diff options
Diffstat (limited to 'fs/fuse/inode.c')
-rw-r--r-- | fs/fuse/inode.c | 58 |
1 files changed, 53 insertions, 5 deletions
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index ea6339c2b6a1..33fad334ba70 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c | |||
@@ -151,6 +151,8 @@ static void fuse_put_super(struct super_block *sb) | |||
151 | mount_count --; | 151 | mount_count --; |
152 | fc->sb = NULL; | 152 | fc->sb = NULL; |
153 | fc->user_id = 0; | 153 | fc->user_id = 0; |
154 | /* Flush all readers on this fs */ | ||
155 | wake_up_all(&fc->waitq); | ||
154 | fuse_release_conn(fc); | 156 | fuse_release_conn(fc); |
155 | *get_fuse_conn_super_p(sb) = NULL; | 157 | *get_fuse_conn_super_p(sb) = NULL; |
156 | spin_unlock(&fuse_lock); | 158 | spin_unlock(&fuse_lock); |
@@ -229,22 +231,51 @@ static int fuse_show_options(struct seq_file *m, struct vfsmount *mnt) | |||
229 | return 0; | 231 | return 0; |
230 | } | 232 | } |
231 | 233 | ||
232 | void fuse_release_conn(struct fuse_conn *fc) | 234 | static void free_conn(struct fuse_conn *fc) |
233 | { | 235 | { |
236 | while (!list_empty(&fc->unused_list)) { | ||
237 | struct fuse_req *req; | ||
238 | req = list_entry(fc->unused_list.next, struct fuse_req, list); | ||
239 | list_del(&req->list); | ||
240 | fuse_request_free(req); | ||
241 | } | ||
234 | kfree(fc); | 242 | kfree(fc); |
235 | } | 243 | } |
236 | 244 | ||
245 | /* Must be called with the fuse lock held */ | ||
246 | void fuse_release_conn(struct fuse_conn *fc) | ||
247 | { | ||
248 | if (!fc->sb && !fc->file) | ||
249 | free_conn(fc); | ||
250 | } | ||
251 | |||
237 | static struct fuse_conn *new_conn(void) | 252 | static struct fuse_conn *new_conn(void) |
238 | { | 253 | { |
239 | struct fuse_conn *fc; | 254 | struct fuse_conn *fc; |
240 | 255 | ||
241 | fc = kmalloc(sizeof(*fc), GFP_KERNEL); | 256 | fc = kmalloc(sizeof(*fc), GFP_KERNEL); |
242 | if (fc != NULL) { | 257 | if (fc != NULL) { |
258 | int i; | ||
243 | memset(fc, 0, sizeof(*fc)); | 259 | memset(fc, 0, sizeof(*fc)); |
244 | fc->sb = NULL; | 260 | fc->sb = NULL; |
261 | fc->file = NULL; | ||
245 | fc->user_id = 0; | 262 | fc->user_id = 0; |
263 | init_waitqueue_head(&fc->waitq); | ||
264 | INIT_LIST_HEAD(&fc->pending); | ||
265 | INIT_LIST_HEAD(&fc->processing); | ||
266 | INIT_LIST_HEAD(&fc->unused_list); | ||
267 | sema_init(&fc->outstanding_sem, 0); | ||
268 | for (i = 0; i < FUSE_MAX_OUTSTANDING; i++) { | ||
269 | struct fuse_req *req = fuse_request_alloc(); | ||
270 | if (!req) { | ||
271 | free_conn(fc); | ||
272 | return NULL; | ||
273 | } | ||
274 | list_add(&req->list, &fc->unused_list); | ||
275 | } | ||
246 | fc->bdi.ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE; | 276 | fc->bdi.ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE; |
247 | fc->bdi.unplug_io_fn = default_unplug_io_fn; | 277 | fc->bdi.unplug_io_fn = default_unplug_io_fn; |
278 | fc->reqctr = 0; | ||
248 | } | 279 | } |
249 | return fc; | 280 | return fc; |
250 | } | 281 | } |
@@ -253,11 +284,20 @@ static struct fuse_conn *get_conn(struct file *file, struct super_block *sb) | |||
253 | { | 284 | { |
254 | struct fuse_conn *fc; | 285 | struct fuse_conn *fc; |
255 | 286 | ||
287 | if (file->f_op != &fuse_dev_operations) | ||
288 | return ERR_PTR(-EINVAL); | ||
256 | fc = new_conn(); | 289 | fc = new_conn(); |
257 | if (fc == NULL) | 290 | if (fc == NULL) |
258 | return NULL; | 291 | return ERR_PTR(-ENOMEM); |
259 | spin_lock(&fuse_lock); | 292 | spin_lock(&fuse_lock); |
260 | fc->sb = sb; | 293 | if (file->private_data) { |
294 | free_conn(fc); | ||
295 | fc = ERR_PTR(-EINVAL); | ||
296 | } else { | ||
297 | file->private_data = fc; | ||
298 | fc->sb = sb; | ||
299 | fc->file = file; | ||
300 | } | ||
261 | spin_unlock(&fuse_lock); | 301 | spin_unlock(&fuse_lock); |
262 | return fc; | 302 | return fc; |
263 | } | 303 | } |
@@ -315,8 +355,8 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent) | |||
315 | 355 | ||
316 | fc = get_conn(file, sb); | 356 | fc = get_conn(file, sb); |
317 | fput(file); | 357 | fput(file); |
318 | if (fc == NULL) | 358 | if (IS_ERR(fc)) |
319 | return -EINVAL; | 359 | return PTR_ERR(fc); |
320 | 360 | ||
321 | fc->user_id = d.user_id; | 361 | fc->user_id = d.user_id; |
322 | 362 | ||
@@ -336,6 +376,7 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent) | |||
336 | iput(root); | 376 | iput(root); |
337 | goto err; | 377 | goto err; |
338 | } | 378 | } |
379 | fuse_send_init(fc); | ||
339 | return 0; | 380 | return 0; |
340 | 381 | ||
341 | err: | 382 | err: |
@@ -411,8 +452,14 @@ static int __init fuse_init(void) | |||
411 | if (res) | 452 | if (res) |
412 | goto err; | 453 | goto err; |
413 | 454 | ||
455 | res = fuse_dev_init(); | ||
456 | if (res) | ||
457 | goto err_fs_cleanup; | ||
458 | |||
414 | return 0; | 459 | return 0; |
415 | 460 | ||
461 | err_fs_cleanup: | ||
462 | fuse_fs_cleanup(); | ||
416 | err: | 463 | err: |
417 | return res; | 464 | return res; |
418 | } | 465 | } |
@@ -422,6 +469,7 @@ static void __exit fuse_exit(void) | |||
422 | printk(KERN_DEBUG "fuse exit\n"); | 469 | printk(KERN_DEBUG "fuse exit\n"); |
423 | 470 | ||
424 | fuse_fs_cleanup(); | 471 | fuse_fs_cleanup(); |
472 | fuse_dev_cleanup(); | ||
425 | } | 473 | } |
426 | 474 | ||
427 | module_init(fuse_init); | 475 | module_init(fuse_init); |