From: Greg Kroah-Hartman Date: Thu, 20 Oct 2016 15:53:30 +0000 (+0200) Subject: 4.7-stable patches X-Git-Tag: v4.7.10~5 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=dbadb752396e7580da25fb33d3f0e9584eacc4f1;p=thirdparty%2Fkernel%2Fstable-queue.git 4.7-stable patches added patches: cachefiles-fix-attempt-to-read-i_blocks-after-deleting-file.patch crypto-ghash-generic-move-common-definitions-to-a-new-header-file.patch crypto-vmx-fix-memory-corruption-caused-by-p8_ghash.patch dlm-free-workqueues-after-the-connections.patch ext4-allow-dax-writeback-for-hole-punch.patch ext4-bugfix-for-mmaped-pages-in-mpage_release_unused_pages.patch ext4-enforce-online-defrag-restriction-for-encrypted-files.patch ext4-fix-memory-leak-in-ext4_insert_range.patch ext4-reinforce-check-of-i_dtime-when-clearing-high-fields-of-uid-and-gid.patch ext4-release-bh-in-make_indexed_dir.patch ext4-unmap-metadata-when-zeroing-blocks.patch scsi-arcmsr-buffer-overflow-in-arcmsr_iop_message_xfer.patch scsi-arcmsr-simplify-user_len-checking.patch scsi-ibmvfc-fix-i-o-hang-when-port-is-not-mapped.patch vfs-mm-fix-a-dead-loop-in-truncate_inode_pages_range.patch vfs-move-permission-checking-into-notify_change-for-utimes-null.patch --- diff --git a/queue-4.7/cachefiles-fix-attempt-to-read-i_blocks-after-deleting-file.patch b/queue-4.7/cachefiles-fix-attempt-to-read-i_blocks-after-deleting-file.patch new file mode 100644 index 00000000000..cb5f5cc5c9a --- /dev/null +++ b/queue-4.7/cachefiles-fix-attempt-to-read-i_blocks-after-deleting-file.patch @@ -0,0 +1,153 @@ +From a818101d7b92e76db2f9a597e4830734767473b9 Mon Sep 17 00:00:00 2001 +From: David Howells +Date: Tue, 9 Aug 2016 17:41:16 +0100 +Subject: cachefiles: Fix attempt to read i_blocks after deleting file [ver #2] + +From: David Howells + +commit a818101d7b92e76db2f9a597e4830734767473b9 upstream. + +An NULL-pointer dereference happens in cachefiles_mark_object_inactive() +when it tries to read i_blocks so that it can tell the cachefilesd daemon +how much space it's making available. + +The problem is that cachefiles_drop_object() calls +cachefiles_mark_object_inactive() after calling cachefiles_delete_object() +because the object being marked active staves off attempts to (re-)use the +file at that filename until after it has been deleted. This means that +d_inode is NULL by the time we come to try to access it. + +To fix the problem, have the caller of cachefiles_mark_object_inactive() +supply the number of blocks freed up. + +Without this, the following oops may occur: + +BUG: unable to handle kernel NULL pointer dereference at 0000000000000098 +IP: [] cachefiles_mark_object_inactive+0x61/0xb0 [cachefiles] +... +CPU: 11 PID: 527 Comm: kworker/u64:4 Tainted: G I ------------ 3.10.0-470.el7.x86_64 #1 +Hardware name: Hewlett-Packard HP Z600 Workstation/0B54h, BIOS 786G4 v03.19 03/11/2011 +Workqueue: fscache_object fscache_object_work_func [fscache] +task: ffff880035edaf10 ti: ffff8800b77c0000 task.ti: ffff8800b77c0000 +RIP: 0010:[] cachefiles_mark_object_inactive+0x61/0xb0 [cachefiles] +RSP: 0018:ffff8800b77c3d70 EFLAGS: 00010246 +RAX: 0000000000000000 RBX: ffff8800bf6cc400 RCX: 0000000000000034 +RDX: 0000000000000000 RSI: ffff880090ffc710 RDI: ffff8800bf761ef8 +RBP: ffff8800b77c3d88 R08: 2000000000000000 R09: 0090ffc710000000 +R10: ff51005d2ff1c400 R11: 0000000000000000 R12: ffff880090ffc600 +R13: ffff8800bf6cc520 R14: ffff8800bf6cc400 R15: ffff8800bf6cc498 +FS: 0000000000000000(0000) GS:ffff8800bb8c0000(0000) knlGS:0000000000000000 +CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b +CR2: 0000000000000098 CR3: 00000000019ba000 CR4: 00000000000007e0 +DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 +DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 +Stack: + ffff880090ffc600 ffff8800bf6cc400 ffff8800867df140 ffff8800b77c3db0 + ffffffffa06c48cb ffff880090ffc600 ffff880090ffc180 ffff880090ffc658 + ffff8800b77c3df0 ffffffffa085d846 ffff8800a96b8150 ffff880090ffc600 +Call Trace: + [] cachefiles_drop_object+0x6b/0xf0 [cachefiles] + [] fscache_drop_object+0xd6/0x1e0 [fscache] + [] fscache_object_work_func+0xa5/0x200 [fscache] + [] process_one_work+0x17b/0x470 + [] worker_thread+0x126/0x410 + [] ? rescuer_thread+0x460/0x460 + [] kthread+0xcf/0xe0 + [] ? kthread_create_on_node+0x140/0x140 + [] ret_from_fork+0x58/0x90 + [] ? kthread_create_on_node+0x140/0x140 + +The oopsing code shows: + + callq 0xffffffff810af6a0 + mov 0xf8(%r12),%rax + mov 0x30(%rax),%rax + mov 0x98(%rax),%rax <---- oops here + lock add %rax,0x130(%rbx) + +where this is: + + d_backing_inode(object->dentry)->i_blocks + +Fixes: a5b3a80b899bda0f456f1246c4c5a1191ea01519 (CacheFiles: Provide read-and-reset release counters for cachefilesd) +Reported-by: Jianhong Yin +Signed-off-by: David Howells +Reviewed-by: Jeff Layton +Reviewed-by: Steve Dickson +Signed-off-by: Al Viro +Signed-off-by: Greg Kroah-Hartman + +--- + fs/cachefiles/interface.c | 8 +++++++- + fs/cachefiles/internal.h | 3 ++- + fs/cachefiles/namei.c | 8 ++++---- + 3 files changed, 13 insertions(+), 6 deletions(-) + +--- a/fs/cachefiles/interface.c ++++ b/fs/cachefiles/interface.c +@@ -253,6 +253,8 @@ static void cachefiles_drop_object(struc + struct cachefiles_object *object; + struct cachefiles_cache *cache; + const struct cred *saved_cred; ++ struct inode *inode; ++ blkcnt_t i_blocks = 0; + + ASSERT(_object); + +@@ -279,6 +281,10 @@ static void cachefiles_drop_object(struc + _object != cache->cache.fsdef + ) { + _debug("- retire object OBJ%x", object->fscache.debug_id); ++ inode = d_backing_inode(object->dentry); ++ if (inode) ++ i_blocks = inode->i_blocks; ++ + cachefiles_begin_secure(cache, &saved_cred); + cachefiles_delete_object(cache, object); + cachefiles_end_secure(cache, saved_cred); +@@ -292,7 +298,7 @@ static void cachefiles_drop_object(struc + + /* note that the object is now inactive */ + if (test_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags)) +- cachefiles_mark_object_inactive(cache, object); ++ cachefiles_mark_object_inactive(cache, object, i_blocks); + + dput(object->dentry); + object->dentry = NULL; +--- a/fs/cachefiles/internal.h ++++ b/fs/cachefiles/internal.h +@@ -160,7 +160,8 @@ extern char *cachefiles_cook_key(const u + * namei.c + */ + extern void cachefiles_mark_object_inactive(struct cachefiles_cache *cache, +- struct cachefiles_object *object); ++ struct cachefiles_object *object, ++ blkcnt_t i_blocks); + extern int cachefiles_delete_object(struct cachefiles_cache *cache, + struct cachefiles_object *object); + extern int cachefiles_walk_to_object(struct cachefiles_object *parent, +--- a/fs/cachefiles/namei.c ++++ b/fs/cachefiles/namei.c +@@ -261,10 +261,9 @@ requeue: + * Mark an object as being inactive. + */ + void cachefiles_mark_object_inactive(struct cachefiles_cache *cache, +- struct cachefiles_object *object) ++ struct cachefiles_object *object, ++ blkcnt_t i_blocks) + { +- blkcnt_t i_blocks = d_backing_inode(object->dentry)->i_blocks; +- + write_lock(&cache->active_lock); + rb_erase(&object->active_node, &cache->active_nodes); + clear_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags); +@@ -707,7 +706,8 @@ mark_active_timed_out: + + check_error: + _debug("check error %d", ret); +- cachefiles_mark_object_inactive(cache, object); ++ cachefiles_mark_object_inactive( ++ cache, object, d_backing_inode(object->dentry)->i_blocks); + release_dentry: + dput(object->dentry); + object->dentry = NULL; diff --git a/queue-4.7/crypto-ghash-generic-move-common-definitions-to-a-new-header-file.patch b/queue-4.7/crypto-ghash-generic-move-common-definitions-to-a-new-header-file.patch new file mode 100644 index 00000000000..2944d88cc60 --- /dev/null +++ b/queue-4.7/crypto-ghash-generic-move-common-definitions-to-a-new-header-file.patch @@ -0,0 +1,76 @@ +From a397ba829d7f8aff4c90af3704573a28ccd61a59 Mon Sep 17 00:00:00 2001 +From: Marcelo Cerri +Date: Wed, 28 Sep 2016 13:42:09 -0300 +Subject: crypto: ghash-generic - move common definitions to a new header file + +From: Marcelo Cerri + +commit a397ba829d7f8aff4c90af3704573a28ccd61a59 upstream. + +Move common values and types used by ghash-generic to a new header file +so drivers can directly use ghash-generic as a fallback implementation. + +Fixes: cc333cd68dfa ("crypto: vmx - Adding GHASH routines for VMX module") +Signed-off-by: Marcelo Cerri +Signed-off-by: Herbert Xu +Signed-off-by: Greg Kroah-Hartman + +--- + crypto/ghash-generic.c | 13 +------------ + include/crypto/ghash.h | 23 +++++++++++++++++++++++ + 2 files changed, 24 insertions(+), 12 deletions(-) + +--- a/crypto/ghash-generic.c ++++ b/crypto/ghash-generic.c +@@ -14,24 +14,13 @@ + + #include + #include ++#include + #include + #include + #include + #include + #include + +-#define GHASH_BLOCK_SIZE 16 +-#define GHASH_DIGEST_SIZE 16 +- +-struct ghash_ctx { +- struct gf128mul_4k *gf128; +-}; +- +-struct ghash_desc_ctx { +- u8 buffer[GHASH_BLOCK_SIZE]; +- u32 bytes; +-}; +- + static int ghash_init(struct shash_desc *desc) + { + struct ghash_desc_ctx *dctx = shash_desc_ctx(desc); +--- /dev/null ++++ b/include/crypto/ghash.h +@@ -0,0 +1,23 @@ ++/* ++ * Common values for GHASH algorithms ++ */ ++ ++#ifndef __CRYPTO_GHASH_H__ ++#define __CRYPTO_GHASH_H__ ++ ++#include ++#include ++ ++#define GHASH_BLOCK_SIZE 16 ++#define GHASH_DIGEST_SIZE 16 ++ ++struct ghash_ctx { ++ struct gf128mul_4k *gf128; ++}; ++ ++struct ghash_desc_ctx { ++ u8 buffer[GHASH_BLOCK_SIZE]; ++ u32 bytes; ++}; ++ ++#endif diff --git a/queue-4.7/crypto-vmx-fix-memory-corruption-caused-by-p8_ghash.patch b/queue-4.7/crypto-vmx-fix-memory-corruption-caused-by-p8_ghash.patch new file mode 100644 index 00000000000..ceef8ef4d84 --- /dev/null +++ b/queue-4.7/crypto-vmx-fix-memory-corruption-caused-by-p8_ghash.patch @@ -0,0 +1,103 @@ +From 80da44c29d997e28c4442825f35f4ac339813877 Mon Sep 17 00:00:00 2001 +From: Marcelo Cerri +Date: Wed, 28 Sep 2016 13:42:10 -0300 +Subject: crypto: vmx - Fix memory corruption caused by p8_ghash + +From: Marcelo Cerri + +commit 80da44c29d997e28c4442825f35f4ac339813877 upstream. + +This patch changes the p8_ghash driver to use ghash-generic as a fixed +fallback implementation. This allows the correct value of descsize to be +defined directly in its shash_alg structure and avoids problems with +incorrect buffer sizes when its state is exported or imported. + +Reported-by: Jan Stancek +Fixes: cc333cd68dfa ("crypto: vmx - Adding GHASH routines for VMX module") +Signed-off-by: Marcelo Cerri +Signed-off-by: Herbert Xu +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/crypto/vmx/ghash.c | 31 ++++++++++++++++--------------- + 1 file changed, 16 insertions(+), 15 deletions(-) + +--- a/drivers/crypto/vmx/ghash.c ++++ b/drivers/crypto/vmx/ghash.c +@@ -26,16 +26,13 @@ + #include + #include + #include ++#include + #include + #include + #include + + #define IN_INTERRUPT in_interrupt() + +-#define GHASH_BLOCK_SIZE (16) +-#define GHASH_DIGEST_SIZE (16) +-#define GHASH_KEY_LEN (16) +- + void gcm_init_p8(u128 htable[16], const u64 Xi[2]); + void gcm_gmult_p8(u64 Xi[2], const u128 htable[16]); + void gcm_ghash_p8(u64 Xi[2], const u128 htable[16], +@@ -55,16 +52,11 @@ struct p8_ghash_desc_ctx { + + static int p8_ghash_init_tfm(struct crypto_tfm *tfm) + { +- const char *alg; ++ const char *alg = "ghash-generic"; + struct crypto_shash *fallback; + struct crypto_shash *shash_tfm = __crypto_shash_cast(tfm); + struct p8_ghash_ctx *ctx = crypto_tfm_ctx(tfm); + +- if (!(alg = crypto_tfm_alg_name(tfm))) { +- printk(KERN_ERR "Failed to get algorithm name.\n"); +- return -ENOENT; +- } +- + fallback = crypto_alloc_shash(alg, 0, CRYPTO_ALG_NEED_FALLBACK); + if (IS_ERR(fallback)) { + printk(KERN_ERR +@@ -78,10 +70,18 @@ static int p8_ghash_init_tfm(struct cryp + crypto_shash_set_flags(fallback, + crypto_shash_get_flags((struct crypto_shash + *) tfm)); +- ctx->fallback = fallback; + +- shash_tfm->descsize = sizeof(struct p8_ghash_desc_ctx) +- + crypto_shash_descsize(fallback); ++ /* Check if the descsize defined in the algorithm is still enough. */ ++ if (shash_tfm->descsize < sizeof(struct p8_ghash_desc_ctx) ++ + crypto_shash_descsize(fallback)) { ++ printk(KERN_ERR ++ "Desc size of the fallback implementation (%s) does not match the expected value: %lu vs %u\n", ++ alg, ++ shash_tfm->descsize - sizeof(struct p8_ghash_desc_ctx), ++ crypto_shash_descsize(fallback)); ++ return -EINVAL; ++ } ++ ctx->fallback = fallback; + + return 0; + } +@@ -113,7 +113,7 @@ static int p8_ghash_setkey(struct crypto + { + struct p8_ghash_ctx *ctx = crypto_tfm_ctx(crypto_shash_tfm(tfm)); + +- if (keylen != GHASH_KEY_LEN) ++ if (keylen != GHASH_BLOCK_SIZE) + return -EINVAL; + + preempt_disable(); +@@ -211,7 +211,8 @@ struct shash_alg p8_ghash_alg = { + .update = p8_ghash_update, + .final = p8_ghash_final, + .setkey = p8_ghash_setkey, +- .descsize = sizeof(struct p8_ghash_desc_ctx), ++ .descsize = sizeof(struct p8_ghash_desc_ctx) ++ + sizeof(struct ghash_desc_ctx), + .base = { + .cra_name = "ghash", + .cra_driver_name = "p8_ghash", diff --git a/queue-4.7/dlm-free-workqueues-after-the-connections.patch b/queue-4.7/dlm-free-workqueues-after-the-connections.patch new file mode 100644 index 00000000000..3561722c381 --- /dev/null +++ b/queue-4.7/dlm-free-workqueues-after-the-connections.patch @@ -0,0 +1,51 @@ +From 3a8db79889ce16930aff19b818f5b09651bb7644 Mon Sep 17 00:00:00 2001 +From: Marcelo Ricardo Leitner +Date: Sat, 8 Oct 2016 10:14:37 -0300 +Subject: dlm: free workqueues after the connections + +From: Marcelo Ricardo Leitner + +commit 3a8db79889ce16930aff19b818f5b09651bb7644 upstream. + +After backporting commit ee44b4bc054a ("dlm: use sctp 1-to-1 API") +series to a kernel with an older workqueue which didn't use RCU yet, it +was noticed that we are freeing the workqueues in dlm_lowcomms_stop() +too early as free_conn() will try to access that memory for canceling +the queued works if any. + +This issue was introduced by commit 0d737a8cfd83 as before it such +attempt to cancel the queued works wasn't performed, so the issue was +not present. + +This patch fixes it by simply inverting the free order. + +Fixes: 0d737a8cfd83 ("dlm: fix race while closing connections") +Signed-off-by: Marcelo Ricardo Leitner +Signed-off-by: David Teigland +Signed-off-by: Greg Kroah-Hartman + +--- + fs/dlm/lowcomms.c | 8 ++------ + 1 file changed, 2 insertions(+), 6 deletions(-) + +--- a/fs/dlm/lowcomms.c ++++ b/fs/dlm/lowcomms.c +@@ -1657,16 +1657,12 @@ void dlm_lowcomms_stop(void) + mutex_lock(&connections_lock); + dlm_allow_conn = 0; + foreach_conn(stop_conn); ++ clean_writequeues(); ++ foreach_conn(free_conn); + mutex_unlock(&connections_lock); + + work_stop(); + +- mutex_lock(&connections_lock); +- clean_writequeues(); +- +- foreach_conn(free_conn); +- +- mutex_unlock(&connections_lock); + kmem_cache_destroy(con_cache); + } + diff --git a/queue-4.7/ext4-allow-dax-writeback-for-hole-punch.patch b/queue-4.7/ext4-allow-dax-writeback-for-hole-punch.patch new file mode 100644 index 00000000000..e7d88b1c7ef --- /dev/null +++ b/queue-4.7/ext4-allow-dax-writeback-for-hole-punch.patch @@ -0,0 +1,43 @@ +From cca32b7eeb4ea24fa6596650e06279ad9130af98 Mon Sep 17 00:00:00 2001 +From: Ross Zwisler +Date: Thu, 22 Sep 2016 11:49:38 -0400 +Subject: ext4: allow DAX writeback for hole punch + +From: Ross Zwisler + +commit cca32b7eeb4ea24fa6596650e06279ad9130af98 upstream. + +Currently when doing a DAX hole punch with ext4 we fail to do a writeback. +This is because the logic around filemap_write_and_wait_range() in +ext4_punch_hole() only looks for dirty page cache pages in the radix tree, +not for dirty DAX exceptional entries. + +Signed-off-by: Ross Zwisler +Reviewed-by: Jan Kara +Signed-off-by: Theodore Ts'o +Signed-off-by: Greg Kroah-Hartman + +--- + fs/ext4/inode.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/fs/ext4/inode.c ++++ b/fs/ext4/inode.c +@@ -3892,7 +3892,7 @@ int ext4_update_disksize_before_punch(st + } + + /* +- * ext4_punch_hole: punches a hole in a file by releaseing the blocks ++ * ext4_punch_hole: punches a hole in a file by releasing the blocks + * associated with the given offset and length + * + * @inode: File inode +@@ -3921,7 +3921,7 @@ int ext4_punch_hole(struct inode *inode, + * Write out all dirty pages to avoid race conditions + * Then release them. + */ +- if (mapping->nrpages && mapping_tagged(mapping, PAGECACHE_TAG_DIRTY)) { ++ if (mapping_tagged(mapping, PAGECACHE_TAG_DIRTY)) { + ret = filemap_write_and_wait_range(mapping, offset, + offset + length - 1); + if (ret) diff --git a/queue-4.7/ext4-bugfix-for-mmaped-pages-in-mpage_release_unused_pages.patch b/queue-4.7/ext4-bugfix-for-mmaped-pages-in-mpage_release_unused_pages.patch new file mode 100644 index 00000000000..024a709c23f --- /dev/null +++ b/queue-4.7/ext4-bugfix-for-mmaped-pages-in-mpage_release_unused_pages.patch @@ -0,0 +1,69 @@ +From 4e800c0359d9a53e6bf0ab216954971b2515247f Mon Sep 17 00:00:00 2001 +From: wangguang +Date: Thu, 15 Sep 2016 11:32:46 -0400 +Subject: ext4: bugfix for mmaped pages in mpage_release_unused_pages() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: wangguang + +commit 4e800c0359d9a53e6bf0ab216954971b2515247f upstream. + +Pages clear buffers after ext4 delayed block allocation failed, +However, it does not clean its pte_dirty flag. +if the pages unmap ,in cording to the pte_dirty , +unmap_page_range may try to call __set_page_dirty, + +which may lead to the bugon at +mpage_prepare_extent_to_map:head = page_buffers(page);. + +This patch just call clear_page_dirty_for_io to clean pte_dirty +at mpage_release_unused_pages for pages mmaped. + +Steps to reproduce the bug: + +(1) mmap a file in ext4 + addr = (char *)mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_SHARED, + fd, 0); + memset(addr, 'i', 4096); + +(2) return EIO at + + ext4_writepages->mpage_map_and_submit_extent->mpage_map_one_extent + +which causes this log message to be print: + + ext4_msg(sb, KERN_CRIT, + "Delayed block allocation failed for " + "inode %lu at logical offset %llu with" + " max blocks %u with error %d", + inode->i_ino, + (unsigned long long)map->m_lblk, + (unsigned)map->m_len, -err); + +(3)Unmap the addr cause warning at + + __set_page_dirty:WARN_ON_ONCE(warn && !PageUptodate(page)); + +(4) wait for a minute,then bugon happen. + +Signed-off-by: wangguang +Signed-off-by: Theodore Ts'o +Signed-off-by: Greg Kroah-Hartman + +--- + fs/ext4/inode.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/fs/ext4/inode.c ++++ b/fs/ext4/inode.c +@@ -1649,6 +1649,8 @@ static void mpage_release_unused_pages(s + BUG_ON(!PageLocked(page)); + BUG_ON(PageWriteback(page)); + if (invalidate) { ++ if (page_mapped(page)) ++ clear_page_dirty_for_io(page); + block_invalidatepage(page, 0, PAGE_SIZE); + ClearPageUptodate(page); + } diff --git a/queue-4.7/ext4-enforce-online-defrag-restriction-for-encrypted-files.patch b/queue-4.7/ext4-enforce-online-defrag-restriction-for-encrypted-files.patch new file mode 100644 index 00000000000..da76d8932d3 --- /dev/null +++ b/queue-4.7/ext4-enforce-online-defrag-restriction-for-encrypted-files.patch @@ -0,0 +1,42 @@ +From 14fbd4aa613bd5110556c281799ce36dc6f3ba97 Mon Sep 17 00:00:00 2001 +From: Eric Whitney +Date: Mon, 29 Aug 2016 15:45:11 -0400 +Subject: ext4: enforce online defrag restriction for encrypted files + +From: Eric Whitney + +commit 14fbd4aa613bd5110556c281799ce36dc6f3ba97 upstream. + +Online defragging of encrypted files is not currently implemented. +However, the move extent ioctl can still return successfully when +called. For example, this occurs when xfstest ext4/020 is run on an +encrypted file system, resulting in a corrupted test file and a +corresponding test failure. + +Until the proper functionality is implemented, fail the move extent +ioctl if either the original or donor file is encrypted. + +Signed-off-by: Eric Whitney +Signed-off-by: Theodore Ts'o +Signed-off-by: Greg Kroah-Hartman + +--- + fs/ext4/move_extent.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +--- a/fs/ext4/move_extent.c ++++ b/fs/ext4/move_extent.c +@@ -598,6 +598,13 @@ ext4_move_extents(struct file *o_filp, s + return -EOPNOTSUPP; + } + ++ if (ext4_encrypted_inode(orig_inode) || ++ ext4_encrypted_inode(donor_inode)) { ++ ext4_msg(orig_inode->i_sb, KERN_ERR, ++ "Online defrag not supported for encrypted files"); ++ return -EOPNOTSUPP; ++ } ++ + /* Protect orig and donor inodes against a truncate */ + lock_two_nondirectories(orig_inode, donor_inode); + diff --git a/queue-4.7/ext4-fix-memory-leak-in-ext4_insert_range.patch b/queue-4.7/ext4-fix-memory-leak-in-ext4_insert_range.patch new file mode 100644 index 00000000000..7253c7922d7 --- /dev/null +++ b/queue-4.7/ext4-fix-memory-leak-in-ext4_insert_range.patch @@ -0,0 +1,50 @@ +From edf15aa180d7b98fe16bd3eda42f9dd0e60dee20 Mon Sep 17 00:00:00 2001 +From: Fabian Frederick +Date: Thu, 15 Sep 2016 11:39:52 -0400 +Subject: ext4: fix memory leak in ext4_insert_range() + +From: Fabian Frederick + +commit edf15aa180d7b98fe16bd3eda42f9dd0e60dee20 upstream. + +Running xfstests generic/013 with kmemleak gives the following: + +unreferenced object 0xffff8801d3d27de0 (size 96): + comm "fsstress", pid 4941, jiffies 4294860168 (age 53.485s) + hex dump (first 32 bytes): + 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 ................ + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ + backtrace: + [] kmemleak_alloc+0x23/0x40 + [] __kmalloc+0xf5/0x1d0 + [] ext4_find_extent+0x1ec/0x2f0 + [] ext4_insert_range+0x34c/0x4a0 + [] ext4_fallocate+0x4e2/0x8b0 + [] vfs_fallocate+0x134/0x210 + [] SyS_fallocate+0x3f/0x60 + [] entry_SYSCALL_64_fastpath+0x13/0x8f + [] 0xffffffffffffffff + +Problem seems mitigated by dropping refs and freeing path +when there's no path[depth].p_ext + +Signed-off-by: Fabian Frederick +Signed-off-by: Theodore Ts'o +Signed-off-by: Greg Kroah-Hartman + +--- + fs/ext4/extents.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/fs/ext4/extents.c ++++ b/fs/ext4/extents.c +@@ -5734,6 +5734,9 @@ int ext4_insert_range(struct inode *inod + up_write(&EXT4_I(inode)->i_data_sem); + goto out_stop; + } ++ } else { ++ ext4_ext_drop_refs(path); ++ kfree(path); + } + + ret = ext4_es_remove_extent(inode, offset_lblk, diff --git a/queue-4.7/ext4-reinforce-check-of-i_dtime-when-clearing-high-fields-of-uid-and-gid.patch b/queue-4.7/ext4-reinforce-check-of-i_dtime-when-clearing-high-fields-of-uid-and-gid.patch new file mode 100644 index 00000000000..a3d6b8e61e1 --- /dev/null +++ b/queue-4.7/ext4-reinforce-check-of-i_dtime-when-clearing-high-fields-of-uid-and-gid.patch @@ -0,0 +1,53 @@ +From 93e3b4e6631d2a74a8cf7429138096862ff9f452 Mon Sep 17 00:00:00 2001 +From: Daeho Jeong +Date: Mon, 5 Sep 2016 22:56:10 -0400 +Subject: ext4: reinforce check of i_dtime when clearing high fields of uid and gid + +From: Daeho Jeong + +commit 93e3b4e6631d2a74a8cf7429138096862ff9f452 upstream. + +Now, ext4_do_update_inode() clears high 16-bit fields of uid/gid +of deleted and evicted inode to fix up interoperability with old +kernels. However, it checks only i_dtime of an inode to determine +whether the inode was deleted and evicted, and this is very risky, +because i_dtime can be used for the pointer maintaining orphan inode +list, too. We need to further check whether the i_dtime is being +used for the orphan inode list even if the i_dtime is not NULL. + +We found that high 16-bit fields of uid/gid of inode are unintentionally +and permanently cleared when the inode truncation is just triggered, +but not finished, and the inode metadata, whose high uid/gid bits are +cleared, is written on disk, and the sudden power-off follows that +in order. + +Signed-off-by: Daeho Jeong +Signed-off-by: Hobin Woo +Signed-off-by: Theodore Ts'o +Signed-off-by: Greg Kroah-Hartman + +--- + fs/ext4/inode.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +--- a/fs/ext4/inode.c ++++ b/fs/ext4/inode.c +@@ -4814,14 +4814,14 @@ static int ext4_do_update_inode(handle_t + * Fix up interoperability with old kernels. Otherwise, old inodes get + * re-used with the upper 16 bits of the uid/gid intact + */ +- if (!ei->i_dtime) { ++ if (ei->i_dtime && list_empty(&ei->i_orphan)) { ++ raw_inode->i_uid_high = 0; ++ raw_inode->i_gid_high = 0; ++ } else { + raw_inode->i_uid_high = + cpu_to_le16(high_16_bits(i_uid)); + raw_inode->i_gid_high = + cpu_to_le16(high_16_bits(i_gid)); +- } else { +- raw_inode->i_uid_high = 0; +- raw_inode->i_gid_high = 0; + } + } else { + raw_inode->i_uid_low = cpu_to_le16(fs_high2lowuid(i_uid)); diff --git a/queue-4.7/ext4-release-bh-in-make_indexed_dir.patch b/queue-4.7/ext4-release-bh-in-make_indexed_dir.patch new file mode 100644 index 00000000000..30134e56be6 --- /dev/null +++ b/queue-4.7/ext4-release-bh-in-make_indexed_dir.patch @@ -0,0 +1,64 @@ +From e81d44778d1d57bbaef9e24c4eac7c8a7a401d40 Mon Sep 17 00:00:00 2001 +From: gmail +Date: Fri, 30 Sep 2016 01:33:37 -0400 +Subject: ext4: release bh in make_indexed_dir + +From: gmail + +commit e81d44778d1d57bbaef9e24c4eac7c8a7a401d40 upstream. + +The commit 6050d47adcad: "ext4: bail out from make_indexed_dir() on +first error" could end up leaking bh2 in the error path. + +[ Also avoid renaming bh2 to bh, which just confuses things --tytso ] + +Signed-off-by: yangsheng +Signed-off-by: Theodore Ts'o +Signed-off-by: Greg Kroah-Hartman + +--- + fs/ext4/namei.c | 14 ++++++-------- + 1 file changed, 6 insertions(+), 8 deletions(-) + +--- a/fs/ext4/namei.c ++++ b/fs/ext4/namei.c +@@ -2043,33 +2043,31 @@ static int make_indexed_dir(handle_t *ha + frame->entries = entries; + frame->at = entries; + frame->bh = bh; +- bh = bh2; + + retval = ext4_handle_dirty_dx_node(handle, dir, frame->bh); + if (retval) + goto out_frames; +- retval = ext4_handle_dirty_dirent_node(handle, dir, bh); ++ retval = ext4_handle_dirty_dirent_node(handle, dir, bh2); + if (retval) + goto out_frames; + +- de = do_split(handle,dir, &bh, frame, &fname->hinfo); ++ de = do_split(handle,dir, &bh2, frame, &fname->hinfo); + if (IS_ERR(de)) { + retval = PTR_ERR(de); + goto out_frames; + } +- dx_release(frames); + +- retval = add_dirent_to_buf(handle, fname, dir, inode, de, bh); +- brelse(bh); +- return retval; ++ retval = add_dirent_to_buf(handle, fname, dir, inode, de, bh2); + out_frames: + /* + * Even if the block split failed, we have to properly write + * out all the changes we did so far. Otherwise we can end up + * with corrupted filesystem. + */ +- ext4_mark_inode_dirty(handle, dir); ++ if (retval) ++ ext4_mark_inode_dirty(handle, dir); + dx_release(frames); ++ brelse(bh2); + return retval; + } + diff --git a/queue-4.7/ext4-unmap-metadata-when-zeroing-blocks.patch b/queue-4.7/ext4-unmap-metadata-when-zeroing-blocks.patch new file mode 100644 index 00000000000..494ff9f3bbb --- /dev/null +++ b/queue-4.7/ext4-unmap-metadata-when-zeroing-blocks.patch @@ -0,0 +1,44 @@ +From 9b623df614576680cadeaa4d7e0b5884de8f7c17 Mon Sep 17 00:00:00 2001 +From: Jan Kara +Date: Fri, 30 Sep 2016 02:02:29 -0400 +Subject: ext4: unmap metadata when zeroing blocks + +From: Jan Kara + +commit 9b623df614576680cadeaa4d7e0b5884de8f7c17 upstream. + +When zeroing blocks for DAX allocations, we also have to unmap aliases +in the block device mappings. Otherwise writeback can overwrite zeros +with stale data from block device page cache. + +Signed-off-by: Jan Kara +Signed-off-by: Theodore Ts'o +Signed-off-by: Greg Kroah-Hartman + +--- + fs/ext4/inode.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +--- a/fs/ext4/inode.c ++++ b/fs/ext4/inode.c +@@ -647,11 +647,19 @@ found: + /* + * We have to zeroout blocks before inserting them into extent + * status tree. Otherwise someone could look them up there and +- * use them before they are really zeroed. ++ * use them before they are really zeroed. We also have to ++ * unmap metadata before zeroing as otherwise writeback can ++ * overwrite zeros with stale data from block device. + */ + if (flags & EXT4_GET_BLOCKS_ZERO && + map->m_flags & EXT4_MAP_MAPPED && + map->m_flags & EXT4_MAP_NEW) { ++ ext4_lblk_t i; ++ ++ for (i = 0; i < map->m_len; i++) { ++ unmap_underlying_metadata(inode->i_sb->s_bdev, ++ map->m_pblk + i); ++ } + ret = ext4_issue_zeroout(inode, map->m_lblk, + map->m_pblk, map->m_len); + if (ret) { diff --git a/queue-4.7/scsi-arcmsr-buffer-overflow-in-arcmsr_iop_message_xfer.patch b/queue-4.7/scsi-arcmsr-buffer-overflow-in-arcmsr_iop_message_xfer.patch new file mode 100644 index 00000000000..70f130ebf56 --- /dev/null +++ b/queue-4.7/scsi-arcmsr-buffer-overflow-in-arcmsr_iop_message_xfer.patch @@ -0,0 +1,46 @@ +From 7bc2b55a5c030685b399bb65b6baa9ccc3d1f167 Mon Sep 17 00:00:00 2001 +From: Dan Carpenter +Date: Thu, 15 Sep 2016 16:44:56 +0300 +Subject: scsi: arcmsr: Buffer overflow in arcmsr_iop_message_xfer() + +From: Dan Carpenter + +commit 7bc2b55a5c030685b399bb65b6baa9ccc3d1f167 upstream. + +We need to put an upper bound on "user_len" so the memcpy() doesn't +overflow. + +Reported-by: Marco Grassi +Signed-off-by: Dan Carpenter +Reviewed-by: Tomas Henzl +Signed-off-by: Martin K. Petersen +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/scsi/arcmsr/arcmsr_hba.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +--- a/drivers/scsi/arcmsr/arcmsr_hba.c ++++ b/drivers/scsi/arcmsr/arcmsr_hba.c +@@ -2388,7 +2388,8 @@ static int arcmsr_iop_message_xfer(struc + } + case ARCMSR_MESSAGE_WRITE_WQBUFFER: { + unsigned char *ver_addr; +- int32_t user_len, cnt2end; ++ uint32_t user_len; ++ int32_t cnt2end; + uint8_t *pQbuffer, *ptmpuserbuffer; + ver_addr = kmalloc(ARCMSR_API_DATA_BUFLEN, GFP_ATOMIC); + if (!ver_addr) { +@@ -2397,6 +2398,11 @@ static int arcmsr_iop_message_xfer(struc + } + ptmpuserbuffer = ver_addr; + user_len = pcmdmessagefld->cmdmessage.Length; ++ if (user_len > ARCMSR_API_DATA_BUFLEN) { ++ retvalue = ARCMSR_MESSAGE_FAIL; ++ kfree(ver_addr); ++ goto message_out; ++ } + memcpy(ptmpuserbuffer, + pcmdmessagefld->messagedatabuffer, user_len); + spin_lock_irqsave(&acb->wqbuffer_lock, flags); diff --git a/queue-4.7/scsi-arcmsr-simplify-user_len-checking.patch b/queue-4.7/scsi-arcmsr-simplify-user_len-checking.patch new file mode 100644 index 00000000000..14b4fc50279 --- /dev/null +++ b/queue-4.7/scsi-arcmsr-simplify-user_len-checking.patch @@ -0,0 +1,56 @@ +From 4bd173c30792791a6daca8c64793ec0a4ae8324f Mon Sep 17 00:00:00 2001 +From: Borislav Petkov +Date: Fri, 23 Sep 2016 13:22:26 +0200 +Subject: scsi: arcmsr: Simplify user_len checking + +From: Borislav Petkov + +commit 4bd173c30792791a6daca8c64793ec0a4ae8324f upstream. + +Do the user_len check first and then the ver_addr allocation so that we +can save us the kfree() on the error path when user_len is > +ARCMSR_API_DATA_BUFLEN. + +Signed-off-by: Borislav Petkov +Cc: Marco Grassi +Cc: Dan Carpenter +Cc: Tomas Henzl +Cc: Martin K. Petersen +Reviewed-by: Johannes Thumshirn +Reviewed-by: Tomas Henzl +Signed-off-by: Martin K. Petersen +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/scsi/arcmsr/arcmsr_hba.c | 14 ++++++++------ + 1 file changed, 8 insertions(+), 6 deletions(-) + +--- a/drivers/scsi/arcmsr/arcmsr_hba.c ++++ b/drivers/scsi/arcmsr/arcmsr_hba.c +@@ -2391,18 +2391,20 @@ static int arcmsr_iop_message_xfer(struc + uint32_t user_len; + int32_t cnt2end; + uint8_t *pQbuffer, *ptmpuserbuffer; +- ver_addr = kmalloc(ARCMSR_API_DATA_BUFLEN, GFP_ATOMIC); +- if (!ver_addr) { ++ ++ user_len = pcmdmessagefld->cmdmessage.Length; ++ if (user_len > ARCMSR_API_DATA_BUFLEN) { + retvalue = ARCMSR_MESSAGE_FAIL; + goto message_out; + } +- ptmpuserbuffer = ver_addr; +- user_len = pcmdmessagefld->cmdmessage.Length; +- if (user_len > ARCMSR_API_DATA_BUFLEN) { ++ ++ ver_addr = kmalloc(ARCMSR_API_DATA_BUFLEN, GFP_ATOMIC); ++ if (!ver_addr) { + retvalue = ARCMSR_MESSAGE_FAIL; +- kfree(ver_addr); + goto message_out; + } ++ ptmpuserbuffer = ver_addr; ++ + memcpy(ptmpuserbuffer, + pcmdmessagefld->messagedatabuffer, user_len); + spin_lock_irqsave(&acb->wqbuffer_lock, flags); diff --git a/queue-4.7/scsi-ibmvfc-fix-i-o-hang-when-port-is-not-mapped.patch b/queue-4.7/scsi-ibmvfc-fix-i-o-hang-when-port-is-not-mapped.patch new file mode 100644 index 00000000000..d8550322d76 --- /dev/null +++ b/queue-4.7/scsi-ibmvfc-fix-i-o-hang-when-port-is-not-mapped.patch @@ -0,0 +1,36 @@ +From 07d0e9a847401ffd2f09bd450d41644cd090e81d Mon Sep 17 00:00:00 2001 +From: Brian King +Date: Mon, 19 Sep 2016 08:59:19 -0500 +Subject: scsi: ibmvfc: Fix I/O hang when port is not mapped + +From: Brian King + +commit 07d0e9a847401ffd2f09bd450d41644cd090e81d upstream. + +If a VFC port gets unmapped in the VIOS, it may not respond with a CRQ +init complete following H_REG_CRQ. If this occurs, we can end up having +called scsi_block_requests and not a resulting unblock until the init +complete happens, which may never occur, and we end up hanging I/O +requests. This patch ensures the host action stay set to +IBMVFC_HOST_ACTION_TGT_DEL so we move all rports into devloss state and +unblock unless we receive an init complete. + +Signed-off-by: Brian King +Acked-by: Tyrel Datwyler +Signed-off-by: Martin K. Petersen +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/scsi/ibmvscsi/ibmvfc.c | 1 - + 1 file changed, 1 deletion(-) + +--- a/drivers/scsi/ibmvscsi/ibmvfc.c ++++ b/drivers/scsi/ibmvscsi/ibmvfc.c +@@ -717,7 +717,6 @@ static int ibmvfc_reset_crq(struct ibmvf + spin_lock_irqsave(vhost->host->host_lock, flags); + vhost->state = IBMVFC_NO_CRQ; + vhost->logged_in = 0; +- ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_NONE); + + /* Clean out the queue */ + memset(crq->msgs, 0, PAGE_SIZE); diff --git a/queue-4.7/series b/queue-4.7/series index 8a163e4cc61..7bd07d0598e 100644 --- a/queue-4.7/series +++ b/queue-4.7/series @@ -26,3 +26,19 @@ brcmfmac-use-correct-skb-freeing-helper-when-deleting-flowring.patch asoc-intel-atom-add-a-missing-star-in-a-memcpy-call.patch reiserfs-unlock-superblock-before-calling-reiserfs_quota_on_mount.patch async_pq_val-fix-dma-memory-leak.patch +scsi-arcmsr-buffer-overflow-in-arcmsr_iop_message_xfer.patch +scsi-arcmsr-simplify-user_len-checking.patch +scsi-ibmvfc-fix-i-o-hang-when-port-is-not-mapped.patch +vfs-mm-fix-a-dead-loop-in-truncate_inode_pages_range.patch +ext4-enforce-online-defrag-restriction-for-encrypted-files.patch +ext4-reinforce-check-of-i_dtime-when-clearing-high-fields-of-uid-and-gid.patch +ext4-bugfix-for-mmaped-pages-in-mpage_release_unused_pages.patch +ext4-fix-memory-leak-in-ext4_insert_range.patch +ext4-allow-dax-writeback-for-hole-punch.patch +ext4-release-bh-in-make_indexed_dir.patch +ext4-unmap-metadata-when-zeroing-blocks.patch +crypto-ghash-generic-move-common-definitions-to-a-new-header-file.patch +crypto-vmx-fix-memory-corruption-caused-by-p8_ghash.patch +dlm-free-workqueues-after-the-connections.patch +vfs-move-permission-checking-into-notify_change-for-utimes-null.patch +cachefiles-fix-attempt-to-read-i_blocks-after-deleting-file.patch diff --git a/queue-4.7/vfs-mm-fix-a-dead-loop-in-truncate_inode_pages_range.patch b/queue-4.7/vfs-mm-fix-a-dead-loop-in-truncate_inode_pages_range.patch new file mode 100644 index 00000000000..75a8547239d --- /dev/null +++ b/queue-4.7/vfs-mm-fix-a-dead-loop-in-truncate_inode_pages_range.patch @@ -0,0 +1,82 @@ +From c2a9737f45e27d8263ff9643f994bda9bac0b944 Mon Sep 17 00:00:00 2001 +From: Wei Fang +Date: Fri, 7 Oct 2016 17:01:52 -0700 +Subject: vfs,mm: fix a dead loop in truncate_inode_pages_range() + +From: Wei Fang + +commit c2a9737f45e27d8263ff9643f994bda9bac0b944 upstream. + +We triggered a deadloop in truncate_inode_pages_range() on 32 bits +architecture with the test case bellow: + + ... + fd = open(); + write(fd, buf, 4096); + preadv64(fd, &iovec, 1, 0xffffffff000); + ftruncate(fd, 0); + ... + +Then ftruncate() will not return forever. + +The filesystem used in this case is ubifs, but it can be triggered on +many other filesystems. + +When preadv64() is called with offset=0xffffffff000, a page with +index=0xffffffff will be added to the radix tree of ->mapping. Then +this page can be found in ->mapping with pagevec_lookup(). After that, +truncate_inode_pages_range(), which is called in ftruncate(), will fall +into an infinite loop: + + - find a page with index=0xffffffff, since index>=end, this page won't + be truncated + + - index++, and index become 0 + + - the page with index=0xffffffff will be found again + +The data type of index is unsigned long, so index won't overflow to 0 on +64 bits architecture in this case, and the dead loop won't happen. + +Since truncate_inode_pages_range() is executed with holding lock of +inode->i_rwsem, any operation related with this lock will be blocked, +and a hung task will happen, e.g.: + + INFO: task truncate_test:3364 blocked for more than 120 seconds. + ... + call_rwsem_down_write_failed+0x17/0x30 + generic_file_write_iter+0x32/0x1c0 + ubifs_write_iter+0xcc/0x170 + __vfs_write+0xc4/0x120 + vfs_write+0xb2/0x1b0 + SyS_write+0x46/0xa0 + +The page with index=0xffffffff added to ->mapping is useless. Fix this +by checking the read position before allocating pages. + +Link: http://lkml.kernel.org/r/1475151010-40166-1-git-send-email-fangwei1@huawei.com +Signed-off-by: Wei Fang +Cc: Christoph Hellwig +Cc: Dave Chinner +Cc: Al Viro +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + mm/filemap.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/mm/filemap.c ++++ b/mm/filemap.c +@@ -1609,6 +1609,10 @@ static ssize_t do_generic_file_read(stru + unsigned int prev_offset; + int error = 0; + ++ if (unlikely(*ppos >= inode->i_sb->s_maxbytes)) ++ return -EINVAL; ++ iov_iter_truncate(iter, inode->i_sb->s_maxbytes); ++ + index = *ppos >> PAGE_SHIFT; + prev_index = ra->prev_pos >> PAGE_SHIFT; + prev_offset = ra->prev_pos & (PAGE_SIZE-1); diff --git a/queue-4.7/vfs-move-permission-checking-into-notify_change-for-utimes-null.patch b/queue-4.7/vfs-move-permission-checking-into-notify_change-for-utimes-null.patch new file mode 100644 index 00000000000..28f573e5718 --- /dev/null +++ b/queue-4.7/vfs-move-permission-checking-into-notify_change-for-utimes-null.patch @@ -0,0 +1,97 @@ +From f2b20f6ee842313a0d681dbbf7f87b70291a6a3b Mon Sep 17 00:00:00 2001 +From: Miklos Szeredi +Date: Fri, 16 Sep 2016 12:44:20 +0200 +Subject: vfs: move permission checking into notify_change() for utimes(NULL) + +From: Miklos Szeredi + +commit f2b20f6ee842313a0d681dbbf7f87b70291a6a3b upstream. + +This fixes a bug where the permission was not properly checked in +overlayfs. The testcase is ltp/utimensat01. + +It is also cleaner and safer to do the permission checking in the vfs +helper instead of the caller. + +This patch introduces an additional ia_valid flag ATTR_TOUCH (since +touch(1) is the most obvious user of utimes(NULL)) that is passed into +notify_change whenever the conditions for this special permission checking +mode are met. + +Reported-by: Aihua Zhang +Signed-off-by: Miklos Szeredi +Tested-by: Aihua Zhang +Signed-off-by: Greg Kroah-Hartman + +--- + fs/attr.c | 15 +++++++++++++++ + fs/utimes.c | 16 +--------------- + include/linux/fs.h | 1 + + 3 files changed, 17 insertions(+), 15 deletions(-) + +--- a/fs/attr.c ++++ b/fs/attr.c +@@ -202,6 +202,21 @@ int notify_change(struct dentry * dentry + return -EPERM; + } + ++ /* ++ * If utimes(2) and friends are called with times == NULL (or both ++ * times are UTIME_NOW), then we need to check for write permission ++ */ ++ if (ia_valid & ATTR_TOUCH) { ++ if (IS_IMMUTABLE(inode)) ++ return -EPERM; ++ ++ if (!inode_owner_or_capable(inode)) { ++ error = inode_permission(inode, MAY_WRITE); ++ if (error) ++ return error; ++ } ++ } ++ + if ((ia_valid & ATTR_MODE)) { + umode_t amode = attr->ia_mode; + /* Flag setting protected by i_mutex */ +--- a/fs/utimes.c ++++ b/fs/utimes.c +@@ -87,20 +87,7 @@ static int utimes_common(struct path *pa + */ + newattrs.ia_valid |= ATTR_TIMES_SET; + } else { +- /* +- * If times is NULL (or both times are UTIME_NOW), +- * then we need to check permissions, because +- * inode_change_ok() won't do it. +- */ +- error = -EACCES; +- if (IS_IMMUTABLE(inode)) +- goto mnt_drop_write_and_out; +- +- if (!inode_owner_or_capable(inode)) { +- error = inode_permission(inode, MAY_WRITE); +- if (error) +- goto mnt_drop_write_and_out; +- } ++ newattrs.ia_valid |= ATTR_TOUCH; + } + retry_deleg: + inode_lock(inode); +@@ -112,7 +99,6 @@ retry_deleg: + goto retry_deleg; + } + +-mnt_drop_write_and_out: + mnt_drop_write(path->mnt); + out: + return error; +--- a/include/linux/fs.h ++++ b/include/linux/fs.h +@@ -228,6 +228,7 @@ typedef int (dio_iodone_t)(struct kiocb + #define ATTR_KILL_PRIV (1 << 14) + #define ATTR_OPEN (1 << 15) /* Truncating from open(O_TRUNC) */ + #define ATTR_TIMES_SET (1 << 16) ++#define ATTR_TOUCH (1 << 17) + + /* + * Whiteout is represented by a char device. The following constants define the