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 | |
| 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()
| -rw-r--r-- | Documentation/filesystems/vfs.txt | 14 | ||||
| -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 |
9 files changed, 62 insertions, 43 deletions
diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt index f93a88250a44..deb48b5fd883 100644 --- a/Documentation/filesystems/vfs.txt +++ b/Documentation/filesystems/vfs.txt | |||
| @@ -359,11 +359,9 @@ struct inode_operations { | |||
| 359 | ssize_t (*listxattr) (struct dentry *, char *, size_t); | 359 | ssize_t (*listxattr) (struct dentry *, char *, size_t); |
| 360 | int (*removexattr) (struct dentry *, const char *); | 360 | int (*removexattr) (struct dentry *, const char *); |
| 361 | void (*update_time)(struct inode *, struct timespec *, int); | 361 | void (*update_time)(struct inode *, struct timespec *, int); |
| 362 | int (*atomic_open)(struct inode *, struct dentry *, | 362 | int (*atomic_open)(struct inode *, struct dentry *, struct file *, |
| 363 | unsigned open_flag, umode_t create_mode, int *opened); | ||
| 363 | int (*tmpfile) (struct inode *, struct dentry *, umode_t); | 364 | int (*tmpfile) (struct inode *, struct dentry *, umode_t); |
| 364 | } ____cacheline_aligned; | ||
| 365 | struct file *, unsigned open_flag, | ||
| 366 | umode_t create_mode, int *opened); | ||
| 367 | }; | 365 | }; |
| 368 | 366 | ||
| 369 | Again, all methods are called without any locks being held, unless | 367 | Again, all methods are called without any locks being held, unless |
| @@ -470,9 +468,11 @@ otherwise noted. | |||
| 470 | method the filesystem can look up, possibly create and open the file in | 468 | method the filesystem can look up, possibly create and open the file in |
| 471 | one atomic operation. If it cannot perform this (e.g. the file type | 469 | one atomic operation. If it cannot perform this (e.g. the file type |
| 472 | turned out to be wrong) it may signal this by returning 1 instead of | 470 | turned out to be wrong) it may signal this by returning 1 instead of |
| 473 | usual 0 or -ve . This method is only called if the last | 471 | usual 0 or -ve . This method is only called if the last component is |
| 474 | component is negative or needs lookup. Cached positive dentries are | 472 | negative or needs lookup. Cached positive dentries are still handled by |
| 475 | still handled by f_op->open(). | 473 | f_op->open(). If the file was created, the FILE_CREATED flag should be |
| 474 | set in "opened". In case of O_EXCL the method must only succeed if the | ||
| 475 | file didn't exist and hence FILE_CREATED shall always be set on success. | ||
| 476 | 476 | ||
| 477 | tmpfile: called in the end of O_TMPFILE open(). Optional, equivalent to | 477 | tmpfile: called in the end of O_TMPFILE open(). Optional, equivalent to |
| 478 | atomically creating, opening and unlinking a file in given directory. | 478 | atomically creating, opening and unlinking a file in given directory. |
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 | { |
