diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-09-18 20:22:22 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-09-18 20:22:22 -0400 |
commit | 3fe03debfc58aba8f5ddb32abd7343237d07714c (patch) | |
tree | f17d2fbf390810404f5d28f45ed5b379fa13c6ef /fs | |
parent | 9baa5059485d6559081d27d9b1fe1714f3fccab1 (diff) | |
parent | 8061a6fa564fe0e71601632758b78d2ba737663c (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull vfs fixes from Al Viro:
"atomic_open-related fixes (Miklos' series, with EEXIST-related parts
replaced with fix in fs/namei.c:atomic_open() instead of messing with
the instances) + race fix in autofs + leak on failure exit in 9p"
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
9p: don't forget to destroy inode cache if fscache registration fails
atomic_open: take care of EEXIST in no-open case with O_CREAT|O_EXCL in fs/namei.c
vfs: don't set FILE_CREATED before calling ->atomic_open()
nfs: set FILE_CREATED
gfs2: set FILE_CREATED
cifs: fix filp leak in cifs_atomic_open()
vfs: improve i_op->atomic_open() documentation
autofs4: close the races around autofs4_notify_daemon()
Diffstat (limited to 'fs')
-rw-r--r-- | fs/9p/v9fs.c | 7 | ||||
-rw-r--r-- | fs/9p/vfs_inode_dotl.c | 8 | ||||
-rw-r--r-- | fs/autofs4/waitq.c | 13 | ||||
-rw-r--r-- | fs/cifs/dir.c | 1 | ||||
-rw-r--r-- | fs/gfs2/inode.c | 4 | ||||
-rw-r--r-- | fs/namei.c | 34 | ||||
-rw-r--r-- | fs/nfs/dir.c | 3 | ||||
-rw-r--r-- | fs/open.c | 21 |
8 files changed, 55 insertions, 36 deletions
diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c index 58e6cbce4156..08f2e1e9a7e6 100644 --- a/fs/9p/v9fs.c +++ b/fs/9p/v9fs.c | |||
@@ -603,10 +603,11 @@ static int v9fs_cache_register(void) | |||
603 | if (ret < 0) | 603 | if (ret < 0) |
604 | return ret; | 604 | return ret; |
605 | #ifdef CONFIG_9P_FSCACHE | 605 | #ifdef CONFIG_9P_FSCACHE |
606 | return fscache_register_netfs(&v9fs_cache_netfs); | 606 | ret = fscache_register_netfs(&v9fs_cache_netfs); |
607 | #else | 607 | if (ret < 0) |
608 | return ret; | 608 | v9fs_destroy_inode_cache(); |
609 | #endif | 609 | #endif |
610 | return ret; | ||
610 | } | 611 | } |
611 | 612 | ||
612 | static void v9fs_cache_unregister(void) | 613 | static void v9fs_cache_unregister(void) |
diff --git a/fs/9p/vfs_inode_dotl.c b/fs/9p/vfs_inode_dotl.c index 53687bbf2296..a7c481402c46 100644 --- a/fs/9p/vfs_inode_dotl.c +++ b/fs/9p/vfs_inode_dotl.c | |||
@@ -267,14 +267,8 @@ v9fs_vfs_atomic_open_dotl(struct inode *dir, struct dentry *dentry, | |||
267 | } | 267 | } |
268 | 268 | ||
269 | /* Only creates */ | 269 | /* Only creates */ |
270 | if (!(flags & O_CREAT)) | 270 | if (!(flags & O_CREAT) || dentry->d_inode) |
271 | return finish_no_open(file, res); | 271 | return finish_no_open(file, res); |
272 | else if (dentry->d_inode) { | ||
273 | if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) | ||
274 | return -EEXIST; | ||
275 | else | ||
276 | return finish_no_open(file, res); | ||
277 | } | ||
278 | 272 | ||
279 | v9ses = v9fs_inode2v9ses(dir); | 273 | v9ses = v9fs_inode2v9ses(dir); |
280 | 274 | ||
diff --git a/fs/autofs4/waitq.c b/fs/autofs4/waitq.c index 3db70dae40d3..689e40d983ad 100644 --- a/fs/autofs4/waitq.c +++ b/fs/autofs4/waitq.c | |||
@@ -109,13 +109,7 @@ static void autofs4_notify_daemon(struct autofs_sb_info *sbi, | |||
109 | 109 | ||
110 | pkt.hdr.proto_version = sbi->version; | 110 | pkt.hdr.proto_version = sbi->version; |
111 | pkt.hdr.type = type; | 111 | pkt.hdr.type = type; |
112 | mutex_lock(&sbi->wq_mutex); | ||
113 | 112 | ||
114 | /* Check if we have become catatonic */ | ||
115 | if (sbi->catatonic) { | ||
116 | mutex_unlock(&sbi->wq_mutex); | ||
117 | return; | ||
118 | } | ||
119 | switch (type) { | 113 | switch (type) { |
120 | /* Kernel protocol v4 missing and expire packets */ | 114 | /* Kernel protocol v4 missing and expire packets */ |
121 | case autofs_ptype_missing: | 115 | case autofs_ptype_missing: |
@@ -427,7 +421,6 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry, | |||
427 | wq->tgid = current->tgid; | 421 | wq->tgid = current->tgid; |
428 | wq->status = -EINTR; /* Status return if interrupted */ | 422 | wq->status = -EINTR; /* Status return if interrupted */ |
429 | wq->wait_ctr = 2; | 423 | wq->wait_ctr = 2; |
430 | mutex_unlock(&sbi->wq_mutex); | ||
431 | 424 | ||
432 | if (sbi->version < 5) { | 425 | if (sbi->version < 5) { |
433 | if (notify == NFY_MOUNT) | 426 | if (notify == NFY_MOUNT) |
@@ -449,15 +442,15 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry, | |||
449 | (unsigned long) wq->wait_queue_token, wq->name.len, | 442 | (unsigned long) wq->wait_queue_token, wq->name.len, |
450 | wq->name.name, notify); | 443 | wq->name.name, notify); |
451 | 444 | ||
452 | /* autofs4_notify_daemon() may block */ | 445 | /* autofs4_notify_daemon() may block; it will unlock ->wq_mutex */ |
453 | autofs4_notify_daemon(sbi, wq, type); | 446 | autofs4_notify_daemon(sbi, wq, type); |
454 | } else { | 447 | } else { |
455 | wq->wait_ctr++; | 448 | wq->wait_ctr++; |
456 | mutex_unlock(&sbi->wq_mutex); | ||
457 | kfree(qstr.name); | ||
458 | DPRINTK("existing wait id = 0x%08lx, name = %.*s, nfy=%d", | 449 | DPRINTK("existing wait id = 0x%08lx, name = %.*s, nfy=%d", |
459 | (unsigned long) wq->wait_queue_token, wq->name.len, | 450 | (unsigned long) wq->wait_queue_token, wq->name.len, |
460 | wq->name.name, notify); | 451 | wq->name.name, notify); |
452 | mutex_unlock(&sbi->wq_mutex); | ||
453 | kfree(qstr.name); | ||
461 | } | 454 | } |
462 | 455 | ||
463 | /* | 456 | /* |
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index d3e2eaa503a6..5384c2a640ca 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c | |||
@@ -500,6 +500,7 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry, | |||
500 | if (server->ops->close) | 500 | if (server->ops->close) |
501 | server->ops->close(xid, tcon, &fid); | 501 | server->ops->close(xid, tcon, &fid); |
502 | cifs_del_pending_open(&open); | 502 | cifs_del_pending_open(&open); |
503 | fput(file); | ||
503 | rc = -ENOMEM; | 504 | rc = -ENOMEM; |
504 | } | 505 | } |
505 | 506 | ||
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 64915eeae5a7..ced3257f06e8 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c | |||
@@ -694,8 +694,10 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry, | |||
694 | 694 | ||
695 | mark_inode_dirty(inode); | 695 | mark_inode_dirty(inode); |
696 | d_instantiate(dentry, inode); | 696 | d_instantiate(dentry, inode); |
697 | if (file) | 697 | if (file) { |
698 | *opened |= FILE_CREATED; | ||
698 | error = finish_open(file, dentry, gfs2_open_common, opened); | 699 | error = finish_open(file, dentry, gfs2_open_common, opened); |
700 | } | ||
699 | gfs2_glock_dq_uninit(ghs); | 701 | gfs2_glock_dq_uninit(ghs); |
700 | gfs2_glock_dq_uninit(ghs + 1); | 702 | gfs2_glock_dq_uninit(ghs + 1); |
701 | return error; | 703 | return error; |
diff --git a/fs/namei.c b/fs/namei.c index 0dc4cbf21f37..645268f23eb6 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -2656,6 +2656,7 @@ static int atomic_open(struct nameidata *nd, struct dentry *dentry, | |||
2656 | int acc_mode; | 2656 | int acc_mode; |
2657 | int create_error = 0; | 2657 | int create_error = 0; |
2658 | struct dentry *const DENTRY_NOT_SET = (void *) -1UL; | 2658 | struct dentry *const DENTRY_NOT_SET = (void *) -1UL; |
2659 | bool excl; | ||
2659 | 2660 | ||
2660 | BUG_ON(dentry->d_inode); | 2661 | BUG_ON(dentry->d_inode); |
2661 | 2662 | ||
@@ -2669,10 +2670,9 @@ static int atomic_open(struct nameidata *nd, struct dentry *dentry, | |||
2669 | if ((open_flag & O_CREAT) && !IS_POSIXACL(dir)) | 2670 | if ((open_flag & O_CREAT) && !IS_POSIXACL(dir)) |
2670 | mode &= ~current_umask(); | 2671 | mode &= ~current_umask(); |
2671 | 2672 | ||
2672 | if ((open_flag & (O_EXCL | O_CREAT)) == (O_EXCL | O_CREAT)) { | 2673 | excl = (open_flag & (O_EXCL | O_CREAT)) == (O_EXCL | O_CREAT); |
2674 | if (excl) | ||
2673 | open_flag &= ~O_TRUNC; | 2675 | open_flag &= ~O_TRUNC; |
2674 | *opened |= FILE_CREATED; | ||
2675 | } | ||
2676 | 2676 | ||
2677 | /* | 2677 | /* |
2678 | * Checking write permission is tricky, bacuse we don't know if we are | 2678 | * Checking write permission is tricky, bacuse we don't know if we are |
@@ -2725,12 +2725,6 @@ static int atomic_open(struct nameidata *nd, struct dentry *dentry, | |||
2725 | goto out; | 2725 | goto out; |
2726 | } | 2726 | } |
2727 | 2727 | ||
2728 | acc_mode = op->acc_mode; | ||
2729 | if (*opened & FILE_CREATED) { | ||
2730 | fsnotify_create(dir, dentry); | ||
2731 | acc_mode = MAY_OPEN; | ||
2732 | } | ||
2733 | |||
2734 | if (error) { /* returned 1, that is */ | 2728 | if (error) { /* returned 1, that is */ |
2735 | if (WARN_ON(file->f_path.dentry == DENTRY_NOT_SET)) { | 2729 | if (WARN_ON(file->f_path.dentry == DENTRY_NOT_SET)) { |
2736 | error = -EIO; | 2730 | error = -EIO; |
@@ -2740,9 +2734,19 @@ static int atomic_open(struct nameidata *nd, struct dentry *dentry, | |||
2740 | dput(dentry); | 2734 | dput(dentry); |
2741 | dentry = file->f_path.dentry; | 2735 | dentry = file->f_path.dentry; |
2742 | } | 2736 | } |
2743 | if (create_error && dentry->d_inode == NULL) { | 2737 | if (*opened & FILE_CREATED) |
2744 | error = create_error; | 2738 | fsnotify_create(dir, dentry); |
2745 | goto out; | 2739 | if (!dentry->d_inode) { |
2740 | WARN_ON(*opened & FILE_CREATED); | ||
2741 | if (create_error) { | ||
2742 | error = create_error; | ||
2743 | goto out; | ||
2744 | } | ||
2745 | } else { | ||
2746 | if (excl && !(*opened & FILE_CREATED)) { | ||
2747 | error = -EEXIST; | ||
2748 | goto out; | ||
2749 | } | ||
2746 | } | 2750 | } |
2747 | goto looked_up; | 2751 | goto looked_up; |
2748 | } | 2752 | } |
@@ -2751,6 +2755,12 @@ static int atomic_open(struct nameidata *nd, struct dentry *dentry, | |||
2751 | * We didn't have the inode before the open, so check open permission | 2755 | * We didn't have the inode before the open, so check open permission |
2752 | * here. | 2756 | * here. |
2753 | */ | 2757 | */ |
2758 | acc_mode = op->acc_mode; | ||
2759 | if (*opened & FILE_CREATED) { | ||
2760 | WARN_ON(!(open_flag & O_CREAT)); | ||
2761 | fsnotify_create(dir, dentry); | ||
2762 | acc_mode = MAY_OPEN; | ||
2763 | } | ||
2754 | error = may_open(&file->f_path, acc_mode, open_flag); | 2764 | error = may_open(&file->f_path, acc_mode, open_flag); |
2755 | if (error) | 2765 | if (error) |
2756 | fput(file); | 2766 | fput(file); |
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index de434f309af0..854a8f05a610 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c | |||
@@ -1392,6 +1392,9 @@ static int nfs_finish_open(struct nfs_open_context *ctx, | |||
1392 | { | 1392 | { |
1393 | int err; | 1393 | int err; |
1394 | 1394 | ||
1395 | if ((open_flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) | ||
1396 | *opened |= FILE_CREATED; | ||
1397 | |||
1395 | err = finish_open(file, dentry, do_open, opened); | 1398 | err = finish_open(file, dentry, do_open, opened); |
1396 | if (err) | 1399 | if (err) |
1397 | goto out; | 1400 | goto out; |
@@ -744,14 +744,24 @@ cleanup_file: | |||
744 | 744 | ||
745 | /** | 745 | /** |
746 | * finish_open - finish opening a file | 746 | * finish_open - finish opening a file |
747 | * @od: opaque open data | 747 | * @file: file pointer |
748 | * @dentry: pointer to dentry | 748 | * @dentry: pointer to dentry |
749 | * @open: open callback | 749 | * @open: open callback |
750 | * @opened: state of open | ||
750 | * | 751 | * |
751 | * This can be used to finish opening a file passed to i_op->atomic_open(). | 752 | * This can be used to finish opening a file passed to i_op->atomic_open(). |
752 | * | 753 | * |
753 | * If the open callback is set to NULL, then the standard f_op->open() | 754 | * If the open callback is set to NULL, then the standard f_op->open() |
754 | * filesystem callback is substituted. | 755 | * filesystem callback is substituted. |
756 | * | ||
757 | * NB: the dentry reference is _not_ consumed. If, for example, the dentry is | ||
758 | * the return value of d_splice_alias(), then the caller needs to perform dput() | ||
759 | * on it after finish_open(). | ||
760 | * | ||
761 | * On successful return @file is a fully instantiated open file. After this, if | ||
762 | * an error occurs in ->atomic_open(), it needs to clean up with fput(). | ||
763 | * | ||
764 | * Returns zero on success or -errno if the open failed. | ||
755 | */ | 765 | */ |
756 | int finish_open(struct file *file, struct dentry *dentry, | 766 | int finish_open(struct file *file, struct dentry *dentry, |
757 | int (*open)(struct inode *, struct file *), | 767 | int (*open)(struct inode *, struct file *), |
@@ -772,11 +782,16 @@ EXPORT_SYMBOL(finish_open); | |||
772 | /** | 782 | /** |
773 | * finish_no_open - finish ->atomic_open() without opening the file | 783 | * finish_no_open - finish ->atomic_open() without opening the file |
774 | * | 784 | * |
775 | * @od: opaque open data | 785 | * @file: file pointer |
776 | * @dentry: dentry or NULL (as returned from ->lookup()) | 786 | * @dentry: dentry or NULL (as returned from ->lookup()) |
777 | * | 787 | * |
778 | * This can be used to set the result of a successful lookup in ->atomic_open(). | 788 | * This can be used to set the result of a successful lookup in ->atomic_open(). |
779 | * The filesystem's atomic_open() method shall return NULL after calling this. | 789 | * |
790 | * NB: unlike finish_open() this function does consume the dentry reference and | ||
791 | * the caller need not dput() it. | ||
792 | * | ||
793 | * Returns "1" which must be the return value of ->atomic_open() after having | ||
794 | * called this function. | ||
780 | */ | 795 | */ |
781 | int finish_no_open(struct file *file, struct dentry *dentry) | 796 | int finish_no_open(struct file *file, struct dentry *dentry) |
782 | { | 797 | { |