diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/affs/affs.h | 2 | ||||
-rw-r--r-- | fs/affs/amigaffs.c | 28 | ||||
-rw-r--r-- | fs/affs/file.c | 76 | ||||
-rw-r--r-- | fs/befs/linuxvfs.c | 4 | ||||
-rw-r--r-- | fs/binfmt_em86.c | 4 | ||||
-rw-r--r-- | fs/binfmt_misc.c | 4 | ||||
-rw-r--r-- | fs/binfmt_script.c | 10 | ||||
-rw-r--r-- | fs/drop_caches.c | 11 | ||||
-rw-r--r-- | fs/exec.c | 113 | ||||
-rw-r--r-- | fs/fat/fat.h | 1 | ||||
-rw-r--r-- | fs/fat/file.c | 3 | ||||
-rw-r--r-- | fs/fat/inode.c | 12 | ||||
-rw-r--r-- | fs/hugetlbfs/inode.c | 14 | ||||
-rw-r--r-- | fs/inode.c | 2 | ||||
-rw-r--r-- | fs/namei.c | 2 | ||||
-rw-r--r-- | fs/notify/dnotify/dnotify.c | 4 | ||||
-rw-r--r-- | fs/notify/fdinfo.c | 6 | ||||
-rw-r--r-- | fs/notify/fsnotify.c | 4 | ||||
-rw-r--r-- | fs/notify/fsnotify.h | 12 | ||||
-rw-r--r-- | fs/notify/inode_mark.c | 113 | ||||
-rw-r--r-- | fs/notify/inotify/inotify_fsnotify.c | 2 | ||||
-rw-r--r-- | fs/notify/inotify/inotify_user.c | 10 | ||||
-rw-r--r-- | fs/notify/mark.c | 97 | ||||
-rw-r--r-- | fs/notify/vfsmount_mark.c | 109 | ||||
-rw-r--r-- | fs/open.c | 11 | ||||
-rw-r--r-- | fs/seq_file.c | 6 |
26 files changed, 376 insertions, 284 deletions
diff --git a/fs/affs/affs.h b/fs/affs/affs.h index 9bca88159725..ff44ff3ff015 100644 --- a/fs/affs/affs.h +++ b/fs/affs/affs.h | |||
@@ -135,8 +135,10 @@ extern void affs_fix_checksum(struct super_block *sb, struct buffer_head *bh); | |||
135 | extern void secs_to_datestamp(time_t secs, struct affs_date *ds); | 135 | extern void secs_to_datestamp(time_t secs, struct affs_date *ds); |
136 | extern umode_t prot_to_mode(u32 prot); | 136 | extern umode_t prot_to_mode(u32 prot); |
137 | extern void mode_to_prot(struct inode *inode); | 137 | extern void mode_to_prot(struct inode *inode); |
138 | __printf(3, 4) | ||
138 | extern void affs_error(struct super_block *sb, const char *function, | 139 | extern void affs_error(struct super_block *sb, const char *function, |
139 | const char *fmt, ...); | 140 | const char *fmt, ...); |
141 | __printf(3, 4) | ||
140 | extern void affs_warning(struct super_block *sb, const char *function, | 142 | extern void affs_warning(struct super_block *sb, const char *function, |
141 | const char *fmt, ...); | 143 | const char *fmt, ...); |
142 | extern bool affs_nofilenametruncate(const struct dentry *dentry); | 144 | extern bool affs_nofilenametruncate(const struct dentry *dentry); |
diff --git a/fs/affs/amigaffs.c b/fs/affs/amigaffs.c index 937ce8754b24..c852f2fa1710 100644 --- a/fs/affs/amigaffs.c +++ b/fs/affs/amigaffs.c | |||
@@ -10,8 +10,6 @@ | |||
10 | 10 | ||
11 | #include "affs.h" | 11 | #include "affs.h" |
12 | 12 | ||
13 | static char ErrorBuffer[256]; | ||
14 | |||
15 | /* | 13 | /* |
16 | * Functions for accessing Amiga-FFS structures. | 14 | * Functions for accessing Amiga-FFS structures. |
17 | */ | 15 | */ |
@@ -444,30 +442,30 @@ mode_to_prot(struct inode *inode) | |||
444 | void | 442 | void |
445 | affs_error(struct super_block *sb, const char *function, const char *fmt, ...) | 443 | affs_error(struct super_block *sb, const char *function, const char *fmt, ...) |
446 | { | 444 | { |
447 | va_list args; | 445 | struct va_format vaf; |
448 | 446 | va_list args; | |
449 | va_start(args,fmt); | ||
450 | vsnprintf(ErrorBuffer,sizeof(ErrorBuffer),fmt,args); | ||
451 | va_end(args); | ||
452 | 447 | ||
453 | pr_crit("error (device %s): %s(): %s\n", sb->s_id, | 448 | va_start(args, fmt); |
454 | function,ErrorBuffer); | 449 | vaf.fmt = fmt; |
450 | vaf.va = &args; | ||
451 | pr_crit("error (device %s): %s(): %pV\n", sb->s_id, function, &vaf); | ||
455 | if (!(sb->s_flags & MS_RDONLY)) | 452 | if (!(sb->s_flags & MS_RDONLY)) |
456 | pr_warn("Remounting filesystem read-only\n"); | 453 | pr_warn("Remounting filesystem read-only\n"); |
457 | sb->s_flags |= MS_RDONLY; | 454 | sb->s_flags |= MS_RDONLY; |
455 | va_end(args); | ||
458 | } | 456 | } |
459 | 457 | ||
460 | void | 458 | void |
461 | affs_warning(struct super_block *sb, const char *function, const char *fmt, ...) | 459 | affs_warning(struct super_block *sb, const char *function, const char *fmt, ...) |
462 | { | 460 | { |
463 | va_list args; | 461 | struct va_format vaf; |
462 | va_list args; | ||
464 | 463 | ||
465 | va_start(args,fmt); | 464 | va_start(args, fmt); |
466 | vsnprintf(ErrorBuffer,sizeof(ErrorBuffer),fmt,args); | 465 | vaf.fmt = fmt; |
466 | vaf.va = &args; | ||
467 | pr_warn("(device %s): %s(): %pV\n", sb->s_id, function, &vaf); | ||
467 | va_end(args); | 468 | va_end(args); |
468 | |||
469 | pr_warn("(device %s): %s(): %s\n", sb->s_id, | ||
470 | function,ErrorBuffer); | ||
471 | } | 469 | } |
472 | 470 | ||
473 | bool | 471 | bool |
diff --git a/fs/affs/file.c b/fs/affs/file.c index 1ed590aafecf..8faa6593ca6d 100644 --- a/fs/affs/file.c +++ b/fs/affs/file.c | |||
@@ -12,35 +12,10 @@ | |||
12 | * affs regular file handling primitives | 12 | * affs regular file handling primitives |
13 | */ | 13 | */ |
14 | 14 | ||
15 | #include <linux/aio.h> | ||
15 | #include "affs.h" | 16 | #include "affs.h" |
16 | 17 | ||
17 | #if PAGE_SIZE < 4096 | ||
18 | #error PAGE_SIZE must be at least 4096 | ||
19 | #endif | ||
20 | |||
21 | static int affs_grow_extcache(struct inode *inode, u32 lc_idx); | ||
22 | static struct buffer_head *affs_alloc_extblock(struct inode *inode, struct buffer_head *bh, u32 ext); | ||
23 | static inline struct buffer_head *affs_get_extblock(struct inode *inode, u32 ext); | ||
24 | static struct buffer_head *affs_get_extblock_slow(struct inode *inode, u32 ext); | 18 | static struct buffer_head *affs_get_extblock_slow(struct inode *inode, u32 ext); |
25 | static int affs_file_open(struct inode *inode, struct file *filp); | ||
26 | static int affs_file_release(struct inode *inode, struct file *filp); | ||
27 | |||
28 | const struct file_operations affs_file_operations = { | ||
29 | .llseek = generic_file_llseek, | ||
30 | .read = new_sync_read, | ||
31 | .read_iter = generic_file_read_iter, | ||
32 | .write = new_sync_write, | ||
33 | .write_iter = generic_file_write_iter, | ||
34 | .mmap = generic_file_mmap, | ||
35 | .open = affs_file_open, | ||
36 | .release = affs_file_release, | ||
37 | .fsync = affs_file_fsync, | ||
38 | .splice_read = generic_file_splice_read, | ||
39 | }; | ||
40 | |||
41 | const struct inode_operations affs_file_inode_operations = { | ||
42 | .setattr = affs_notify_change, | ||
43 | }; | ||
44 | 19 | ||
45 | static int | 20 | static int |
46 | affs_file_open(struct inode *inode, struct file *filp) | 21 | affs_file_open(struct inode *inode, struct file *filp) |
@@ -355,7 +330,8 @@ affs_get_block(struct inode *inode, sector_t block, struct buffer_head *bh_resul | |||
355 | 330 | ||
356 | /* store new block */ | 331 | /* store new block */ |
357 | if (bh_result->b_blocknr) | 332 | if (bh_result->b_blocknr) |
358 | affs_warning(sb, "get_block", "block already set (%x)", bh_result->b_blocknr); | 333 | affs_warning(sb, "get_block", "block already set (%lx)", |
334 | (unsigned long)bh_result->b_blocknr); | ||
359 | AFFS_BLOCK(sb, ext_bh, block) = cpu_to_be32(blocknr); | 335 | AFFS_BLOCK(sb, ext_bh, block) = cpu_to_be32(blocknr); |
360 | AFFS_HEAD(ext_bh)->block_count = cpu_to_be32(block + 1); | 336 | AFFS_HEAD(ext_bh)->block_count = cpu_to_be32(block + 1); |
361 | affs_adjust_checksum(ext_bh, blocknr - bh_result->b_blocknr + 1); | 337 | affs_adjust_checksum(ext_bh, blocknr - bh_result->b_blocknr + 1); |
@@ -377,7 +353,8 @@ affs_get_block(struct inode *inode, sector_t block, struct buffer_head *bh_resul | |||
377 | return 0; | 353 | return 0; |
378 | 354 | ||
379 | err_big: | 355 | err_big: |
380 | affs_error(inode->i_sb,"get_block","strange block request %d", block); | 356 | affs_error(inode->i_sb, "get_block", "strange block request %d", |
357 | (int)block); | ||
381 | return -EIO; | 358 | return -EIO; |
382 | err_ext: | 359 | err_ext: |
383 | // unlock cache | 360 | // unlock cache |
@@ -412,6 +389,22 @@ static void affs_write_failed(struct address_space *mapping, loff_t to) | |||
412 | } | 389 | } |
413 | } | 390 | } |
414 | 391 | ||
392 | static ssize_t | ||
393 | affs_direct_IO(int rw, struct kiocb *iocb, struct iov_iter *iter, | ||
394 | loff_t offset) | ||
395 | { | ||
396 | struct file *file = iocb->ki_filp; | ||
397 | struct address_space *mapping = file->f_mapping; | ||
398 | struct inode *inode = mapping->host; | ||
399 | size_t count = iov_iter_count(iter); | ||
400 | ssize_t ret; | ||
401 | |||
402 | ret = blockdev_direct_IO(rw, iocb, inode, iter, offset, affs_get_block); | ||
403 | if (ret < 0 && (rw & WRITE)) | ||
404 | affs_write_failed(mapping, offset + count); | ||
405 | return ret; | ||
406 | } | ||
407 | |||
415 | static int affs_write_begin(struct file *file, struct address_space *mapping, | 408 | static int affs_write_begin(struct file *file, struct address_space *mapping, |
416 | loff_t pos, unsigned len, unsigned flags, | 409 | loff_t pos, unsigned len, unsigned flags, |
417 | struct page **pagep, void **fsdata) | 410 | struct page **pagep, void **fsdata) |
@@ -438,6 +431,7 @@ const struct address_space_operations affs_aops = { | |||
438 | .writepage = affs_writepage, | 431 | .writepage = affs_writepage, |
439 | .write_begin = affs_write_begin, | 432 | .write_begin = affs_write_begin, |
440 | .write_end = generic_write_end, | 433 | .write_end = generic_write_end, |
434 | .direct_IO = affs_direct_IO, | ||
441 | .bmap = _affs_bmap | 435 | .bmap = _affs_bmap |
442 | }; | 436 | }; |
443 | 437 | ||
@@ -867,8 +861,9 @@ affs_truncate(struct inode *inode) | |||
867 | // lock cache | 861 | // lock cache |
868 | ext_bh = affs_get_extblock(inode, ext); | 862 | ext_bh = affs_get_extblock(inode, ext); |
869 | if (IS_ERR(ext_bh)) { | 863 | if (IS_ERR(ext_bh)) { |
870 | affs_warning(sb, "truncate", "unexpected read error for ext block %u (%d)", | 864 | affs_warning(sb, "truncate", |
871 | ext, PTR_ERR(ext_bh)); | 865 | "unexpected read error for ext block %u (%ld)", |
866 | (unsigned int)ext, PTR_ERR(ext_bh)); | ||
872 | return; | 867 | return; |
873 | } | 868 | } |
874 | if (AFFS_I(inode)->i_lc) { | 869 | if (AFFS_I(inode)->i_lc) { |
@@ -914,8 +909,9 @@ affs_truncate(struct inode *inode) | |||
914 | struct buffer_head *bh = affs_bread_ino(inode, last_blk, 0); | 909 | struct buffer_head *bh = affs_bread_ino(inode, last_blk, 0); |
915 | u32 tmp; | 910 | u32 tmp; |
916 | if (IS_ERR(bh)) { | 911 | if (IS_ERR(bh)) { |
917 | affs_warning(sb, "truncate", "unexpected read error for last block %u (%d)", | 912 | affs_warning(sb, "truncate", |
918 | ext, PTR_ERR(bh)); | 913 | "unexpected read error for last block %u (%ld)", |
914 | (unsigned int)ext, PTR_ERR(bh)); | ||
919 | return; | 915 | return; |
920 | } | 916 | } |
921 | tmp = be32_to_cpu(AFFS_DATA_HEAD(bh)->next); | 917 | tmp = be32_to_cpu(AFFS_DATA_HEAD(bh)->next); |
@@ -961,3 +957,19 @@ int affs_file_fsync(struct file *filp, loff_t start, loff_t end, int datasync) | |||
961 | mutex_unlock(&inode->i_mutex); | 957 | mutex_unlock(&inode->i_mutex); |
962 | return ret; | 958 | return ret; |
963 | } | 959 | } |
960 | const struct file_operations affs_file_operations = { | ||
961 | .llseek = generic_file_llseek, | ||
962 | .read = new_sync_read, | ||
963 | .read_iter = generic_file_read_iter, | ||
964 | .write = new_sync_write, | ||
965 | .write_iter = generic_file_write_iter, | ||
966 | .mmap = generic_file_mmap, | ||
967 | .open = affs_file_open, | ||
968 | .release = affs_file_release, | ||
969 | .fsync = affs_file_fsync, | ||
970 | .splice_read = generic_file_splice_read, | ||
971 | }; | ||
972 | |||
973 | const struct inode_operations affs_file_inode_operations = { | ||
974 | .setattr = affs_notify_change, | ||
975 | }; | ||
diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c index b94d1cc9cd30..edf47774b03d 100644 --- a/fs/befs/linuxvfs.c +++ b/fs/befs/linuxvfs.c | |||
@@ -269,10 +269,6 @@ more: | |||
269 | } | 269 | } |
270 | ctx->pos++; | 270 | ctx->pos++; |
271 | goto more; | 271 | goto more; |
272 | |||
273 | befs_debug(sb, "<--- %s pos %lld", __func__, ctx->pos); | ||
274 | |||
275 | return 0; | ||
276 | } | 272 | } |
277 | 273 | ||
278 | static struct inode * | 274 | static struct inode * |
diff --git a/fs/binfmt_em86.c b/fs/binfmt_em86.c index f37b08cea1f7..490538536cb4 100644 --- a/fs/binfmt_em86.c +++ b/fs/binfmt_em86.c | |||
@@ -42,6 +42,10 @@ static int load_em86(struct linux_binprm *bprm) | |||
42 | return -ENOEXEC; | 42 | return -ENOEXEC; |
43 | } | 43 | } |
44 | 44 | ||
45 | /* Need to be able to load the file after exec */ | ||
46 | if (bprm->interp_flags & BINPRM_FLAGS_PATH_INACCESSIBLE) | ||
47 | return -ENOENT; | ||
48 | |||
45 | allow_write_access(bprm->file); | 49 | allow_write_access(bprm->file); |
46 | fput(bprm->file); | 50 | fput(bprm->file); |
47 | bprm->file = NULL; | 51 | bprm->file = NULL; |
diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c index 70789e198dea..c04ef1d4f18a 100644 --- a/fs/binfmt_misc.c +++ b/fs/binfmt_misc.c | |||
@@ -144,6 +144,10 @@ static int load_misc_binary(struct linux_binprm *bprm) | |||
144 | if (!fmt) | 144 | if (!fmt) |
145 | goto ret; | 145 | goto ret; |
146 | 146 | ||
147 | /* Need to be able to load the file after exec */ | ||
148 | if (bprm->interp_flags & BINPRM_FLAGS_PATH_INACCESSIBLE) | ||
149 | return -ENOENT; | ||
150 | |||
147 | if (!(fmt->flags & MISC_FMT_PRESERVE_ARGV0)) { | 151 | if (!(fmt->flags & MISC_FMT_PRESERVE_ARGV0)) { |
148 | retval = remove_arg_zero(bprm); | 152 | retval = remove_arg_zero(bprm); |
149 | if (retval) | 153 | if (retval) |
diff --git a/fs/binfmt_script.c b/fs/binfmt_script.c index 5027a3e14922..afdf4e3cafc2 100644 --- a/fs/binfmt_script.c +++ b/fs/binfmt_script.c | |||
@@ -24,6 +24,16 @@ static int load_script(struct linux_binprm *bprm) | |||
24 | 24 | ||
25 | if ((bprm->buf[0] != '#') || (bprm->buf[1] != '!')) | 25 | if ((bprm->buf[0] != '#') || (bprm->buf[1] != '!')) |
26 | return -ENOEXEC; | 26 | return -ENOEXEC; |
27 | |||
28 | /* | ||
29 | * If the script filename will be inaccessible after exec, typically | ||
30 | * because it is a "/dev/fd/<fd>/.." path against an O_CLOEXEC fd, give | ||
31 | * up now (on the assumption that the interpreter will want to load | ||
32 | * this file). | ||
33 | */ | ||
34 | if (bprm->interp_flags & BINPRM_FLAGS_PATH_INACCESSIBLE) | ||
35 | return -ENOENT; | ||
36 | |||
27 | /* | 37 | /* |
28 | * This section does the #! interpretation. | 38 | * This section does the #! interpretation. |
29 | * Sorta complicated, but hopefully it will work. -TYT | 39 | * Sorta complicated, but hopefully it will work. -TYT |
diff --git a/fs/drop_caches.c b/fs/drop_caches.c index 1de7294aad20..2bc2c87f35e7 100644 --- a/fs/drop_caches.c +++ b/fs/drop_caches.c | |||
@@ -40,13 +40,14 @@ static void drop_pagecache_sb(struct super_block *sb, void *unused) | |||
40 | static void drop_slab(void) | 40 | static void drop_slab(void) |
41 | { | 41 | { |
42 | int nr_objects; | 42 | int nr_objects; |
43 | struct shrink_control shrink = { | ||
44 | .gfp_mask = GFP_KERNEL, | ||
45 | }; | ||
46 | 43 | ||
47 | nodes_setall(shrink.nodes_to_scan); | ||
48 | do { | 44 | do { |
49 | nr_objects = shrink_slab(&shrink, 1000, 1000); | 45 | int nid; |
46 | |||
47 | nr_objects = 0; | ||
48 | for_each_online_node(nid) | ||
49 | nr_objects += shrink_node_slabs(GFP_KERNEL, nid, | ||
50 | 1000, 1000); | ||
50 | } while (nr_objects > 10); | 51 | } while (nr_objects > 10); |
51 | } | 52 | } |
52 | 53 | ||
@@ -748,18 +748,25 @@ EXPORT_SYMBOL(setup_arg_pages); | |||
748 | 748 | ||
749 | #endif /* CONFIG_MMU */ | 749 | #endif /* CONFIG_MMU */ |
750 | 750 | ||
751 | static struct file *do_open_exec(struct filename *name) | 751 | static struct file *do_open_execat(int fd, struct filename *name, int flags) |
752 | { | 752 | { |
753 | struct file *file; | 753 | struct file *file; |
754 | int err; | 754 | int err; |
755 | static const struct open_flags open_exec_flags = { | 755 | struct open_flags open_exec_flags = { |
756 | .open_flag = O_LARGEFILE | O_RDONLY | __FMODE_EXEC, | 756 | .open_flag = O_LARGEFILE | O_RDONLY | __FMODE_EXEC, |
757 | .acc_mode = MAY_EXEC | MAY_OPEN, | 757 | .acc_mode = MAY_EXEC | MAY_OPEN, |
758 | .intent = LOOKUP_OPEN, | 758 | .intent = LOOKUP_OPEN, |
759 | .lookup_flags = LOOKUP_FOLLOW, | 759 | .lookup_flags = LOOKUP_FOLLOW, |
760 | }; | 760 | }; |
761 | 761 | ||
762 | file = do_filp_open(AT_FDCWD, name, &open_exec_flags); | 762 | if ((flags & ~(AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) != 0) |
763 | return ERR_PTR(-EINVAL); | ||
764 | if (flags & AT_SYMLINK_NOFOLLOW) | ||
765 | open_exec_flags.lookup_flags &= ~LOOKUP_FOLLOW; | ||
766 | if (flags & AT_EMPTY_PATH) | ||
767 | open_exec_flags.lookup_flags |= LOOKUP_EMPTY; | ||
768 | |||
769 | file = do_filp_open(fd, name, &open_exec_flags); | ||
763 | if (IS_ERR(file)) | 770 | if (IS_ERR(file)) |
764 | goto out; | 771 | goto out; |
765 | 772 | ||
@@ -770,12 +777,13 @@ static struct file *do_open_exec(struct filename *name) | |||
770 | if (file->f_path.mnt->mnt_flags & MNT_NOEXEC) | 777 | if (file->f_path.mnt->mnt_flags & MNT_NOEXEC) |
771 | goto exit; | 778 | goto exit; |
772 | 779 | ||
773 | fsnotify_open(file); | ||
774 | |||
775 | err = deny_write_access(file); | 780 | err = deny_write_access(file); |
776 | if (err) | 781 | if (err) |
777 | goto exit; | 782 | goto exit; |
778 | 783 | ||
784 | if (name->name[0] != '\0') | ||
785 | fsnotify_open(file); | ||
786 | |||
779 | out: | 787 | out: |
780 | return file; | 788 | return file; |
781 | 789 | ||
@@ -787,7 +795,7 @@ exit: | |||
787 | struct file *open_exec(const char *name) | 795 | struct file *open_exec(const char *name) |
788 | { | 796 | { |
789 | struct filename tmp = { .name = name }; | 797 | struct filename tmp = { .name = name }; |
790 | return do_open_exec(&tmp); | 798 | return do_open_execat(AT_FDCWD, &tmp, 0); |
791 | } | 799 | } |
792 | EXPORT_SYMBOL(open_exec); | 800 | EXPORT_SYMBOL(open_exec); |
793 | 801 | ||
@@ -1428,10 +1436,12 @@ static int exec_binprm(struct linux_binprm *bprm) | |||
1428 | /* | 1436 | /* |
1429 | * sys_execve() executes a new program. | 1437 | * sys_execve() executes a new program. |
1430 | */ | 1438 | */ |
1431 | static int do_execve_common(struct filename *filename, | 1439 | static int do_execveat_common(int fd, struct filename *filename, |
1432 | struct user_arg_ptr argv, | 1440 | struct user_arg_ptr argv, |
1433 | struct user_arg_ptr envp) | 1441 | struct user_arg_ptr envp, |
1442 | int flags) | ||
1434 | { | 1443 | { |
1444 | char *pathbuf = NULL; | ||
1435 | struct linux_binprm *bprm; | 1445 | struct linux_binprm *bprm; |
1436 | struct file *file; | 1446 | struct file *file; |
1437 | struct files_struct *displaced; | 1447 | struct files_struct *displaced; |
@@ -1472,7 +1482,7 @@ static int do_execve_common(struct filename *filename, | |||
1472 | check_unsafe_exec(bprm); | 1482 | check_unsafe_exec(bprm); |
1473 | current->in_execve = 1; | 1483 | current->in_execve = 1; |
1474 | 1484 | ||
1475 | file = do_open_exec(filename); | 1485 | file = do_open_execat(fd, filename, flags); |
1476 | retval = PTR_ERR(file); | 1486 | retval = PTR_ERR(file); |
1477 | if (IS_ERR(file)) | 1487 | if (IS_ERR(file)) |
1478 | goto out_unmark; | 1488 | goto out_unmark; |
@@ -1480,7 +1490,28 @@ static int do_execve_common(struct filename *filename, | |||
1480 | sched_exec(); | 1490 | sched_exec(); |
1481 | 1491 | ||
1482 | bprm->file = file; | 1492 | bprm->file = file; |
1483 | bprm->filename = bprm->interp = filename->name; | 1493 | if (fd == AT_FDCWD || filename->name[0] == '/') { |
1494 | bprm->filename = filename->name; | ||
1495 | } else { | ||
1496 | if (filename->name[0] == '\0') | ||
1497 | pathbuf = kasprintf(GFP_TEMPORARY, "/dev/fd/%d", fd); | ||
1498 | else | ||
1499 | pathbuf = kasprintf(GFP_TEMPORARY, "/dev/fd/%d/%s", | ||
1500 | fd, filename->name); | ||
1501 | if (!pathbuf) { | ||
1502 | retval = -ENOMEM; | ||
1503 | goto out_unmark; | ||
1504 | } | ||
1505 | /* | ||
1506 | * Record that a name derived from an O_CLOEXEC fd will be | ||
1507 | * inaccessible after exec. Relies on having exclusive access to | ||
1508 | * current->files (due to unshare_files above). | ||
1509 | */ | ||
1510 | if (close_on_exec(fd, rcu_dereference_raw(current->files->fdt))) | ||
1511 | bprm->interp_flags |= BINPRM_FLAGS_PATH_INACCESSIBLE; | ||
1512 | bprm->filename = pathbuf; | ||
1513 | } | ||
1514 | bprm->interp = bprm->filename; | ||
1484 | 1515 | ||
1485 | retval = bprm_mm_init(bprm); | 1516 | retval = bprm_mm_init(bprm); |
1486 | if (retval) | 1517 | if (retval) |
@@ -1521,6 +1552,7 @@ static int do_execve_common(struct filename *filename, | |||
1521 | acct_update_integrals(current); | 1552 | acct_update_integrals(current); |
1522 | task_numa_free(current); | 1553 | task_numa_free(current); |
1523 | free_bprm(bprm); | 1554 | free_bprm(bprm); |
1555 | kfree(pathbuf); | ||
1524 | putname(filename); | 1556 | putname(filename); |
1525 | if (displaced) | 1557 | if (displaced) |
1526 | put_files_struct(displaced); | 1558 | put_files_struct(displaced); |
@@ -1538,6 +1570,7 @@ out_unmark: | |||
1538 | 1570 | ||
1539 | out_free: | 1571 | out_free: |
1540 | free_bprm(bprm); | 1572 | free_bprm(bprm); |
1573 | kfree(pathbuf); | ||
1541 | 1574 | ||
1542 | out_files: | 1575 | out_files: |
1543 | if (displaced) | 1576 | if (displaced) |
@@ -1553,7 +1586,18 @@ int do_execve(struct filename *filename, | |||
1553 | { | 1586 | { |
1554 | struct user_arg_ptr argv = { .ptr.native = __argv }; | 1587 | struct user_arg_ptr argv = { .ptr.native = __argv }; |
1555 | struct user_arg_ptr envp = { .ptr.native = __envp }; | 1588 | struct user_arg_ptr envp = { .ptr.native = __envp }; |
1556 | return do_execve_common(filename, argv, envp); | 1589 | return do_execveat_common(AT_FDCWD, filename, argv, envp, 0); |
1590 | } | ||
1591 | |||
1592 | int do_execveat(int fd, struct filename *filename, | ||
1593 | const char __user *const __user *__argv, | ||
1594 | const char __user *const __user *__envp, | ||
1595 | int flags) | ||
1596 | { | ||
1597 | struct user_arg_ptr argv = { .ptr.native = __argv }; | ||
1598 | struct user_arg_ptr envp = { .ptr.native = __envp }; | ||
1599 | |||
1600 | return do_execveat_common(fd, filename, argv, envp, flags); | ||
1557 | } | 1601 | } |
1558 | 1602 | ||
1559 | #ifdef CONFIG_COMPAT | 1603 | #ifdef CONFIG_COMPAT |
@@ -1569,7 +1613,23 @@ static int compat_do_execve(struct filename *filename, | |||
1569 | .is_compat = true, | 1613 | .is_compat = true, |
1570 | .ptr.compat = __envp, | 1614 | .ptr.compat = __envp, |
1571 | }; | 1615 | }; |
1572 | return do_execve_common(filename, argv, envp); | 1616 | return do_execveat_common(AT_FDCWD, filename, argv, envp, 0); |
1617 | } | ||
1618 | |||
1619 | static int compat_do_execveat(int fd, struct filename *filename, | ||
1620 | const compat_uptr_t __user *__argv, | ||
1621 | const compat_uptr_t __user *__envp, | ||
1622 | int flags) | ||
1623 | { | ||
1624 | struct user_arg_ptr argv = { | ||
1625 | .is_compat = true, | ||
1626 | .ptr.compat = __argv, | ||
1627 | }; | ||
1628 | struct user_arg_ptr envp = { | ||
1629 | .is_compat = true, | ||
1630 | .ptr.compat = __envp, | ||
1631 | }; | ||
1632 | return do_execveat_common(fd, filename, argv, envp, flags); | ||
1573 | } | 1633 | } |
1574 | #endif | 1634 | #endif |
1575 | 1635 | ||
@@ -1609,6 +1669,20 @@ SYSCALL_DEFINE3(execve, | |||
1609 | { | 1669 | { |
1610 | return do_execve(getname(filename), argv, envp); | 1670 | return do_execve(getname(filename), argv, envp); |
1611 | } | 1671 | } |
1672 | |||
1673 | SYSCALL_DEFINE5(execveat, | ||
1674 | int, fd, const char __user *, filename, | ||
1675 | const char __user *const __user *, argv, | ||
1676 | const char __user *const __user *, envp, | ||
1677 | int, flags) | ||
1678 | { | ||
1679 | int lookup_flags = (flags & AT_EMPTY_PATH) ? LOOKUP_EMPTY : 0; | ||
1680 | |||
1681 | return do_execveat(fd, | ||
1682 | getname_flags(filename, lookup_flags, NULL), | ||
1683 | argv, envp, flags); | ||
1684 | } | ||
1685 | |||
1612 | #ifdef CONFIG_COMPAT | 1686 | #ifdef CONFIG_COMPAT |
1613 | COMPAT_SYSCALL_DEFINE3(execve, const char __user *, filename, | 1687 | COMPAT_SYSCALL_DEFINE3(execve, const char __user *, filename, |
1614 | const compat_uptr_t __user *, argv, | 1688 | const compat_uptr_t __user *, argv, |
@@ -1616,4 +1690,17 @@ COMPAT_SYSCALL_DEFINE3(execve, const char __user *, filename, | |||
1616 | { | 1690 | { |
1617 | return compat_do_execve(getname(filename), argv, envp); | 1691 | return compat_do_execve(getname(filename), argv, envp); |
1618 | } | 1692 | } |
1693 | |||
1694 | COMPAT_SYSCALL_DEFINE5(execveat, int, fd, | ||
1695 | const char __user *, filename, | ||
1696 | const compat_uptr_t __user *, argv, | ||
1697 | const compat_uptr_t __user *, envp, | ||
1698 | int, flags) | ||
1699 | { | ||
1700 | int lookup_flags = (flags & AT_EMPTY_PATH) ? LOOKUP_EMPTY : 0; | ||
1701 | |||
1702 | return compat_do_execveat(fd, | ||
1703 | getname_flags(filename, lookup_flags, NULL), | ||
1704 | argv, envp, flags); | ||
1705 | } | ||
1619 | #endif | 1706 | #endif |
diff --git a/fs/fat/fat.h b/fs/fat/fat.h index e0c4ba39a377..64e295e8ff38 100644 --- a/fs/fat/fat.h +++ b/fs/fat/fat.h | |||
@@ -370,6 +370,7 @@ extern int fat_file_fsync(struct file *file, loff_t start, loff_t end, | |||
370 | int datasync); | 370 | int datasync); |
371 | 371 | ||
372 | /* fat/inode.c */ | 372 | /* fat/inode.c */ |
373 | extern int fat_block_truncate_page(struct inode *inode, loff_t from); | ||
373 | extern void fat_attach(struct inode *inode, loff_t i_pos); | 374 | extern void fat_attach(struct inode *inode, loff_t i_pos); |
374 | extern void fat_detach(struct inode *inode); | 375 | extern void fat_detach(struct inode *inode); |
375 | extern struct inode *fat_iget(struct super_block *sb, loff_t i_pos); | 376 | extern struct inode *fat_iget(struct super_block *sb, loff_t i_pos); |
diff --git a/fs/fat/file.c b/fs/fat/file.c index 85f79a89e747..8429c68e3057 100644 --- a/fs/fat/file.c +++ b/fs/fat/file.c | |||
@@ -443,6 +443,9 @@ int fat_setattr(struct dentry *dentry, struct iattr *attr) | |||
443 | } | 443 | } |
444 | 444 | ||
445 | if (attr->ia_valid & ATTR_SIZE) { | 445 | if (attr->ia_valid & ATTR_SIZE) { |
446 | error = fat_block_truncate_page(inode, attr->ia_size); | ||
447 | if (error) | ||
448 | goto out; | ||
446 | down_write(&MSDOS_I(inode)->truncate_lock); | 449 | down_write(&MSDOS_I(inode)->truncate_lock); |
447 | truncate_setsize(inode, attr->ia_size); | 450 | truncate_setsize(inode, attr->ia_size); |
448 | fat_truncate_blocks(inode, attr->ia_size); | 451 | fat_truncate_blocks(inode, attr->ia_size); |
diff --git a/fs/fat/inode.c b/fs/fat/inode.c index 756aead10d96..7b41a2dcdd76 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c | |||
@@ -294,6 +294,18 @@ static sector_t _fat_bmap(struct address_space *mapping, sector_t block) | |||
294 | return blocknr; | 294 | return blocknr; |
295 | } | 295 | } |
296 | 296 | ||
297 | /* | ||
298 | * fat_block_truncate_page() zeroes out a mapping from file offset `from' | ||
299 | * up to the end of the block which corresponds to `from'. | ||
300 | * This is required during truncate to physically zeroout the tail end | ||
301 | * of that block so it doesn't yield old data if the file is later grown. | ||
302 | * Also, avoid causing failure from fsx for cases of "data past EOF" | ||
303 | */ | ||
304 | int fat_block_truncate_page(struct inode *inode, loff_t from) | ||
305 | { | ||
306 | return block_truncate_page(inode->i_mapping, from, fat_get_block); | ||
307 | } | ||
308 | |||
297 | static const struct address_space_operations fat_aops = { | 309 | static const struct address_space_operations fat_aops = { |
298 | .readpage = fat_readpage, | 310 | .readpage = fat_readpage, |
299 | .readpages = fat_readpages, | 311 | .readpages = fat_readpages, |
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index 1e2872b25343..5eba47f593f8 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c | |||
@@ -412,10 +412,10 @@ static int hugetlb_vmtruncate(struct inode *inode, loff_t offset) | |||
412 | pgoff = offset >> PAGE_SHIFT; | 412 | pgoff = offset >> PAGE_SHIFT; |
413 | 413 | ||
414 | i_size_write(inode, offset); | 414 | i_size_write(inode, offset); |
415 | mutex_lock(&mapping->i_mmap_mutex); | 415 | i_mmap_lock_write(mapping); |
416 | if (!RB_EMPTY_ROOT(&mapping->i_mmap)) | 416 | if (!RB_EMPTY_ROOT(&mapping->i_mmap)) |
417 | hugetlb_vmtruncate_list(&mapping->i_mmap, pgoff); | 417 | hugetlb_vmtruncate_list(&mapping->i_mmap, pgoff); |
418 | mutex_unlock(&mapping->i_mmap_mutex); | 418 | i_mmap_unlock_write(mapping); |
419 | truncate_hugepages(inode, offset); | 419 | truncate_hugepages(inode, offset); |
420 | return 0; | 420 | return 0; |
421 | } | 421 | } |
@@ -472,12 +472,12 @@ static struct inode *hugetlbfs_get_root(struct super_block *sb, | |||
472 | } | 472 | } |
473 | 473 | ||
474 | /* | 474 | /* |
475 | * Hugetlbfs is not reclaimable; therefore its i_mmap_mutex will never | 475 | * Hugetlbfs is not reclaimable; therefore its i_mmap_rwsem will never |
476 | * be taken from reclaim -- unlike regular filesystems. This needs an | 476 | * be taken from reclaim -- unlike regular filesystems. This needs an |
477 | * annotation because huge_pmd_share() does an allocation under | 477 | * annotation because huge_pmd_share() does an allocation under |
478 | * i_mmap_mutex. | 478 | * i_mmap_rwsem. |
479 | */ | 479 | */ |
480 | static struct lock_class_key hugetlbfs_i_mmap_mutex_key; | 480 | static struct lock_class_key hugetlbfs_i_mmap_rwsem_key; |
481 | 481 | ||
482 | static struct inode *hugetlbfs_get_inode(struct super_block *sb, | 482 | static struct inode *hugetlbfs_get_inode(struct super_block *sb, |
483 | struct inode *dir, | 483 | struct inode *dir, |
@@ -495,8 +495,8 @@ static struct inode *hugetlbfs_get_inode(struct super_block *sb, | |||
495 | struct hugetlbfs_inode_info *info; | 495 | struct hugetlbfs_inode_info *info; |
496 | inode->i_ino = get_next_ino(); | 496 | inode->i_ino = get_next_ino(); |
497 | inode_init_owner(inode, dir, mode); | 497 | inode_init_owner(inode, dir, mode); |
498 | lockdep_set_class(&inode->i_mapping->i_mmap_mutex, | 498 | lockdep_set_class(&inode->i_mapping->i_mmap_rwsem, |
499 | &hugetlbfs_i_mmap_mutex_key); | 499 | &hugetlbfs_i_mmap_rwsem_key); |
500 | inode->i_mapping->a_ops = &hugetlbfs_aops; | 500 | inode->i_mapping->a_ops = &hugetlbfs_aops; |
501 | inode->i_mapping->backing_dev_info =&hugetlbfs_backing_dev_info; | 501 | inode->i_mapping->backing_dev_info =&hugetlbfs_backing_dev_info; |
502 | inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; | 502 | inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; |
diff --git a/fs/inode.c b/fs/inode.c index 2ed95f7caa4f..ad60555b4768 100644 --- a/fs/inode.c +++ b/fs/inode.c | |||
@@ -346,7 +346,7 @@ void address_space_init_once(struct address_space *mapping) | |||
346 | memset(mapping, 0, sizeof(*mapping)); | 346 | memset(mapping, 0, sizeof(*mapping)); |
347 | INIT_RADIX_TREE(&mapping->page_tree, GFP_ATOMIC); | 347 | INIT_RADIX_TREE(&mapping->page_tree, GFP_ATOMIC); |
348 | spin_lock_init(&mapping->tree_lock); | 348 | spin_lock_init(&mapping->tree_lock); |
349 | mutex_init(&mapping->i_mmap_mutex); | 349 | init_rwsem(&mapping->i_mmap_rwsem); |
350 | INIT_LIST_HEAD(&mapping->private_list); | 350 | INIT_LIST_HEAD(&mapping->private_list); |
351 | spin_lock_init(&mapping->private_lock); | 351 | spin_lock_init(&mapping->private_lock); |
352 | mapping->i_mmap = RB_ROOT; | 352 | mapping->i_mmap = RB_ROOT; |
diff --git a/fs/namei.c b/fs/namei.c index db5fe86319e6..ca814165d84c 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -130,7 +130,7 @@ void final_putname(struct filename *name) | |||
130 | 130 | ||
131 | #define EMBEDDED_NAME_MAX (PATH_MAX - sizeof(struct filename)) | 131 | #define EMBEDDED_NAME_MAX (PATH_MAX - sizeof(struct filename)) |
132 | 132 | ||
133 | static struct filename * | 133 | struct filename * |
134 | getname_flags(const char __user *filename, int flags, int *empty) | 134 | getname_flags(const char __user *filename, int flags, int *empty) |
135 | { | 135 | { |
136 | struct filename *result, *err; | 136 | struct filename *result, *err; |
diff --git a/fs/notify/dnotify/dnotify.c b/fs/notify/dnotify/dnotify.c index caaaf9dfe353..44523f4a6084 100644 --- a/fs/notify/dnotify/dnotify.c +++ b/fs/notify/dnotify/dnotify.c | |||
@@ -69,8 +69,8 @@ static void dnotify_recalc_inode_mask(struct fsnotify_mark *fsn_mark) | |||
69 | if (old_mask == new_mask) | 69 | if (old_mask == new_mask) |
70 | return; | 70 | return; |
71 | 71 | ||
72 | if (fsn_mark->i.inode) | 72 | if (fsn_mark->inode) |
73 | fsnotify_recalc_inode_mask(fsn_mark->i.inode); | 73 | fsnotify_recalc_inode_mask(fsn_mark->inode); |
74 | } | 74 | } |
75 | 75 | ||
76 | /* | 76 | /* |
diff --git a/fs/notify/fdinfo.c b/fs/notify/fdinfo.c index 6ffd220eb14d..58b7cdb63da9 100644 --- a/fs/notify/fdinfo.c +++ b/fs/notify/fdinfo.c | |||
@@ -80,7 +80,7 @@ static void inotify_fdinfo(struct seq_file *m, struct fsnotify_mark *mark) | |||
80 | return; | 80 | return; |
81 | 81 | ||
82 | inode_mark = container_of(mark, struct inotify_inode_mark, fsn_mark); | 82 | inode_mark = container_of(mark, struct inotify_inode_mark, fsn_mark); |
83 | inode = igrab(mark->i.inode); | 83 | inode = igrab(mark->inode); |
84 | if (inode) { | 84 | if (inode) { |
85 | seq_printf(m, "inotify wd:%x ino:%lx sdev:%x mask:%x ignored_mask:%x ", | 85 | seq_printf(m, "inotify wd:%x ino:%lx sdev:%x mask:%x ignored_mask:%x ", |
86 | inode_mark->wd, inode->i_ino, inode->i_sb->s_dev, | 86 | inode_mark->wd, inode->i_ino, inode->i_sb->s_dev, |
@@ -112,7 +112,7 @@ static void fanotify_fdinfo(struct seq_file *m, struct fsnotify_mark *mark) | |||
112 | mflags |= FAN_MARK_IGNORED_SURV_MODIFY; | 112 | mflags |= FAN_MARK_IGNORED_SURV_MODIFY; |
113 | 113 | ||
114 | if (mark->flags & FSNOTIFY_MARK_FLAG_INODE) { | 114 | if (mark->flags & FSNOTIFY_MARK_FLAG_INODE) { |
115 | inode = igrab(mark->i.inode); | 115 | inode = igrab(mark->inode); |
116 | if (!inode) | 116 | if (!inode) |
117 | return; | 117 | return; |
118 | seq_printf(m, "fanotify ino:%lx sdev:%x mflags:%x mask:%x ignored_mask:%x ", | 118 | seq_printf(m, "fanotify ino:%lx sdev:%x mflags:%x mask:%x ignored_mask:%x ", |
@@ -122,7 +122,7 @@ static void fanotify_fdinfo(struct seq_file *m, struct fsnotify_mark *mark) | |||
122 | seq_putc(m, '\n'); | 122 | seq_putc(m, '\n'); |
123 | iput(inode); | 123 | iput(inode); |
124 | } else if (mark->flags & FSNOTIFY_MARK_FLAG_VFSMOUNT) { | 124 | } else if (mark->flags & FSNOTIFY_MARK_FLAG_VFSMOUNT) { |
125 | struct mount *mnt = real_mount(mark->m.mnt); | 125 | struct mount *mnt = real_mount(mark->mnt); |
126 | 126 | ||
127 | seq_printf(m, "fanotify mnt_id:%x mflags:%x mask:%x ignored_mask:%x\n", | 127 | seq_printf(m, "fanotify mnt_id:%x mflags:%x mask:%x ignored_mask:%x\n", |
128 | mnt->mnt_id, mflags, mark->mask, mark->ignored_mask); | 128 | mnt->mnt_id, mflags, mark->mask, mark->ignored_mask); |
diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c index 41e39102743a..dd3fb0b17be7 100644 --- a/fs/notify/fsnotify.c +++ b/fs/notify/fsnotify.c | |||
@@ -242,13 +242,13 @@ int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, | |||
242 | 242 | ||
243 | if (inode_node) { | 243 | if (inode_node) { |
244 | inode_mark = hlist_entry(srcu_dereference(inode_node, &fsnotify_mark_srcu), | 244 | inode_mark = hlist_entry(srcu_dereference(inode_node, &fsnotify_mark_srcu), |
245 | struct fsnotify_mark, i.i_list); | 245 | struct fsnotify_mark, obj_list); |
246 | inode_group = inode_mark->group; | 246 | inode_group = inode_mark->group; |
247 | } | 247 | } |
248 | 248 | ||
249 | if (vfsmount_node) { | 249 | if (vfsmount_node) { |
250 | vfsmount_mark = hlist_entry(srcu_dereference(vfsmount_node, &fsnotify_mark_srcu), | 250 | vfsmount_mark = hlist_entry(srcu_dereference(vfsmount_node, &fsnotify_mark_srcu), |
251 | struct fsnotify_mark, m.m_list); | 251 | struct fsnotify_mark, obj_list); |
252 | vfsmount_group = vfsmount_mark->group; | 252 | vfsmount_group = vfsmount_mark->group; |
253 | } | 253 | } |
254 | 254 | ||
diff --git a/fs/notify/fsnotify.h b/fs/notify/fsnotify.h index 3b68b0ae0a97..13a00be516d2 100644 --- a/fs/notify/fsnotify.h +++ b/fs/notify/fsnotify.h | |||
@@ -12,12 +12,19 @@ extern void fsnotify_flush_notify(struct fsnotify_group *group); | |||
12 | /* protects reads of inode and vfsmount marks list */ | 12 | /* protects reads of inode and vfsmount marks list */ |
13 | extern struct srcu_struct fsnotify_mark_srcu; | 13 | extern struct srcu_struct fsnotify_mark_srcu; |
14 | 14 | ||
15 | /* Calculate mask of events for a list of marks */ | ||
16 | extern u32 fsnotify_recalc_mask(struct hlist_head *head); | ||
17 | |||
15 | /* compare two groups for sorting of marks lists */ | 18 | /* compare two groups for sorting of marks lists */ |
16 | extern int fsnotify_compare_groups(struct fsnotify_group *a, | 19 | extern int fsnotify_compare_groups(struct fsnotify_group *a, |
17 | struct fsnotify_group *b); | 20 | struct fsnotify_group *b); |
18 | 21 | ||
19 | extern void fsnotify_set_inode_mark_mask_locked(struct fsnotify_mark *fsn_mark, | 22 | extern void fsnotify_set_inode_mark_mask_locked(struct fsnotify_mark *fsn_mark, |
20 | __u32 mask); | 23 | __u32 mask); |
24 | /* Add mark to a proper place in mark list */ | ||
25 | extern int fsnotify_add_mark_list(struct hlist_head *head, | ||
26 | struct fsnotify_mark *mark, | ||
27 | int allow_dups); | ||
21 | /* add a mark to an inode */ | 28 | /* add a mark to an inode */ |
22 | extern int fsnotify_add_inode_mark(struct fsnotify_mark *mark, | 29 | extern int fsnotify_add_inode_mark(struct fsnotify_mark *mark, |
23 | struct fsnotify_group *group, struct inode *inode, | 30 | struct fsnotify_group *group, struct inode *inode, |
@@ -31,6 +38,11 @@ extern int fsnotify_add_vfsmount_mark(struct fsnotify_mark *mark, | |||
31 | extern void fsnotify_destroy_vfsmount_mark(struct fsnotify_mark *mark); | 38 | extern void fsnotify_destroy_vfsmount_mark(struct fsnotify_mark *mark); |
32 | /* inode specific destruction of a mark */ | 39 | /* inode specific destruction of a mark */ |
33 | extern void fsnotify_destroy_inode_mark(struct fsnotify_mark *mark); | 40 | extern void fsnotify_destroy_inode_mark(struct fsnotify_mark *mark); |
41 | /* Destroy all marks in the given list */ | ||
42 | extern void fsnotify_destroy_marks(struct list_head *to_free); | ||
43 | /* Find mark belonging to given group in the list of marks */ | ||
44 | extern struct fsnotify_mark *fsnotify_find_mark(struct hlist_head *head, | ||
45 | struct fsnotify_group *group); | ||
34 | /* run the list of all marks associated with inode and flag them to be freed */ | 46 | /* run the list of all marks associated with inode and flag them to be freed */ |
35 | extern void fsnotify_clear_marks_by_inode(struct inode *inode); | 47 | extern void fsnotify_clear_marks_by_inode(struct inode *inode); |
36 | /* run the list of all marks associated with vfsmount and flag them to be freed */ | 48 | /* run the list of all marks associated with vfsmount and flag them to be freed */ |
diff --git a/fs/notify/inode_mark.c b/fs/notify/inode_mark.c index dfbf5447eea4..3daf513ee99e 100644 --- a/fs/notify/inode_mark.c +++ b/fs/notify/inode_mark.c | |||
@@ -31,28 +31,13 @@ | |||
31 | #include "../internal.h" | 31 | #include "../internal.h" |
32 | 32 | ||
33 | /* | 33 | /* |
34 | * Recalculate the mask of events relevant to a given inode locked. | ||
35 | */ | ||
36 | static void fsnotify_recalc_inode_mask_locked(struct inode *inode) | ||
37 | { | ||
38 | struct fsnotify_mark *mark; | ||
39 | __u32 new_mask = 0; | ||
40 | |||
41 | assert_spin_locked(&inode->i_lock); | ||
42 | |||
43 | hlist_for_each_entry(mark, &inode->i_fsnotify_marks, i.i_list) | ||
44 | new_mask |= mark->mask; | ||
45 | inode->i_fsnotify_mask = new_mask; | ||
46 | } | ||
47 | |||
48 | /* | ||
49 | * Recalculate the inode->i_fsnotify_mask, or the mask of all FS_* event types | 34 | * Recalculate the inode->i_fsnotify_mask, or the mask of all FS_* event types |
50 | * any notifier is interested in hearing for this inode. | 35 | * any notifier is interested in hearing for this inode. |
51 | */ | 36 | */ |
52 | void fsnotify_recalc_inode_mask(struct inode *inode) | 37 | void fsnotify_recalc_inode_mask(struct inode *inode) |
53 | { | 38 | { |
54 | spin_lock(&inode->i_lock); | 39 | spin_lock(&inode->i_lock); |
55 | fsnotify_recalc_inode_mask_locked(inode); | 40 | inode->i_fsnotify_mask = fsnotify_recalc_mask(&inode->i_fsnotify_marks); |
56 | spin_unlock(&inode->i_lock); | 41 | spin_unlock(&inode->i_lock); |
57 | 42 | ||
58 | __fsnotify_update_child_dentry_flags(inode); | 43 | __fsnotify_update_child_dentry_flags(inode); |
@@ -60,23 +45,22 @@ void fsnotify_recalc_inode_mask(struct inode *inode) | |||
60 | 45 | ||
61 | void fsnotify_destroy_inode_mark(struct fsnotify_mark *mark) | 46 | void fsnotify_destroy_inode_mark(struct fsnotify_mark *mark) |
62 | { | 47 | { |
63 | struct inode *inode = mark->i.inode; | 48 | struct inode *inode = mark->inode; |
64 | 49 | ||
65 | BUG_ON(!mutex_is_locked(&mark->group->mark_mutex)); | 50 | BUG_ON(!mutex_is_locked(&mark->group->mark_mutex)); |
66 | assert_spin_locked(&mark->lock); | 51 | assert_spin_locked(&mark->lock); |
67 | 52 | ||
68 | spin_lock(&inode->i_lock); | 53 | spin_lock(&inode->i_lock); |
69 | 54 | ||
70 | hlist_del_init_rcu(&mark->i.i_list); | 55 | hlist_del_init_rcu(&mark->obj_list); |
71 | mark->i.inode = NULL; | 56 | mark->inode = NULL; |
72 | 57 | ||
73 | /* | 58 | /* |
74 | * this mark is now off the inode->i_fsnotify_marks list and we | 59 | * this mark is now off the inode->i_fsnotify_marks list and we |
75 | * hold the inode->i_lock, so this is the perfect time to update the | 60 | * hold the inode->i_lock, so this is the perfect time to update the |
76 | * inode->i_fsnotify_mask | 61 | * inode->i_fsnotify_mask |
77 | */ | 62 | */ |
78 | fsnotify_recalc_inode_mask_locked(inode); | 63 | inode->i_fsnotify_mask = fsnotify_recalc_mask(&inode->i_fsnotify_marks); |
79 | |||
80 | spin_unlock(&inode->i_lock); | 64 | spin_unlock(&inode->i_lock); |
81 | } | 65 | } |
82 | 66 | ||
@@ -85,30 +69,19 @@ void fsnotify_destroy_inode_mark(struct fsnotify_mark *mark) | |||
85 | */ | 69 | */ |
86 | void fsnotify_clear_marks_by_inode(struct inode *inode) | 70 | void fsnotify_clear_marks_by_inode(struct inode *inode) |
87 | { | 71 | { |
88 | struct fsnotify_mark *mark, *lmark; | 72 | struct fsnotify_mark *mark; |
89 | struct hlist_node *n; | 73 | struct hlist_node *n; |
90 | LIST_HEAD(free_list); | 74 | LIST_HEAD(free_list); |
91 | 75 | ||
92 | spin_lock(&inode->i_lock); | 76 | spin_lock(&inode->i_lock); |
93 | hlist_for_each_entry_safe(mark, n, &inode->i_fsnotify_marks, i.i_list) { | 77 | hlist_for_each_entry_safe(mark, n, &inode->i_fsnotify_marks, obj_list) { |
94 | list_add(&mark->i.free_i_list, &free_list); | 78 | list_add(&mark->free_list, &free_list); |
95 | hlist_del_init_rcu(&mark->i.i_list); | 79 | hlist_del_init_rcu(&mark->obj_list); |
96 | fsnotify_get_mark(mark); | 80 | fsnotify_get_mark(mark); |
97 | } | 81 | } |
98 | spin_unlock(&inode->i_lock); | 82 | spin_unlock(&inode->i_lock); |
99 | 83 | ||
100 | list_for_each_entry_safe(mark, lmark, &free_list, i.free_i_list) { | 84 | fsnotify_destroy_marks(&free_list); |
101 | struct fsnotify_group *group; | ||
102 | |||
103 | spin_lock(&mark->lock); | ||
104 | fsnotify_get_group(mark->group); | ||
105 | group = mark->group; | ||
106 | spin_unlock(&mark->lock); | ||
107 | |||
108 | fsnotify_destroy_mark(mark, group); | ||
109 | fsnotify_put_mark(mark); | ||
110 | fsnotify_put_group(group); | ||
111 | } | ||
112 | } | 85 | } |
113 | 86 | ||
114 | /* | 87 | /* |
@@ -123,34 +96,13 @@ void fsnotify_clear_inode_marks_by_group(struct fsnotify_group *group) | |||
123 | * given a group and inode, find the mark associated with that combination. | 96 | * given a group and inode, find the mark associated with that combination. |
124 | * if found take a reference to that mark and return it, else return NULL | 97 | * if found take a reference to that mark and return it, else return NULL |
125 | */ | 98 | */ |
126 | static struct fsnotify_mark *fsnotify_find_inode_mark_locked( | ||
127 | struct fsnotify_group *group, | ||
128 | struct inode *inode) | ||
129 | { | ||
130 | struct fsnotify_mark *mark; | ||
131 | |||
132 | assert_spin_locked(&inode->i_lock); | ||
133 | |||
134 | hlist_for_each_entry(mark, &inode->i_fsnotify_marks, i.i_list) { | ||
135 | if (mark->group == group) { | ||
136 | fsnotify_get_mark(mark); | ||
137 | return mark; | ||
138 | } | ||
139 | } | ||
140 | return NULL; | ||
141 | } | ||
142 | |||
143 | /* | ||
144 | * given a group and inode, find the mark associated with that combination. | ||
145 | * if found take a reference to that mark and return it, else return NULL | ||
146 | */ | ||
147 | struct fsnotify_mark *fsnotify_find_inode_mark(struct fsnotify_group *group, | 99 | struct fsnotify_mark *fsnotify_find_inode_mark(struct fsnotify_group *group, |
148 | struct inode *inode) | 100 | struct inode *inode) |
149 | { | 101 | { |
150 | struct fsnotify_mark *mark; | 102 | struct fsnotify_mark *mark; |
151 | 103 | ||
152 | spin_lock(&inode->i_lock); | 104 | spin_lock(&inode->i_lock); |
153 | mark = fsnotify_find_inode_mark_locked(group, inode); | 105 | mark = fsnotify_find_mark(&inode->i_fsnotify_marks, group); |
154 | spin_unlock(&inode->i_lock); | 106 | spin_unlock(&inode->i_lock); |
155 | 107 | ||
156 | return mark; | 108 | return mark; |
@@ -168,10 +120,10 @@ void fsnotify_set_inode_mark_mask_locked(struct fsnotify_mark *mark, | |||
168 | assert_spin_locked(&mark->lock); | 120 | assert_spin_locked(&mark->lock); |
169 | 121 | ||
170 | if (mask && | 122 | if (mask && |
171 | mark->i.inode && | 123 | mark->inode && |
172 | !(mark->flags & FSNOTIFY_MARK_FLAG_OBJECT_PINNED)) { | 124 | !(mark->flags & FSNOTIFY_MARK_FLAG_OBJECT_PINNED)) { |
173 | mark->flags |= FSNOTIFY_MARK_FLAG_OBJECT_PINNED; | 125 | mark->flags |= FSNOTIFY_MARK_FLAG_OBJECT_PINNED; |
174 | inode = igrab(mark->i.inode); | 126 | inode = igrab(mark->inode); |
175 | /* | 127 | /* |
176 | * we shouldn't be able to get here if the inode wasn't | 128 | * we shouldn't be able to get here if the inode wasn't |
177 | * already safely held in memory. But bug in case it | 129 | * already safely held in memory. But bug in case it |
@@ -192,9 +144,7 @@ int fsnotify_add_inode_mark(struct fsnotify_mark *mark, | |||
192 | struct fsnotify_group *group, struct inode *inode, | 144 | struct fsnotify_group *group, struct inode *inode, |
193 | int allow_dups) | 145 | int allow_dups) |
194 | { | 146 | { |
195 | struct fsnotify_mark *lmark, *last = NULL; | 147 | int ret; |
196 | int ret = 0; | ||
197 | int cmp; | ||
198 | 148 | ||
199 | mark->flags |= FSNOTIFY_MARK_FLAG_INODE; | 149 | mark->flags |= FSNOTIFY_MARK_FLAG_INODE; |
200 | 150 | ||
@@ -202,37 +152,10 @@ int fsnotify_add_inode_mark(struct fsnotify_mark *mark, | |||
202 | assert_spin_locked(&mark->lock); | 152 | assert_spin_locked(&mark->lock); |
203 | 153 | ||
204 | spin_lock(&inode->i_lock); | 154 | spin_lock(&inode->i_lock); |
205 | 155 | mark->inode = inode; | |
206 | mark->i.inode = inode; | 156 | ret = fsnotify_add_mark_list(&inode->i_fsnotify_marks, mark, |
207 | 157 | allow_dups); | |
208 | /* is mark the first mark? */ | 158 | inode->i_fsnotify_mask = fsnotify_recalc_mask(&inode->i_fsnotify_marks); |
209 | if (hlist_empty(&inode->i_fsnotify_marks)) { | ||
210 | hlist_add_head_rcu(&mark->i.i_list, &inode->i_fsnotify_marks); | ||
211 | goto out; | ||
212 | } | ||
213 | |||
214 | /* should mark be in the middle of the current list? */ | ||
215 | hlist_for_each_entry(lmark, &inode->i_fsnotify_marks, i.i_list) { | ||
216 | last = lmark; | ||
217 | |||
218 | if ((lmark->group == group) && !allow_dups) { | ||
219 | ret = -EEXIST; | ||
220 | goto out; | ||
221 | } | ||
222 | |||
223 | cmp = fsnotify_compare_groups(lmark->group, mark->group); | ||
224 | if (cmp < 0) | ||
225 | continue; | ||
226 | |||
227 | hlist_add_before_rcu(&mark->i.i_list, &lmark->i.i_list); | ||
228 | goto out; | ||
229 | } | ||
230 | |||
231 | BUG_ON(last == NULL); | ||
232 | /* mark should be the last entry. last is the current last entry */ | ||
233 | hlist_add_behind_rcu(&mark->i.i_list, &last->i.i_list); | ||
234 | out: | ||
235 | fsnotify_recalc_inode_mask_locked(inode); | ||
236 | spin_unlock(&inode->i_lock); | 159 | spin_unlock(&inode->i_lock); |
237 | 160 | ||
238 | return ret; | 161 | return ret; |
diff --git a/fs/notify/inotify/inotify_fsnotify.c b/fs/notify/inotify/inotify_fsnotify.c index 7d888d77d59a..2cd900c2c737 100644 --- a/fs/notify/inotify/inotify_fsnotify.c +++ b/fs/notify/inotify/inotify_fsnotify.c | |||
@@ -156,7 +156,7 @@ static int idr_callback(int id, void *p, void *data) | |||
156 | */ | 156 | */ |
157 | if (fsn_mark) | 157 | if (fsn_mark) |
158 | printk(KERN_WARNING "fsn_mark->group=%p inode=%p wd=%d\n", | 158 | printk(KERN_WARNING "fsn_mark->group=%p inode=%p wd=%d\n", |
159 | fsn_mark->group, fsn_mark->i.inode, i_mark->wd); | 159 | fsn_mark->group, fsn_mark->inode, i_mark->wd); |
160 | return 0; | 160 | return 0; |
161 | } | 161 | } |
162 | 162 | ||
diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c index 283aa312d745..450648697433 100644 --- a/fs/notify/inotify/inotify_user.c +++ b/fs/notify/inotify/inotify_user.c | |||
@@ -433,7 +433,7 @@ static void inotify_remove_from_idr(struct fsnotify_group *group, | |||
433 | if (wd == -1) { | 433 | if (wd == -1) { |
434 | WARN_ONCE(1, "%s: i_mark=%p i_mark->wd=%d i_mark->group=%p" | 434 | WARN_ONCE(1, "%s: i_mark=%p i_mark->wd=%d i_mark->group=%p" |
435 | " i_mark->inode=%p\n", __func__, i_mark, i_mark->wd, | 435 | " i_mark->inode=%p\n", __func__, i_mark, i_mark->wd, |
436 | i_mark->fsn_mark.group, i_mark->fsn_mark.i.inode); | 436 | i_mark->fsn_mark.group, i_mark->fsn_mark.inode); |
437 | goto out; | 437 | goto out; |
438 | } | 438 | } |
439 | 439 | ||
@@ -442,7 +442,7 @@ static void inotify_remove_from_idr(struct fsnotify_group *group, | |||
442 | if (unlikely(!found_i_mark)) { | 442 | if (unlikely(!found_i_mark)) { |
443 | WARN_ONCE(1, "%s: i_mark=%p i_mark->wd=%d i_mark->group=%p" | 443 | WARN_ONCE(1, "%s: i_mark=%p i_mark->wd=%d i_mark->group=%p" |
444 | " i_mark->inode=%p\n", __func__, i_mark, i_mark->wd, | 444 | " i_mark->inode=%p\n", __func__, i_mark, i_mark->wd, |
445 | i_mark->fsn_mark.group, i_mark->fsn_mark.i.inode); | 445 | i_mark->fsn_mark.group, i_mark->fsn_mark.inode); |
446 | goto out; | 446 | goto out; |
447 | } | 447 | } |
448 | 448 | ||
@@ -456,9 +456,9 @@ static void inotify_remove_from_idr(struct fsnotify_group *group, | |||
456 | "mark->inode=%p found_i_mark=%p found_i_mark->wd=%d " | 456 | "mark->inode=%p found_i_mark=%p found_i_mark->wd=%d " |
457 | "found_i_mark->group=%p found_i_mark->inode=%p\n", | 457 | "found_i_mark->group=%p found_i_mark->inode=%p\n", |
458 | __func__, i_mark, i_mark->wd, i_mark->fsn_mark.group, | 458 | __func__, i_mark, i_mark->wd, i_mark->fsn_mark.group, |
459 | i_mark->fsn_mark.i.inode, found_i_mark, found_i_mark->wd, | 459 | i_mark->fsn_mark.inode, found_i_mark, found_i_mark->wd, |
460 | found_i_mark->fsn_mark.group, | 460 | found_i_mark->fsn_mark.group, |
461 | found_i_mark->fsn_mark.i.inode); | 461 | found_i_mark->fsn_mark.inode); |
462 | goto out; | 462 | goto out; |
463 | } | 463 | } |
464 | 464 | ||
@@ -470,7 +470,7 @@ static void inotify_remove_from_idr(struct fsnotify_group *group, | |||
470 | if (unlikely(atomic_read(&i_mark->fsn_mark.refcnt) < 3)) { | 470 | if (unlikely(atomic_read(&i_mark->fsn_mark.refcnt) < 3)) { |
471 | printk(KERN_ERR "%s: i_mark=%p i_mark->wd=%d i_mark->group=%p" | 471 | printk(KERN_ERR "%s: i_mark=%p i_mark->wd=%d i_mark->group=%p" |
472 | " i_mark->inode=%p\n", __func__, i_mark, i_mark->wd, | 472 | " i_mark->inode=%p\n", __func__, i_mark, i_mark->wd, |
473 | i_mark->fsn_mark.group, i_mark->fsn_mark.i.inode); | 473 | i_mark->fsn_mark.group, i_mark->fsn_mark.inode); |
474 | /* we can't really recover with bad ref cnting.. */ | 474 | /* we can't really recover with bad ref cnting.. */ |
475 | BUG(); | 475 | BUG(); |
476 | } | 476 | } |
diff --git a/fs/notify/mark.c b/fs/notify/mark.c index 34c38fabf514..92e48c70f0f0 100644 --- a/fs/notify/mark.c +++ b/fs/notify/mark.c | |||
@@ -110,6 +110,17 @@ void fsnotify_put_mark(struct fsnotify_mark *mark) | |||
110 | } | 110 | } |
111 | } | 111 | } |
112 | 112 | ||
113 | /* Calculate mask of events for a list of marks */ | ||
114 | u32 fsnotify_recalc_mask(struct hlist_head *head) | ||
115 | { | ||
116 | u32 new_mask = 0; | ||
117 | struct fsnotify_mark *mark; | ||
118 | |||
119 | hlist_for_each_entry(mark, head, obj_list) | ||
120 | new_mask |= mark->mask; | ||
121 | return new_mask; | ||
122 | } | ||
123 | |||
113 | /* | 124 | /* |
114 | * Any time a mark is getting freed we end up here. | 125 | * Any time a mark is getting freed we end up here. |
115 | * The caller had better be holding a reference to this mark so we don't actually | 126 | * The caller had better be holding a reference to this mark so we don't actually |
@@ -133,7 +144,7 @@ void fsnotify_destroy_mark_locked(struct fsnotify_mark *mark, | |||
133 | mark->flags &= ~FSNOTIFY_MARK_FLAG_ALIVE; | 144 | mark->flags &= ~FSNOTIFY_MARK_FLAG_ALIVE; |
134 | 145 | ||
135 | if (mark->flags & FSNOTIFY_MARK_FLAG_INODE) { | 146 | if (mark->flags & FSNOTIFY_MARK_FLAG_INODE) { |
136 | inode = mark->i.inode; | 147 | inode = mark->inode; |
137 | fsnotify_destroy_inode_mark(mark); | 148 | fsnotify_destroy_inode_mark(mark); |
138 | } else if (mark->flags & FSNOTIFY_MARK_FLAG_VFSMOUNT) | 149 | } else if (mark->flags & FSNOTIFY_MARK_FLAG_VFSMOUNT) |
139 | fsnotify_destroy_vfsmount_mark(mark); | 150 | fsnotify_destroy_vfsmount_mark(mark); |
@@ -150,7 +161,7 @@ void fsnotify_destroy_mark_locked(struct fsnotify_mark *mark, | |||
150 | mutex_unlock(&group->mark_mutex); | 161 | mutex_unlock(&group->mark_mutex); |
151 | 162 | ||
152 | spin_lock(&destroy_lock); | 163 | spin_lock(&destroy_lock); |
153 | list_add(&mark->destroy_list, &destroy_list); | 164 | list_add(&mark->g_list, &destroy_list); |
154 | spin_unlock(&destroy_lock); | 165 | spin_unlock(&destroy_lock); |
155 | wake_up(&destroy_waitq); | 166 | wake_up(&destroy_waitq); |
156 | /* | 167 | /* |
@@ -192,6 +203,27 @@ void fsnotify_destroy_mark(struct fsnotify_mark *mark, | |||
192 | mutex_unlock(&group->mark_mutex); | 203 | mutex_unlock(&group->mark_mutex); |
193 | } | 204 | } |
194 | 205 | ||
206 | /* | ||
207 | * Destroy all marks in the given list. The marks must be already detached from | ||
208 | * the original inode / vfsmount. | ||
209 | */ | ||
210 | void fsnotify_destroy_marks(struct list_head *to_free) | ||
211 | { | ||
212 | struct fsnotify_mark *mark, *lmark; | ||
213 | struct fsnotify_group *group; | ||
214 | |||
215 | list_for_each_entry_safe(mark, lmark, to_free, free_list) { | ||
216 | spin_lock(&mark->lock); | ||
217 | fsnotify_get_group(mark->group); | ||
218 | group = mark->group; | ||
219 | spin_unlock(&mark->lock); | ||
220 | |||
221 | fsnotify_destroy_mark(mark, group); | ||
222 | fsnotify_put_mark(mark); | ||
223 | fsnotify_put_group(group); | ||
224 | } | ||
225 | } | ||
226 | |||
195 | void fsnotify_set_mark_mask_locked(struct fsnotify_mark *mark, __u32 mask) | 227 | void fsnotify_set_mark_mask_locked(struct fsnotify_mark *mark, __u32 mask) |
196 | { | 228 | { |
197 | assert_spin_locked(&mark->lock); | 229 | assert_spin_locked(&mark->lock); |
@@ -245,6 +277,39 @@ int fsnotify_compare_groups(struct fsnotify_group *a, struct fsnotify_group *b) | |||
245 | return -1; | 277 | return -1; |
246 | } | 278 | } |
247 | 279 | ||
280 | /* Add mark into proper place in given list of marks */ | ||
281 | int fsnotify_add_mark_list(struct hlist_head *head, struct fsnotify_mark *mark, | ||
282 | int allow_dups) | ||
283 | { | ||
284 | struct fsnotify_mark *lmark, *last = NULL; | ||
285 | int cmp; | ||
286 | |||
287 | /* is mark the first mark? */ | ||
288 | if (hlist_empty(head)) { | ||
289 | hlist_add_head_rcu(&mark->obj_list, head); | ||
290 | return 0; | ||
291 | } | ||
292 | |||
293 | /* should mark be in the middle of the current list? */ | ||
294 | hlist_for_each_entry(lmark, head, obj_list) { | ||
295 | last = lmark; | ||
296 | |||
297 | if ((lmark->group == mark->group) && !allow_dups) | ||
298 | return -EEXIST; | ||
299 | |||
300 | cmp = fsnotify_compare_groups(lmark->group, mark->group); | ||
301 | if (cmp >= 0) { | ||
302 | hlist_add_before_rcu(&mark->obj_list, &lmark->obj_list); | ||
303 | return 0; | ||
304 | } | ||
305 | } | ||
306 | |||
307 | BUG_ON(last == NULL); | ||
308 | /* mark should be the last entry. last is the current last entry */ | ||
309 | hlist_add_behind_rcu(&mark->obj_list, &last->obj_list); | ||
310 | return 0; | ||
311 | } | ||
312 | |||
248 | /* | 313 | /* |
249 | * Attach an initialized mark to a given group and fs object. | 314 | * Attach an initialized mark to a given group and fs object. |
250 | * These marks may be used for the fsnotify backend to determine which | 315 | * These marks may be used for the fsnotify backend to determine which |
@@ -305,7 +370,7 @@ err: | |||
305 | spin_unlock(&mark->lock); | 370 | spin_unlock(&mark->lock); |
306 | 371 | ||
307 | spin_lock(&destroy_lock); | 372 | spin_lock(&destroy_lock); |
308 | list_add(&mark->destroy_list, &destroy_list); | 373 | list_add(&mark->g_list, &destroy_list); |
309 | spin_unlock(&destroy_lock); | 374 | spin_unlock(&destroy_lock); |
310 | wake_up(&destroy_waitq); | 375 | wake_up(&destroy_waitq); |
311 | 376 | ||
@@ -323,6 +388,24 @@ int fsnotify_add_mark(struct fsnotify_mark *mark, struct fsnotify_group *group, | |||
323 | } | 388 | } |
324 | 389 | ||
325 | /* | 390 | /* |
391 | * Given a list of marks, find the mark associated with given group. If found | ||
392 | * take a reference to that mark and return it, else return NULL. | ||
393 | */ | ||
394 | struct fsnotify_mark *fsnotify_find_mark(struct hlist_head *head, | ||
395 | struct fsnotify_group *group) | ||
396 | { | ||
397 | struct fsnotify_mark *mark; | ||
398 | |||
399 | hlist_for_each_entry(mark, head, obj_list) { | ||
400 | if (mark->group == group) { | ||
401 | fsnotify_get_mark(mark); | ||
402 | return mark; | ||
403 | } | ||
404 | } | ||
405 | return NULL; | ||
406 | } | ||
407 | |||
408 | /* | ||
326 | * clear any marks in a group in which mark->flags & flags is true | 409 | * clear any marks in a group in which mark->flags & flags is true |
327 | */ | 410 | */ |
328 | void fsnotify_clear_marks_by_group_flags(struct fsnotify_group *group, | 411 | void fsnotify_clear_marks_by_group_flags(struct fsnotify_group *group, |
@@ -352,8 +435,8 @@ void fsnotify_clear_marks_by_group(struct fsnotify_group *group) | |||
352 | void fsnotify_duplicate_mark(struct fsnotify_mark *new, struct fsnotify_mark *old) | 435 | void fsnotify_duplicate_mark(struct fsnotify_mark *new, struct fsnotify_mark *old) |
353 | { | 436 | { |
354 | assert_spin_locked(&old->lock); | 437 | assert_spin_locked(&old->lock); |
355 | new->i.inode = old->i.inode; | 438 | new->inode = old->inode; |
356 | new->m.mnt = old->m.mnt; | 439 | new->mnt = old->mnt; |
357 | if (old->group) | 440 | if (old->group) |
358 | fsnotify_get_group(old->group); | 441 | fsnotify_get_group(old->group); |
359 | new->group = old->group; | 442 | new->group = old->group; |
@@ -386,8 +469,8 @@ static int fsnotify_mark_destroy(void *ignored) | |||
386 | 469 | ||
387 | synchronize_srcu(&fsnotify_mark_srcu); | 470 | synchronize_srcu(&fsnotify_mark_srcu); |
388 | 471 | ||
389 | list_for_each_entry_safe(mark, next, &private_destroy_list, destroy_list) { | 472 | list_for_each_entry_safe(mark, next, &private_destroy_list, g_list) { |
390 | list_del_init(&mark->destroy_list); | 473 | list_del_init(&mark->g_list); |
391 | fsnotify_put_mark(mark); | 474 | fsnotify_put_mark(mark); |
392 | } | 475 | } |
393 | 476 | ||
diff --git a/fs/notify/vfsmount_mark.c b/fs/notify/vfsmount_mark.c index faefa72a11eb..326b148e623c 100644 --- a/fs/notify/vfsmount_mark.c +++ b/fs/notify/vfsmount_mark.c | |||
@@ -32,31 +32,20 @@ | |||
32 | 32 | ||
33 | void fsnotify_clear_marks_by_mount(struct vfsmount *mnt) | 33 | void fsnotify_clear_marks_by_mount(struct vfsmount *mnt) |
34 | { | 34 | { |
35 | struct fsnotify_mark *mark, *lmark; | 35 | struct fsnotify_mark *mark; |
36 | struct hlist_node *n; | 36 | struct hlist_node *n; |
37 | struct mount *m = real_mount(mnt); | 37 | struct mount *m = real_mount(mnt); |
38 | LIST_HEAD(free_list); | 38 | LIST_HEAD(free_list); |
39 | 39 | ||
40 | spin_lock(&mnt->mnt_root->d_lock); | 40 | spin_lock(&mnt->mnt_root->d_lock); |
41 | hlist_for_each_entry_safe(mark, n, &m->mnt_fsnotify_marks, m.m_list) { | 41 | hlist_for_each_entry_safe(mark, n, &m->mnt_fsnotify_marks, obj_list) { |
42 | list_add(&mark->m.free_m_list, &free_list); | 42 | list_add(&mark->free_list, &free_list); |
43 | hlist_del_init_rcu(&mark->m.m_list); | 43 | hlist_del_init_rcu(&mark->obj_list); |
44 | fsnotify_get_mark(mark); | 44 | fsnotify_get_mark(mark); |
45 | } | 45 | } |
46 | spin_unlock(&mnt->mnt_root->d_lock); | 46 | spin_unlock(&mnt->mnt_root->d_lock); |
47 | 47 | ||
48 | list_for_each_entry_safe(mark, lmark, &free_list, m.free_m_list) { | 48 | fsnotify_destroy_marks(&free_list); |
49 | struct fsnotify_group *group; | ||
50 | |||
51 | spin_lock(&mark->lock); | ||
52 | fsnotify_get_group(mark->group); | ||
53 | group = mark->group; | ||
54 | spin_unlock(&mark->lock); | ||
55 | |||
56 | fsnotify_destroy_mark(mark, group); | ||
57 | fsnotify_put_mark(mark); | ||
58 | fsnotify_put_group(group); | ||
59 | } | ||
60 | } | 49 | } |
61 | 50 | ||
62 | void fsnotify_clear_vfsmount_marks_by_group(struct fsnotify_group *group) | 51 | void fsnotify_clear_vfsmount_marks_by_group(struct fsnotify_group *group) |
@@ -65,66 +54,35 @@ void fsnotify_clear_vfsmount_marks_by_group(struct fsnotify_group *group) | |||
65 | } | 54 | } |
66 | 55 | ||
67 | /* | 56 | /* |
68 | * Recalculate the mask of events relevant to a given vfsmount locked. | ||
69 | */ | ||
70 | static void fsnotify_recalc_vfsmount_mask_locked(struct vfsmount *mnt) | ||
71 | { | ||
72 | struct mount *m = real_mount(mnt); | ||
73 | struct fsnotify_mark *mark; | ||
74 | __u32 new_mask = 0; | ||
75 | |||
76 | assert_spin_locked(&mnt->mnt_root->d_lock); | ||
77 | |||
78 | hlist_for_each_entry(mark, &m->mnt_fsnotify_marks, m.m_list) | ||
79 | new_mask |= mark->mask; | ||
80 | m->mnt_fsnotify_mask = new_mask; | ||
81 | } | ||
82 | |||
83 | /* | ||
84 | * Recalculate the mnt->mnt_fsnotify_mask, or the mask of all FS_* event types | 57 | * Recalculate the mnt->mnt_fsnotify_mask, or the mask of all FS_* event types |
85 | * any notifier is interested in hearing for this mount point | 58 | * any notifier is interested in hearing for this mount point |
86 | */ | 59 | */ |
87 | void fsnotify_recalc_vfsmount_mask(struct vfsmount *mnt) | 60 | void fsnotify_recalc_vfsmount_mask(struct vfsmount *mnt) |
88 | { | 61 | { |
62 | struct mount *m = real_mount(mnt); | ||
63 | |||
89 | spin_lock(&mnt->mnt_root->d_lock); | 64 | spin_lock(&mnt->mnt_root->d_lock); |
90 | fsnotify_recalc_vfsmount_mask_locked(mnt); | 65 | m->mnt_fsnotify_mask = fsnotify_recalc_mask(&m->mnt_fsnotify_marks); |
91 | spin_unlock(&mnt->mnt_root->d_lock); | 66 | spin_unlock(&mnt->mnt_root->d_lock); |
92 | } | 67 | } |
93 | 68 | ||
94 | void fsnotify_destroy_vfsmount_mark(struct fsnotify_mark *mark) | 69 | void fsnotify_destroy_vfsmount_mark(struct fsnotify_mark *mark) |
95 | { | 70 | { |
96 | struct vfsmount *mnt = mark->m.mnt; | 71 | struct vfsmount *mnt = mark->mnt; |
72 | struct mount *m = real_mount(mnt); | ||
97 | 73 | ||
98 | BUG_ON(!mutex_is_locked(&mark->group->mark_mutex)); | 74 | BUG_ON(!mutex_is_locked(&mark->group->mark_mutex)); |
99 | assert_spin_locked(&mark->lock); | 75 | assert_spin_locked(&mark->lock); |
100 | 76 | ||
101 | spin_lock(&mnt->mnt_root->d_lock); | 77 | spin_lock(&mnt->mnt_root->d_lock); |
102 | 78 | ||
103 | hlist_del_init_rcu(&mark->m.m_list); | 79 | hlist_del_init_rcu(&mark->obj_list); |
104 | mark->m.mnt = NULL; | 80 | mark->mnt = NULL; |
105 | |||
106 | fsnotify_recalc_vfsmount_mask_locked(mnt); | ||
107 | 81 | ||
82 | m->mnt_fsnotify_mask = fsnotify_recalc_mask(&m->mnt_fsnotify_marks); | ||
108 | spin_unlock(&mnt->mnt_root->d_lock); | 83 | spin_unlock(&mnt->mnt_root->d_lock); |
109 | } | 84 | } |
110 | 85 | ||
111 | static struct fsnotify_mark *fsnotify_find_vfsmount_mark_locked(struct fsnotify_group *group, | ||
112 | struct vfsmount *mnt) | ||
113 | { | ||
114 | struct mount *m = real_mount(mnt); | ||
115 | struct fsnotify_mark *mark; | ||
116 | |||
117 | assert_spin_locked(&mnt->mnt_root->d_lock); | ||
118 | |||
119 | hlist_for_each_entry(mark, &m->mnt_fsnotify_marks, m.m_list) { | ||
120 | if (mark->group == group) { | ||
121 | fsnotify_get_mark(mark); | ||
122 | return mark; | ||
123 | } | ||
124 | } | ||
125 | return NULL; | ||
126 | } | ||
127 | |||
128 | /* | 86 | /* |
129 | * given a group and vfsmount, find the mark associated with that combination. | 87 | * given a group and vfsmount, find the mark associated with that combination. |
130 | * if found take a reference to that mark and return it, else return NULL | 88 | * if found take a reference to that mark and return it, else return NULL |
@@ -132,10 +90,11 @@ static struct fsnotify_mark *fsnotify_find_vfsmount_mark_locked(struct fsnotify_ | |||
132 | struct fsnotify_mark *fsnotify_find_vfsmount_mark(struct fsnotify_group *group, | 90 | struct fsnotify_mark *fsnotify_find_vfsmount_mark(struct fsnotify_group *group, |
133 | struct vfsmount *mnt) | 91 | struct vfsmount *mnt) |
134 | { | 92 | { |
93 | struct mount *m = real_mount(mnt); | ||
135 | struct fsnotify_mark *mark; | 94 | struct fsnotify_mark *mark; |
136 | 95 | ||
137 | spin_lock(&mnt->mnt_root->d_lock); | 96 | spin_lock(&mnt->mnt_root->d_lock); |
138 | mark = fsnotify_find_vfsmount_mark_locked(group, mnt); | 97 | mark = fsnotify_find_mark(&m->mnt_fsnotify_marks, group); |
139 | spin_unlock(&mnt->mnt_root->d_lock); | 98 | spin_unlock(&mnt->mnt_root->d_lock); |
140 | 99 | ||
141 | return mark; | 100 | return mark; |
@@ -151,9 +110,7 @@ int fsnotify_add_vfsmount_mark(struct fsnotify_mark *mark, | |||
151 | int allow_dups) | 110 | int allow_dups) |
152 | { | 111 | { |
153 | struct mount *m = real_mount(mnt); | 112 | struct mount *m = real_mount(mnt); |
154 | struct fsnotify_mark *lmark, *last = NULL; | 113 | int ret; |
155 | int ret = 0; | ||
156 | int cmp; | ||
157 | 114 | ||
158 | mark->flags |= FSNOTIFY_MARK_FLAG_VFSMOUNT; | 115 | mark->flags |= FSNOTIFY_MARK_FLAG_VFSMOUNT; |
159 | 116 | ||
@@ -161,37 +118,9 @@ int fsnotify_add_vfsmount_mark(struct fsnotify_mark *mark, | |||
161 | assert_spin_locked(&mark->lock); | 118 | assert_spin_locked(&mark->lock); |
162 | 119 | ||
163 | spin_lock(&mnt->mnt_root->d_lock); | 120 | spin_lock(&mnt->mnt_root->d_lock); |
164 | 121 | mark->mnt = mnt; | |
165 | mark->m.mnt = mnt; | 122 | ret = fsnotify_add_mark_list(&m->mnt_fsnotify_marks, mark, allow_dups); |
166 | 123 | m->mnt_fsnotify_mask = fsnotify_recalc_mask(&m->mnt_fsnotify_marks); | |
167 | /* is mark the first mark? */ | ||
168 | if (hlist_empty(&m->mnt_fsnotify_marks)) { | ||
169 | hlist_add_head_rcu(&mark->m.m_list, &m->mnt_fsnotify_marks); | ||
170 | goto out; | ||
171 | } | ||
172 | |||
173 | /* should mark be in the middle of the current list? */ | ||
174 | hlist_for_each_entry(lmark, &m->mnt_fsnotify_marks, m.m_list) { | ||
175 | last = lmark; | ||
176 | |||
177 | if ((lmark->group == group) && !allow_dups) { | ||
178 | ret = -EEXIST; | ||
179 | goto out; | ||
180 | } | ||
181 | |||
182 | cmp = fsnotify_compare_groups(lmark->group, mark->group); | ||
183 | if (cmp < 0) | ||
184 | continue; | ||
185 | |||
186 | hlist_add_before_rcu(&mark->m.m_list, &lmark->m.m_list); | ||
187 | goto out; | ||
188 | } | ||
189 | |||
190 | BUG_ON(last == NULL); | ||
191 | /* mark should be the last entry. last is the current last entry */ | ||
192 | hlist_add_behind_rcu(&mark->m.m_list, &last->m.m_list); | ||
193 | out: | ||
194 | fsnotify_recalc_vfsmount_mask_locked(mnt); | ||
195 | spin_unlock(&mnt->mnt_root->d_lock); | 124 | spin_unlock(&mnt->mnt_root->d_lock); |
196 | 125 | ||
197 | return ret; | 126 | return ret; |
@@ -295,6 +295,17 @@ int do_fallocate(struct file *file, int mode, loff_t offset, loff_t len) | |||
295 | 295 | ||
296 | sb_start_write(inode->i_sb); | 296 | sb_start_write(inode->i_sb); |
297 | ret = file->f_op->fallocate(file, mode, offset, len); | 297 | ret = file->f_op->fallocate(file, mode, offset, len); |
298 | |||
299 | /* | ||
300 | * Create inotify and fanotify events. | ||
301 | * | ||
302 | * To keep the logic simple always create events if fallocate succeeds. | ||
303 | * This implies that events are even created if the file size remains | ||
304 | * unchanged, e.g. when using flag FALLOC_FL_KEEP_SIZE. | ||
305 | */ | ||
306 | if (ret == 0) | ||
307 | fsnotify_modify(file); | ||
308 | |||
298 | sb_end_write(inode->i_sb); | 309 | sb_end_write(inode->i_sb); |
299 | return ret; | 310 | return ret; |
300 | } | 311 | } |
diff --git a/fs/seq_file.c b/fs/seq_file.c index 353948ba1c5b..dbf3a59c86bb 100644 --- a/fs/seq_file.c +++ b/fs/seq_file.c | |||
@@ -25,7 +25,11 @@ static void *seq_buf_alloc(unsigned long size) | |||
25 | { | 25 | { |
26 | void *buf; | 26 | void *buf; |
27 | 27 | ||
28 | buf = kmalloc(size, GFP_KERNEL | __GFP_NOWARN); | 28 | /* |
29 | * __GFP_NORETRY to avoid oom-killings with high-order allocations - | ||
30 | * it's better to fall back to vmalloc() than to kill things. | ||
31 | */ | ||
32 | buf = kmalloc(size, GFP_KERNEL | __GFP_NORETRY | __GFP_NOWARN); | ||
29 | if (!buf && size > PAGE_SIZE) | 33 | if (!buf && size > PAGE_SIZE) |
30 | buf = vmalloc(size); | 34 | buf = vmalloc(size); |
31 | return buf; | 35 | return buf; |