diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-04-20 12:01:26 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-04-20 12:01:26 -0400 |
| commit | 0d9cf33b4aabd8de03f80659ceae967ba2b3ba30 (patch) | |
| tree | 2e3ed6e9d9e1a43742714f472480eddc313ee906 /fs | |
| parent | 4d1890531413a19d63cb980fee6d9d3ff86d97ad (diff) | |
| parent | 44f06ba8297c7e9dfd0e49b40cbe119113cca094 (diff) | |
Merge tag 'for_v4.17-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs
- isofs memory leak fix
- two fsnotify fixes of event mask handling
- udf fix of UTF-16 handling
- couple other smaller cleanups
* tag 'for_v4.17-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs:
udf: Fix leak of UTF-16 surrogates into encoded strings
fs: ext2: Adding new return type vm_fault_t
isofs: fix potential memory leak in mount option parsing
MAINTAINERS: add an entry for FSNOTIFY infrastructure
fsnotify: fix typo in a comment about mark->g_list
fsnotify: fix ignore mask logic in send_to_group()
isofs compress: Remove VLA usage
fs: quota: Replace GFP_ATOMIC with GFP_KERNEL in dquot_init
fanotify: fix logic of events on child
Diffstat (limited to 'fs')
| -rw-r--r-- | fs/ext2/file.c | 4 | ||||
| -rw-r--r-- | fs/isofs/compress.c | 19 | ||||
| -rw-r--r-- | fs/isofs/inode.c | 3 | ||||
| -rw-r--r-- | fs/notify/fanotify/fanotify.c | 34 | ||||
| -rw-r--r-- | fs/notify/fsnotify.c | 25 | ||||
| -rw-r--r-- | fs/quota/dquot.c | 2 | ||||
| -rw-r--r-- | fs/udf/unicode.c | 6 |
7 files changed, 54 insertions, 39 deletions
diff --git a/fs/ext2/file.c b/fs/ext2/file.c index 09640220fda8..047c327a6b23 100644 --- a/fs/ext2/file.c +++ b/fs/ext2/file.c | |||
| @@ -88,11 +88,11 @@ out_unlock: | |||
| 88 | * The default page_lock and i_size verification done by non-DAX fault paths | 88 | * The default page_lock and i_size verification done by non-DAX fault paths |
| 89 | * is sufficient because ext2 doesn't support hole punching. | 89 | * is sufficient because ext2 doesn't support hole punching. |
| 90 | */ | 90 | */ |
| 91 | static int ext2_dax_fault(struct vm_fault *vmf) | 91 | static vm_fault_t ext2_dax_fault(struct vm_fault *vmf) |
| 92 | { | 92 | { |
| 93 | struct inode *inode = file_inode(vmf->vma->vm_file); | 93 | struct inode *inode = file_inode(vmf->vma->vm_file); |
| 94 | struct ext2_inode_info *ei = EXT2_I(inode); | 94 | struct ext2_inode_info *ei = EXT2_I(inode); |
| 95 | int ret; | 95 | vm_fault_t ret; |
| 96 | 96 | ||
| 97 | if (vmf->flags & FAULT_FLAG_WRITE) { | 97 | if (vmf->flags & FAULT_FLAG_WRITE) { |
| 98 | sb_start_pagefault(inode->i_sb); | 98 | sb_start_pagefault(inode->i_sb); |
diff --git a/fs/isofs/compress.c b/fs/isofs/compress.c index 9bb2fe35799d..10205ececc27 100644 --- a/fs/isofs/compress.c +++ b/fs/isofs/compress.c | |||
| @@ -20,6 +20,7 @@ | |||
| 20 | #include <linux/init.h> | 20 | #include <linux/init.h> |
| 21 | #include <linux/bio.h> | 21 | #include <linux/bio.h> |
| 22 | 22 | ||
| 23 | #include <linux/slab.h> | ||
| 23 | #include <linux/vmalloc.h> | 24 | #include <linux/vmalloc.h> |
| 24 | #include <linux/zlib.h> | 25 | #include <linux/zlib.h> |
| 25 | 26 | ||
| @@ -59,7 +60,7 @@ static loff_t zisofs_uncompress_block(struct inode *inode, loff_t block_start, | |||
| 59 | >> bufshift; | 60 | >> bufshift; |
| 60 | int haveblocks; | 61 | int haveblocks; |
| 61 | blkcnt_t blocknum; | 62 | blkcnt_t blocknum; |
| 62 | struct buffer_head *bhs[needblocks + 1]; | 63 | struct buffer_head **bhs; |
| 63 | int curbh, curpage; | 64 | int curbh, curpage; |
| 64 | 65 | ||
| 65 | if (block_size > deflateBound(1UL << zisofs_block_shift)) { | 66 | if (block_size > deflateBound(1UL << zisofs_block_shift)) { |
| @@ -80,7 +81,11 @@ static loff_t zisofs_uncompress_block(struct inode *inode, loff_t block_start, | |||
| 80 | 81 | ||
| 81 | /* Because zlib is not thread-safe, do all the I/O at the top. */ | 82 | /* Because zlib is not thread-safe, do all the I/O at the top. */ |
| 82 | blocknum = block_start >> bufshift; | 83 | blocknum = block_start >> bufshift; |
| 83 | memset(bhs, 0, (needblocks + 1) * sizeof(struct buffer_head *)); | 84 | bhs = kcalloc(needblocks + 1, sizeof(*bhs), GFP_KERNEL); |
| 85 | if (!bhs) { | ||
| 86 | *errp = -ENOMEM; | ||
| 87 | return 0; | ||
| 88 | } | ||
| 84 | haveblocks = isofs_get_blocks(inode, blocknum, bhs, needblocks); | 89 | haveblocks = isofs_get_blocks(inode, blocknum, bhs, needblocks); |
| 85 | ll_rw_block(REQ_OP_READ, 0, haveblocks, bhs); | 90 | ll_rw_block(REQ_OP_READ, 0, haveblocks, bhs); |
| 86 | 91 | ||
| @@ -190,6 +195,7 @@ z_eio: | |||
| 190 | b_eio: | 195 | b_eio: |
| 191 | for (i = 0; i < haveblocks; i++) | 196 | for (i = 0; i < haveblocks; i++) |
| 192 | brelse(bhs[i]); | 197 | brelse(bhs[i]); |
| 198 | kfree(bhs); | ||
| 193 | return stream.total_out; | 199 | return stream.total_out; |
| 194 | } | 200 | } |
| 195 | 201 | ||
| @@ -305,7 +311,7 @@ static int zisofs_readpage(struct file *file, struct page *page) | |||
| 305 | unsigned int zisofs_pages_per_cblock = | 311 | unsigned int zisofs_pages_per_cblock = |
| 306 | PAGE_SHIFT <= zisofs_block_shift ? | 312 | PAGE_SHIFT <= zisofs_block_shift ? |
| 307 | (1 << (zisofs_block_shift - PAGE_SHIFT)) : 0; | 313 | (1 << (zisofs_block_shift - PAGE_SHIFT)) : 0; |
| 308 | struct page *pages[max_t(unsigned, zisofs_pages_per_cblock, 1)]; | 314 | struct page **pages; |
| 309 | pgoff_t index = page->index, end_index; | 315 | pgoff_t index = page->index, end_index; |
| 310 | 316 | ||
| 311 | end_index = (inode->i_size + PAGE_SIZE - 1) >> PAGE_SHIFT; | 317 | end_index = (inode->i_size + PAGE_SIZE - 1) >> PAGE_SHIFT; |
| @@ -330,6 +336,12 @@ static int zisofs_readpage(struct file *file, struct page *page) | |||
| 330 | full_page = 0; | 336 | full_page = 0; |
| 331 | pcount = 1; | 337 | pcount = 1; |
| 332 | } | 338 | } |
| 339 | pages = kcalloc(max_t(unsigned int, zisofs_pages_per_cblock, 1), | ||
| 340 | sizeof(*pages), GFP_KERNEL); | ||
| 341 | if (!pages) { | ||
| 342 | unlock_page(page); | ||
| 343 | return -ENOMEM; | ||
| 344 | } | ||
| 333 | pages[full_page] = page; | 345 | pages[full_page] = page; |
| 334 | 346 | ||
| 335 | for (i = 0; i < pcount; i++, index++) { | 347 | for (i = 0; i < pcount; i++, index++) { |
| @@ -357,6 +369,7 @@ static int zisofs_readpage(struct file *file, struct page *page) | |||
| 357 | } | 369 | } |
| 358 | 370 | ||
| 359 | /* At this point, err contains 0 or -EIO depending on the "critical" page */ | 371 | /* At this point, err contains 0 or -EIO depending on the "critical" page */ |
| 372 | kfree(pages); | ||
| 360 | return err; | 373 | return err; |
| 361 | } | 374 | } |
| 362 | 375 | ||
diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c index bc258a4402f6..ec3fba7d492f 100644 --- a/fs/isofs/inode.c +++ b/fs/isofs/inode.c | |||
| @@ -394,7 +394,10 @@ static int parse_options(char *options, struct iso9660_options *popt) | |||
| 394 | break; | 394 | break; |
| 395 | #ifdef CONFIG_JOLIET | 395 | #ifdef CONFIG_JOLIET |
| 396 | case Opt_iocharset: | 396 | case Opt_iocharset: |
| 397 | kfree(popt->iocharset); | ||
| 397 | popt->iocharset = match_strdup(&args[0]); | 398 | popt->iocharset = match_strdup(&args[0]); |
| 399 | if (!popt->iocharset) | ||
| 400 | return 0; | ||
| 398 | break; | 401 | break; |
| 399 | #endif | 402 | #endif |
| 400 | case Opt_map_a: | 403 | case Opt_map_a: |
diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c index d51e1bb781cf..d94e8031fe5f 100644 --- a/fs/notify/fanotify/fanotify.c +++ b/fs/notify/fanotify/fanotify.c | |||
| @@ -92,7 +92,7 @@ static bool fanotify_should_send_event(struct fsnotify_mark *inode_mark, | |||
| 92 | u32 event_mask, | 92 | u32 event_mask, |
| 93 | const void *data, int data_type) | 93 | const void *data, int data_type) |
| 94 | { | 94 | { |
| 95 | __u32 marks_mask, marks_ignored_mask; | 95 | __u32 marks_mask = 0, marks_ignored_mask = 0; |
| 96 | const struct path *path = data; | 96 | const struct path *path = data; |
| 97 | 97 | ||
| 98 | pr_debug("%s: inode_mark=%p vfsmnt_mark=%p mask=%x data=%p" | 98 | pr_debug("%s: inode_mark=%p vfsmnt_mark=%p mask=%x data=%p" |
| @@ -108,24 +108,20 @@ static bool fanotify_should_send_event(struct fsnotify_mark *inode_mark, | |||
| 108 | !d_can_lookup(path->dentry)) | 108 | !d_can_lookup(path->dentry)) |
| 109 | return false; | 109 | return false; |
| 110 | 110 | ||
| 111 | if (inode_mark && vfsmnt_mark) { | 111 | /* |
| 112 | marks_mask = (vfsmnt_mark->mask | inode_mark->mask); | 112 | * if the event is for a child and this inode doesn't care about |
| 113 | marks_ignored_mask = (vfsmnt_mark->ignored_mask | inode_mark->ignored_mask); | 113 | * events on the child, don't send it! |
| 114 | } else if (inode_mark) { | 114 | */ |
| 115 | /* | 115 | if (inode_mark && |
| 116 | * if the event is for a child and this inode doesn't care about | 116 | (!(event_mask & FS_EVENT_ON_CHILD) || |
| 117 | * events on the child, don't send it! | 117 | (inode_mark->mask & FS_EVENT_ON_CHILD))) { |
| 118 | */ | 118 | marks_mask |= inode_mark->mask; |
| 119 | if ((event_mask & FS_EVENT_ON_CHILD) && | 119 | marks_ignored_mask |= inode_mark->ignored_mask; |
| 120 | !(inode_mark->mask & FS_EVENT_ON_CHILD)) | 120 | } |
| 121 | return false; | 121 | |
| 122 | marks_mask = inode_mark->mask; | 122 | if (vfsmnt_mark) { |
| 123 | marks_ignored_mask = inode_mark->ignored_mask; | 123 | marks_mask |= vfsmnt_mark->mask; |
| 124 | } else if (vfsmnt_mark) { | 124 | marks_ignored_mask |= vfsmnt_mark->ignored_mask; |
| 125 | marks_mask = vfsmnt_mark->mask; | ||
| 126 | marks_ignored_mask = vfsmnt_mark->ignored_mask; | ||
| 127 | } else { | ||
| 128 | BUG(); | ||
| 129 | } | 125 | } |
| 130 | 126 | ||
| 131 | if (d_is_dir(path->dentry) && | 127 | if (d_is_dir(path->dentry) && |
diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c index 219b269c737e..613ec7e5a465 100644 --- a/fs/notify/fsnotify.c +++ b/fs/notify/fsnotify.c | |||
| @@ -192,8 +192,9 @@ static int send_to_group(struct inode *to_tell, | |||
| 192 | struct fsnotify_iter_info *iter_info) | 192 | struct fsnotify_iter_info *iter_info) |
| 193 | { | 193 | { |
| 194 | struct fsnotify_group *group = NULL; | 194 | struct fsnotify_group *group = NULL; |
| 195 | __u32 inode_test_mask = 0; | 195 | __u32 test_mask = (mask & ~FS_EVENT_ON_CHILD); |
| 196 | __u32 vfsmount_test_mask = 0; | 196 | __u32 marks_mask = 0; |
| 197 | __u32 marks_ignored_mask = 0; | ||
| 197 | 198 | ||
| 198 | if (unlikely(!inode_mark && !vfsmount_mark)) { | 199 | if (unlikely(!inode_mark && !vfsmount_mark)) { |
| 199 | BUG(); | 200 | BUG(); |
| @@ -213,29 +214,25 @@ static int send_to_group(struct inode *to_tell, | |||
| 213 | /* does the inode mark tell us to do something? */ | 214 | /* does the inode mark tell us to do something? */ |
| 214 | if (inode_mark) { | 215 | if (inode_mark) { |
| 215 | group = inode_mark->group; | 216 | group = inode_mark->group; |
| 216 | inode_test_mask = (mask & ~FS_EVENT_ON_CHILD); | 217 | marks_mask |= inode_mark->mask; |
| 217 | inode_test_mask &= inode_mark->mask; | 218 | marks_ignored_mask |= inode_mark->ignored_mask; |
| 218 | inode_test_mask &= ~inode_mark->ignored_mask; | ||
| 219 | } | 219 | } |
| 220 | 220 | ||
| 221 | /* does the vfsmount_mark tell us to do something? */ | 221 | /* does the vfsmount_mark tell us to do something? */ |
| 222 | if (vfsmount_mark) { | 222 | if (vfsmount_mark) { |
| 223 | vfsmount_test_mask = (mask & ~FS_EVENT_ON_CHILD); | ||
| 224 | group = vfsmount_mark->group; | 223 | group = vfsmount_mark->group; |
| 225 | vfsmount_test_mask &= vfsmount_mark->mask; | 224 | marks_mask |= vfsmount_mark->mask; |
| 226 | vfsmount_test_mask &= ~vfsmount_mark->ignored_mask; | 225 | marks_ignored_mask |= vfsmount_mark->ignored_mask; |
| 227 | if (inode_mark) | ||
| 228 | vfsmount_test_mask &= ~inode_mark->ignored_mask; | ||
| 229 | } | 226 | } |
| 230 | 227 | ||
| 231 | pr_debug("%s: group=%p to_tell=%p mask=%x inode_mark=%p" | 228 | pr_debug("%s: group=%p to_tell=%p mask=%x inode_mark=%p" |
| 232 | " inode_test_mask=%x vfsmount_mark=%p vfsmount_test_mask=%x" | 229 | " vfsmount_mark=%p marks_mask=%x marks_ignored_mask=%x" |
| 233 | " data=%p data_is=%d cookie=%d\n", | 230 | " data=%p data_is=%d cookie=%d\n", |
| 234 | __func__, group, to_tell, mask, inode_mark, | 231 | __func__, group, to_tell, mask, inode_mark, vfsmount_mark, |
| 235 | inode_test_mask, vfsmount_mark, vfsmount_test_mask, data, | 232 | marks_mask, marks_ignored_mask, data, |
| 236 | data_is, cookie); | 233 | data_is, cookie); |
| 237 | 234 | ||
| 238 | if (!inode_test_mask && !vfsmount_test_mask) | 235 | if (!(test_mask & marks_mask & ~marks_ignored_mask)) |
| 239 | return 0; | 236 | return 0; |
| 240 | 237 | ||
| 241 | return group->ops->handle_event(group, to_tell, inode_mark, | 238 | return group->ops->handle_event(group, to_tell, inode_mark, |
diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c index 020c597ef9b6..d88231e3b2be 100644 --- a/fs/quota/dquot.c +++ b/fs/quota/dquot.c | |||
| @@ -2966,7 +2966,7 @@ static int __init dquot_init(void) | |||
| 2966 | NULL); | 2966 | NULL); |
| 2967 | 2967 | ||
| 2968 | order = 0; | 2968 | order = 0; |
| 2969 | dquot_hash = (struct hlist_head *)__get_free_pages(GFP_ATOMIC, order); | 2969 | dquot_hash = (struct hlist_head *)__get_free_pages(GFP_KERNEL, order); |
| 2970 | if (!dquot_hash) | 2970 | if (!dquot_hash) |
| 2971 | panic("Cannot create dquot hash table"); | 2971 | panic("Cannot create dquot hash table"); |
| 2972 | 2972 | ||
diff --git a/fs/udf/unicode.c b/fs/udf/unicode.c index f897e55f2cd0..16a8ad21b77e 100644 --- a/fs/udf/unicode.c +++ b/fs/udf/unicode.c | |||
| @@ -28,6 +28,9 @@ | |||
| 28 | 28 | ||
| 29 | #include "udf_sb.h" | 29 | #include "udf_sb.h" |
| 30 | 30 | ||
| 31 | #define SURROGATE_MASK 0xfffff800 | ||
| 32 | #define SURROGATE_PAIR 0x0000d800 | ||
| 33 | |||
| 31 | static int udf_uni2char_utf8(wchar_t uni, | 34 | static int udf_uni2char_utf8(wchar_t uni, |
| 32 | unsigned char *out, | 35 | unsigned char *out, |
| 33 | int boundlen) | 36 | int boundlen) |
| @@ -37,6 +40,9 @@ static int udf_uni2char_utf8(wchar_t uni, | |||
| 37 | if (boundlen <= 0) | 40 | if (boundlen <= 0) |
| 38 | return -ENAMETOOLONG; | 41 | return -ENAMETOOLONG; |
| 39 | 42 | ||
| 43 | if ((uni & SURROGATE_MASK) == SURROGATE_PAIR) | ||
| 44 | return -EINVAL; | ||
| 45 | |||
| 40 | if (uni < 0x80) { | 46 | if (uni < 0x80) { |
| 41 | out[u_len++] = (unsigned char)uni; | 47 | out[u_len++] = (unsigned char)uni; |
| 42 | } else if (uni < 0x800) { | 48 | } else if (uni < 0x800) { |
