]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.4-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 5 Mar 2014 18:34:52 +0000 (10:34 -0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 5 Mar 2014 18:34:52 +0000 (10:34 -0800)
added patches:
fuse-hotfix-truncate_pagecache-issue.patch
fuse-readdir-check-for-slash-in-names.patch
libceph-unregister-request-in-__map_request-failed-and-nofail-false.patch
nilfs2-fix-issue-with-race-condition-of-competition-between-segments-for-dirty-blocks.patch

queue-3.4/fuse-hotfix-truncate_pagecache-issue.patch [new file with mode: 0644]
queue-3.4/fuse-readdir-check-for-slash-in-names.patch [new file with mode: 0644]
queue-3.4/libceph-unregister-request-in-__map_request-failed-and-nofail-false.patch [new file with mode: 0644]
queue-3.4/nilfs2-fix-issue-with-race-condition-of-competition-between-segments-for-dirty-blocks.patch [new file with mode: 0644]
queue-3.4/series

diff --git a/queue-3.4/fuse-hotfix-truncate_pagecache-issue.patch b/queue-3.4/fuse-hotfix-truncate_pagecache-issue.patch
new file mode 100644 (file)
index 0000000..0c54967
--- /dev/null
@@ -0,0 +1,194 @@
+From 9417815157557d273325641f7ad2b6dd147276f4 Mon Sep 17 00:00:00 2001
+From: Maxim Patlasov <MPatlasov@parallels.com>
+Date: Fri, 30 Aug 2013 17:06:04 +0400
+Subject: fuse: hotfix truncate_pagecache() issue
+
+From: Maxim Patlasov <MPatlasov@parallels.com>
+
+commit 06a7c3c2781409af95000c60a5df743fd4e2f8b4 upstream.
+
+The way how fuse calls truncate_pagecache() from fuse_change_attributes()
+is completely wrong. Because, w/o i_mutex held, we never sure whether
+'oldsize' and 'attr->size' are valid by the time of execution of
+truncate_pagecache(inode, oldsize, attr->size). In fact, as soon as we
+released fc->lock in the middle of fuse_change_attributes(), we completely
+loose control of actions which may happen with given inode until we reach
+truncate_pagecache. The list of potentially dangerous actions includes
+mmap-ed reads and writes, ftruncate(2) and write(2) extending file size.
+
+The typical outcome of doing truncate_pagecache() with outdated arguments
+is data corruption from user point of view. This is (in some sense)
+acceptable in cases when the issue is triggered by a change of the file on
+the server (i.e. externally wrt fuse operation), but it is absolutely
+intolerable in scenarios when a single fuse client modifies a file without
+any external intervention. A real life case I discovered by fsx-linux
+looked like this:
+
+1. Shrinking ftruncate(2) comes to fuse_do_setattr(). The latter sends
+FUSE_SETATTR to the server synchronously, but before getting fc->lock ...
+2. fuse_dentry_revalidate() is asynchronously called. It sends FUSE_LOOKUP
+to the server synchronously, then calls fuse_change_attributes(). The
+latter updates i_size, releases fc->lock, but before comparing oldsize vs
+attr->size..
+3. fuse_do_setattr() from the first step proceeds by acquiring fc->lock and
+updating attributes and i_size, but now oldsize is equal to
+outarg.attr.size because i_size has just been updated (step 2). Hence,
+fuse_do_setattr() returns w/o calling truncate_pagecache().
+4. As soon as ftruncate(2) completes, the user extends file size by
+write(2) making a hole in the middle of file, then reads data from the hole
+either by read(2) or mmap-ed read. The user expects to get zero data from
+the hole, but gets stale data because truncate_pagecache() is not executed
+yet.
+
+The scenario above illustrates one side of the problem: not truncating the
+page cache even though we should. Another side corresponds to truncating
+page cache too late, when the state of inode changed significantly.
+Theoretically, the following is possible:
+
+1. As in the previous scenario fuse_dentry_revalidate() discovered that
+i_size changed (due to our own fuse_do_setattr()) and is going to call
+truncate_pagecache() for some 'new_size' it believes valid right now. But
+by the time that particular truncate_pagecache() is called ...
+2. fuse_do_setattr() returns (either having called truncate_pagecache() or
+not -- it doesn't matter).
+3. The file is extended either by write(2) or ftruncate(2) or fallocate(2).
+4. mmap-ed write makes a page in the extended region dirty.
+
+The result will be the lost of data user wrote on the fourth step.
+
+The patch is a hotfix resolving the issue in a simplistic way: let's skip
+dangerous i_size update and truncate_pagecache if an operation changing
+file size is in progress. This simplistic approach looks correct for the
+cases w/o external changes. And to handle them properly, more sophisticated
+and intrusive techniques (e.g. NFS-like one) would be required. I'd like to
+postpone it until the issue is well discussed on the mailing list(s).
+
+Changed in v2:
+ - improved patch description to cover both sides of the issue.
+
+Signed-off-by: Maxim Patlasov <mpatlasov@parallels.com>
+Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
+[bwh: Backported to 3.2: add the fuse_inode::state field which we didn't have]
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+Cc: Rui Xiang <rui.xiang@huawei.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/fuse/dir.c    |    7 ++++++-
+ fs/fuse/file.c   |    8 +++++++-
+ fs/fuse/fuse_i.h |    9 +++++++++
+ fs/fuse/inode.c  |    4 +++-
+ 4 files changed, 25 insertions(+), 3 deletions(-)
+
+--- a/fs/fuse/dir.c
++++ b/fs/fuse/dir.c
+@@ -1348,6 +1348,7 @@ static int fuse_do_setattr(struct dentry
+ {
+       struct inode *inode = entry->d_inode;
+       struct fuse_conn *fc = get_fuse_conn(inode);
++      struct fuse_inode *fi = get_fuse_inode(inode);
+       struct fuse_req *req;
+       struct fuse_setattr_in inarg;
+       struct fuse_attr_out outarg;
+@@ -1378,8 +1379,10 @@ static int fuse_do_setattr(struct dentry
+       if (IS_ERR(req))
+               return PTR_ERR(req);
+-      if (is_truncate)
++      if (is_truncate) {
+               fuse_set_nowrite(inode);
++              set_bit(FUSE_I_SIZE_UNSTABLE, &fi->state);
++      }
+       memset(&inarg, 0, sizeof(inarg));
+       memset(&outarg, 0, sizeof(outarg));
+@@ -1441,12 +1444,14 @@ static int fuse_do_setattr(struct dentry
+               invalidate_inode_pages2(inode->i_mapping);
+       }
++      clear_bit(FUSE_I_SIZE_UNSTABLE, &fi->state);
+       return 0;
+ error:
+       if (is_truncate)
+               fuse_release_nowrite(inode);
++      clear_bit(FUSE_I_SIZE_UNSTABLE, &fi->state);
+       return err;
+ }
+--- a/fs/fuse/file.c
++++ b/fs/fuse/file.c
+@@ -515,7 +515,8 @@ static void fuse_read_update_size(struct
+       struct fuse_inode *fi = get_fuse_inode(inode);
+       spin_lock(&fc->lock);
+-      if (attr_ver == fi->attr_version && size < inode->i_size) {
++      if (attr_ver == fi->attr_version && size < inode->i_size &&
++          !test_bit(FUSE_I_SIZE_UNSTABLE, &fi->state)) {
+               fi->attr_version = ++fc->attr_version;
+               i_size_write(inode, size);
+       }
+@@ -877,12 +878,16 @@ static ssize_t fuse_perform_write(struct
+ {
+       struct inode *inode = mapping->host;
+       struct fuse_conn *fc = get_fuse_conn(inode);
++      struct fuse_inode *fi = get_fuse_inode(inode);
+       int err = 0;
+       ssize_t res = 0;
+       if (is_bad_inode(inode))
+               return -EIO;
++      if (inode->i_size < pos + iov_iter_count(ii))
++              set_bit(FUSE_I_SIZE_UNSTABLE, &fi->state);
++
+       do {
+               struct fuse_req *req;
+               ssize_t count;
+@@ -917,6 +922,7 @@ static ssize_t fuse_perform_write(struct
+       if (res > 0)
+               fuse_write_update_size(inode, pos);
++      clear_bit(FUSE_I_SIZE_UNSTABLE, &fi->state);
+       fuse_invalidate_attr(inode);
+       return res > 0 ? res : err;
+--- a/fs/fuse/fuse_i.h
++++ b/fs/fuse/fuse_i.h
+@@ -103,6 +103,15 @@ struct fuse_inode {
+       /** List of writepage requestst (pending or sent) */
+       struct list_head writepages;
++
++      /** Miscellaneous bits describing inode state */
++      unsigned long state;
++};
++
++/** FUSE inode state bits */
++enum {
++      /** An operation changing file size is in progress  */
++      FUSE_I_SIZE_UNSTABLE,
+ };
+ struct fuse_conn;
+--- a/fs/fuse/inode.c
++++ b/fs/fuse/inode.c
+@@ -92,6 +92,7 @@ static struct inode *fuse_alloc_inode(st
+       fi->attr_version = 0;
+       fi->writectr = 0;
+       fi->orig_ino = 0;
++      fi->state = 0;
+       INIT_LIST_HEAD(&fi->write_files);
+       INIT_LIST_HEAD(&fi->queued_writes);
+       INIT_LIST_HEAD(&fi->writepages);
+@@ -199,7 +200,8 @@ void fuse_change_attributes(struct inode
+       loff_t oldsize;
+       spin_lock(&fc->lock);
+-      if (attr_version != 0 && fi->attr_version > attr_version) {
++      if ((attr_version != 0 && fi->attr_version > attr_version) ||
++          test_bit(FUSE_I_SIZE_UNSTABLE, &fi->state)) {
+               spin_unlock(&fc->lock);
+               return;
+       }
diff --git a/queue-3.4/fuse-readdir-check-for-slash-in-names.patch b/queue-3.4/fuse-readdir-check-for-slash-in-names.patch
new file mode 100644 (file)
index 0000000..a7a0609
--- /dev/null
@@ -0,0 +1,34 @@
+From b5f9e3533584d2fb6c90c63da767b85421b07def Mon Sep 17 00:00:00 2001
+From: Miklos Szeredi <mszeredi@suse.cz>
+Date: Tue, 3 Sep 2013 14:28:38 +0200
+Subject: fuse: readdir: check for slash in names
+
+From: Miklos Szeredi <mszeredi@suse.cz>
+
+commit efeb9e60d48f7778fdcad4a0f3ad9ea9b19e5dfd upstream.
+
+Userspace can add names containing a slash character to the directory
+listing.  Don't allow this as it could cause all sorts of trouble.
+
+Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
+[bwh: Backported to 3.2: drop changes to parse_dirplusfile() which we
+ don't have]
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+Cc: Rui Xiang <rui.xiang@huawei.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/fuse/dir.c |    2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/fs/fuse/dir.c
++++ b/fs/fuse/dir.c
+@@ -1103,6 +1103,8 @@ static int parse_dirfile(char *buf, size
+                       return -EIO;
+               if (reclen > nbytes)
+                       break;
++              if (memchr(dirent->name, '/', dirent->namelen) != NULL)
++                      return -EIO;
+               over = filldir(dstbuf, dirent->name, dirent->namelen,
+                              file->f_pos, dirent->ino, dirent->type);
diff --git a/queue-3.4/libceph-unregister-request-in-__map_request-failed-and-nofail-false.patch b/queue-3.4/libceph-unregister-request-in-__map_request-failed-and-nofail-false.patch
new file mode 100644 (file)
index 0000000..db8019b
--- /dev/null
@@ -0,0 +1,35 @@
+From be47dfad8e39e8b849fd0487292b3998284ddbc2 Mon Sep 17 00:00:00 2001
+From: majianpeng <majianpeng@gmail.com>
+Date: Tue, 16 Jul 2013 15:45:48 +0800
+Subject: libceph: unregister request in __map_request failed and nofail == false
+
+From: majianpeng <majianpeng@gmail.com>
+
+commit 73d9f7eef3d98c3920e144797cc1894c6b005a1e upstream.
+
+For nofail == false request, if __map_request failed, the caller does
+cleanup work, like releasing the relative pages.  It doesn't make any sense
+to retry this request.
+
+Signed-off-by: Jianpeng Ma <majianpeng@gmail.com>
+Reviewed-by: Sage Weil <sage@inktank.com>
+[bwh: Backported to 3.2: adjust indentation]
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+Cc: Rui Xiang <rui.xiang@huawei.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ net/ceph/osd_client.c |    2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/net/ceph/osd_client.c
++++ b/net/ceph/osd_client.c
+@@ -1721,6 +1721,8 @@ int ceph_osdc_start_request(struct ceph_
+                               dout("osdc_start_request failed map, "
+                                    " will retry %lld\n", req->r_tid);
+                               rc = 0;
++                      } else {
++                              __unregister_request(osdc, req);
+                       }
+                       goto out_unlock;
+               }
diff --git a/queue-3.4/nilfs2-fix-issue-with-race-condition-of-competition-between-segments-for-dirty-blocks.patch b/queue-3.4/nilfs2-fix-issue-with-race-condition-of-competition-between-segments-for-dirty-blocks.patch
new file mode 100644 (file)
index 0000000..f2f26e5
--- /dev/null
@@ -0,0 +1,289 @@
+From ccebcc74c81d8399c7b204aea47c1f33b09c2b17 Mon Sep 17 00:00:00 2001
+From: Vyacheslav Dubeyko <slava@dubeyko.com>
+Date: Mon, 30 Sep 2013 13:45:12 -0700
+Subject: nilfs2: fix issue with race condition of competition between segments for dirty blocks
+
+From: Vyacheslav Dubeyko <slava@dubeyko.com>
+
+commit 7f42ec3941560f0902fe3671e36f2c20ffd3af0a upstream.
+
+Many NILFS2 users were reported about strange file system corruption
+(for example):
+
+   NILFS: bad btree node (blocknr=185027): level = 0, flags = 0x0, nchildren = 768
+   NILFS error (device sda4): nilfs_bmap_last_key: broken bmap (inode number=11540)
+
+But such error messages are consequence of file system's issue that takes
+place more earlier.  Fortunately, Jerome Poulin <jeromepoulin@gmail.com>
+and Anton Eliasson <devel@antoneliasson.se> were reported about another
+issue not so recently.  These reports describe the issue with segctor
+thread's crash:
+
+  BUG: unable to handle kernel paging request at 0000000000004c83
+  IP: nilfs_end_page_io+0x12/0xd0 [nilfs2]
+
+  Call Trace:
+   nilfs_segctor_do_construct+0xf25/0x1b20 [nilfs2]
+   nilfs_segctor_construct+0x17b/0x290 [nilfs2]
+   nilfs_segctor_thread+0x122/0x3b0 [nilfs2]
+   kthread+0xc0/0xd0
+   ret_from_fork+0x7c/0xb0
+
+These two issues have one reason.  This reason can raise third issue
+too.  Third issue results in hanging of segctor thread with eating of
+100% CPU.
+
+REPRODUCING PATH:
+
+One of the possible way or the issue reproducing was described by
+Jermoe me Poulin <jeromepoulin@gmail.com>:
+
+1. init S to get to single user mode.
+2. sysrq+E to make sure only my shell is running
+3. start network-manager to get my wifi connection up
+4. login as root and launch "screen"
+5. cd /boot/log/nilfs which is a ext3 mount point and can log when NILFS dies.
+6. lscp | xz -9e > lscp.txt.xz
+7. mount my snapshot using mount -o cp=3360839,ro /dev/vgUbuntu/root /mnt/nilfs
+8. start a screen to dump /proc/kmsg to text file since rsyslog is killed
+9. start a screen and launch strace -f -o find-cat.log -t find
+/mnt/nilfs -type f -exec cat {} > /dev/null \;
+10. start a screen and launch strace -f -o apt-get.log -t apt-get update
+11. launch the last command again as it did not crash the first time
+12. apt-get crashes
+13. ps aux > ps-aux-crashed.log
+13. sysrq+W
+14. sysrq+E  wait for everything to terminate
+15. sysrq+SUSB
+
+Simplified way of the issue reproducing is starting kernel compilation
+task and "apt-get update" in parallel.
+
+REPRODUCIBILITY:
+
+The issue is reproduced not stable [60% - 80%].  It is very important to
+have proper environment for the issue reproducing.  The critical
+conditions for successful reproducing:
+
+(1) It should have big modified file by mmap() way.
+
+(2) This file should have the count of dirty blocks are greater that
+    several segments in size (for example, two or three) from time to time
+    during processing.
+
+(3) It should be intensive background activity of files modification
+    in another thread.
+
+INVESTIGATION:
+
+First of all, it is possible to see that the reason of crash is not valid
+page address:
+
+  NILFS [nilfs_segctor_complete_write]:2100 bh->b_count 0, bh->b_blocknr 13895680, bh->b_size 13897727, bh->b_page 0000000000001a82
+  NILFS [nilfs_segctor_complete_write]:2101 segbuf->sb_segnum 6783
+
+Moreover, value of b_page (0x1a82) is 6786.  This value looks like segment
+number.  And b_blocknr with b_size values look like block numbers.  So,
+buffer_head's pointer points on not proper address value.
+
+Detailed investigation of the issue is discovered such picture:
+
+  [-----------------------------SEGMENT 6783-------------------------------]
+  NILFS [nilfs_segctor_do_construct]:2310 nilfs_segctor_begin_construction
+  NILFS [nilfs_segctor_do_construct]:2321 nilfs_segctor_collect
+  NILFS [nilfs_segctor_do_construct]:2336 nilfs_segctor_assign
+  NILFS [nilfs_segctor_do_construct]:2367 nilfs_segctor_update_segusage
+  NILFS [nilfs_segctor_do_construct]:2371 nilfs_segctor_prepare_write
+  NILFS [nilfs_segctor_do_construct]:2376 nilfs_add_checksums_on_logs
+  NILFS [nilfs_segctor_do_construct]:2381 nilfs_segctor_write
+  NILFS [nilfs_segbuf_submit_bio]:464 bio->bi_sector 111149024, segbuf->sb_segnum 6783
+
+  [-----------------------------SEGMENT 6784-------------------------------]
+  NILFS [nilfs_segctor_do_construct]:2310 nilfs_segctor_begin_construction
+  NILFS [nilfs_segctor_do_construct]:2321 nilfs_segctor_collect
+  NILFS [nilfs_lookup_dirty_data_buffers]:782 bh->b_count 1, bh->b_page ffffea000709b000, page->index 0, i_ino 1033103, i_size 25165824
+  NILFS [nilfs_lookup_dirty_data_buffers]:783 bh->b_assoc_buffers.next ffff8802174a6798, bh->b_assoc_buffers.prev ffff880221cffee8
+  NILFS [nilfs_segctor_do_construct]:2336 nilfs_segctor_assign
+  NILFS [nilfs_segctor_do_construct]:2367 nilfs_segctor_update_segusage
+  NILFS [nilfs_segctor_do_construct]:2371 nilfs_segctor_prepare_write
+  NILFS [nilfs_segctor_do_construct]:2376 nilfs_add_checksums_on_logs
+  NILFS [nilfs_segctor_do_construct]:2381 nilfs_segctor_write
+  NILFS [nilfs_segbuf_submit_bh]:575 bh->b_count 1, bh->b_page ffffea000709b000, page->index 0, i_ino 1033103, i_size 25165824
+  NILFS [nilfs_segbuf_submit_bh]:576 segbuf->sb_segnum 6784
+  NILFS [nilfs_segbuf_submit_bh]:577 bh->b_assoc_buffers.next ffff880218a0d5f8, bh->b_assoc_buffers.prev ffff880218bcdf50
+  NILFS [nilfs_segbuf_submit_bio]:464 bio->bi_sector 111150080, segbuf->sb_segnum 6784, segbuf->sb_nbio 0
+  [----------] ditto
+  NILFS [nilfs_segbuf_submit_bio]:464 bio->bi_sector 111164416, segbuf->sb_segnum 6784, segbuf->sb_nbio 15
+
+  [-----------------------------SEGMENT 6785-------------------------------]
+  NILFS [nilfs_segctor_do_construct]:2310 nilfs_segctor_begin_construction
+  NILFS [nilfs_segctor_do_construct]:2321 nilfs_segctor_collect
+  NILFS [nilfs_lookup_dirty_data_buffers]:782 bh->b_count 2, bh->b_page ffffea000709b000, page->index 0, i_ino 1033103, i_size 25165824
+  NILFS [nilfs_lookup_dirty_data_buffers]:783 bh->b_assoc_buffers.next ffff880219277e80, bh->b_assoc_buffers.prev ffff880221cffc88
+  NILFS [nilfs_segctor_do_construct]:2367 nilfs_segctor_update_segusage
+  NILFS [nilfs_segctor_do_construct]:2371 nilfs_segctor_prepare_write
+  NILFS [nilfs_segctor_do_construct]:2376 nilfs_add_checksums_on_logs
+  NILFS [nilfs_segctor_do_construct]:2381 nilfs_segctor_write
+  NILFS [nilfs_segbuf_submit_bh]:575 bh->b_count 2, bh->b_page ffffea000709b000, page->index 0, i_ino 1033103, i_size 25165824
+  NILFS [nilfs_segbuf_submit_bh]:576 segbuf->sb_segnum 6785
+  NILFS [nilfs_segbuf_submit_bh]:577 bh->b_assoc_buffers.next ffff880218a0d5f8, bh->b_assoc_buffers.prev ffff880222cc7ee8
+  NILFS [nilfs_segbuf_submit_bio]:464 bio->bi_sector 111165440, segbuf->sb_segnum 6785, segbuf->sb_nbio 0
+  [----------] ditto
+  NILFS [nilfs_segbuf_submit_bio]:464 bio->bi_sector 111177728, segbuf->sb_segnum 6785, segbuf->sb_nbio 12
+
+  NILFS [nilfs_segctor_do_construct]:2399 nilfs_segctor_wait
+  NILFS [nilfs_segbuf_wait]:676 segbuf->sb_segnum 6783
+  NILFS [nilfs_segbuf_wait]:676 segbuf->sb_segnum 6784
+  NILFS [nilfs_segbuf_wait]:676 segbuf->sb_segnum 6785
+
+  NILFS [nilfs_segctor_complete_write]:2100 bh->b_count 0, bh->b_blocknr 13895680, bh->b_size 13897727, bh->b_page 0000000000001a82
+
+  BUG: unable to handle kernel paging request at 0000000000001a82
+  IP: [<ffffffffa024d0f2>] nilfs_end_page_io+0x12/0xd0 [nilfs2]
+
+Usually, for every segment we collect dirty files in list.  Then, dirty
+blocks are gathered for every dirty file, prepared for write and
+submitted by means of nilfs_segbuf_submit_bh() call.  Finally, it takes
+place complete write phase after calling nilfs_end_bio_write() on the
+block layer.  Buffers/pages are marked as not dirty on final phase and
+processed files removed from the list of dirty files.
+
+It is possible to see that we had three prepare_write and submit_bio
+phases before segbuf_wait and complete_write phase.  Moreover, segments
+compete between each other for dirty blocks because on every iteration
+of segments processing dirty buffer_heads are added in several lists of
+payload_buffers:
+
+  [SEGMENT 6784]: bh->b_assoc_buffers.next ffff880218a0d5f8, bh->b_assoc_buffers.prev ffff880218bcdf50
+  [SEGMENT 6785]: bh->b_assoc_buffers.next ffff880218a0d5f8, bh->b_assoc_buffers.prev ffff880222cc7ee8
+
+The next pointer is the same but prev pointer has changed.  It means
+that buffer_head has next pointer from one list but prev pointer from
+another.  Such modification can be made several times.  And, finally, it
+can be resulted in various issues: (1) segctor hanging, (2) segctor
+crashing, (3) file system metadata corruption.
+
+FIX:
+This patch adds:
+
+(1) setting of BH_Async_Write flag in nilfs_segctor_prepare_write()
+    for every proccessed dirty block;
+
+(2) checking of BH_Async_Write flag in
+    nilfs_lookup_dirty_data_buffers() and
+    nilfs_lookup_dirty_node_buffers();
+
+(3) clearing of BH_Async_Write flag in nilfs_segctor_complete_write(),
+    nilfs_abort_logs(), nilfs_forget_buffer(), nilfs_clear_dirty_page().
+
+Reported-by: Jerome Poulin <jeromepoulin@gmail.com>
+Reported-by: Anton Eliasson <devel@antoneliasson.se>
+Cc: Paul Fertser <fercerpav@gmail.com>
+Cc: ARAI Shun-ichi <hermes@ceres.dti.ne.jp>
+Cc: Piotr Szymaniak <szarpaj@grubelek.pl>
+Cc: Juan Barry Manuel Canham <Linux@riotingpacifist.net>
+Cc: Zahid Chowdhury <zahid.chowdhury@starsolutions.com>
+Cc: Elmer Zhang <freeboy6716@gmail.com>
+Cc: Kenneth Langga <klangga@gmail.com>
+Signed-off-by: Vyacheslav Dubeyko <slava@dubeyko.com>
+Acked-by: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+[bwh: Backported to 3.2: nilfs_clear_dirty_page() has not been separated
+ from nilfs_clear_dirty_pages()]
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+Cc: Rui Xiang <rui.xiang@huawei.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/nilfs2/page.c    |    2 ++
+ fs/nilfs2/segment.c |   11 +++++++++--
+ 2 files changed, 11 insertions(+), 2 deletions(-)
+
+--- a/fs/nilfs2/page.c
++++ b/fs/nilfs2/page.c
+@@ -94,6 +94,7 @@ void nilfs_forget_buffer(struct buffer_h
+       clear_buffer_nilfs_volatile(bh);
+       clear_buffer_nilfs_checked(bh);
+       clear_buffer_nilfs_redirected(bh);
++      clear_buffer_async_write(bh);
+       clear_buffer_dirty(bh);
+       if (nilfs_page_buffers_clean(page))
+               __nilfs_clear_page_dirty(page);
+@@ -390,6 +391,7 @@ void nilfs_clear_dirty_pages(struct addr
+                       bh = head = page_buffers(page);
+                       do {
+                               lock_buffer(bh);
++                              clear_buffer_async_write(bh);
+                               clear_buffer_dirty(bh);
+                               clear_buffer_nilfs_volatile(bh);
+                               clear_buffer_nilfs_checked(bh);
+--- a/fs/nilfs2/segment.c
++++ b/fs/nilfs2/segment.c
+@@ -662,7 +662,7 @@ static size_t nilfs_lookup_dirty_data_bu
+               bh = head = page_buffers(page);
+               do {
+-                      if (!buffer_dirty(bh))
++                      if (!buffer_dirty(bh) || buffer_async_write(bh))
+                               continue;
+                       get_bh(bh);
+                       list_add_tail(&bh->b_assoc_buffers, listp);
+@@ -696,7 +696,8 @@ static void nilfs_lookup_dirty_node_buff
+               for (i = 0; i < pagevec_count(&pvec); i++) {
+                       bh = head = page_buffers(pvec.pages[i]);
+                       do {
+-                              if (buffer_dirty(bh)) {
++                              if (buffer_dirty(bh) &&
++                                              !buffer_async_write(bh)) {
+                                       get_bh(bh);
+                                       list_add_tail(&bh->b_assoc_buffers,
+                                                     listp);
+@@ -1578,6 +1579,7 @@ static void nilfs_segctor_prepare_write(
+               list_for_each_entry(bh, &segbuf->sb_segsum_buffers,
+                                   b_assoc_buffers) {
++                      set_buffer_async_write(bh);
+                       if (bh->b_page != bd_page) {
+                               if (bd_page) {
+                                       lock_page(bd_page);
+@@ -1591,6 +1593,7 @@ static void nilfs_segctor_prepare_write(
+               list_for_each_entry(bh, &segbuf->sb_payload_buffers,
+                                   b_assoc_buffers) {
++                      set_buffer_async_write(bh);
+                       if (bh == segbuf->sb_super_root) {
+                               if (bh->b_page != bd_page) {
+                                       lock_page(bd_page);
+@@ -1676,6 +1679,7 @@ static void nilfs_abort_logs(struct list
+       list_for_each_entry(segbuf, logs, sb_list) {
+               list_for_each_entry(bh, &segbuf->sb_segsum_buffers,
+                                   b_assoc_buffers) {
++                      clear_buffer_async_write(bh);
+                       if (bh->b_page != bd_page) {
+                               if (bd_page)
+                                       end_page_writeback(bd_page);
+@@ -1685,6 +1689,7 @@ static void nilfs_abort_logs(struct list
+               list_for_each_entry(bh, &segbuf->sb_payload_buffers,
+                                   b_assoc_buffers) {
++                      clear_buffer_async_write(bh);
+                       if (bh == segbuf->sb_super_root) {
+                               if (bh->b_page != bd_page) {
+                                       end_page_writeback(bd_page);
+@@ -1754,6 +1759,7 @@ static void nilfs_segctor_complete_write
+                                   b_assoc_buffers) {
+                       set_buffer_uptodate(bh);
+                       clear_buffer_dirty(bh);
++                      clear_buffer_async_write(bh);
+                       if (bh->b_page != bd_page) {
+                               if (bd_page)
+                                       end_page_writeback(bd_page);
+@@ -1775,6 +1781,7 @@ static void nilfs_segctor_complete_write
+                                   b_assoc_buffers) {
+                       set_buffer_uptodate(bh);
+                       clear_buffer_dirty(bh);
++                      clear_buffer_async_write(bh);
+                       clear_buffer_delay(bh);
+                       clear_buffer_nilfs_volatile(bh);
+                       clear_buffer_nilfs_redirected(bh);
index c1875848a4571783902e928be048dc5196d7e0e1..51dcb439192b7274ee11331cfd0825dfad44ee47 100644 (file)
@@ -51,3 +51,7 @@ cgroup-fix-rcu-accesses-to-task-cgroups.patch
 mm-hotplug-correctly-add-new-zone-to-all-other-nodes-zone-lists.patch
 perf-tools-remove-extraneous-newline-when-parsing-hardware-cache-events.patch
 perf-tools-fix-cache-event-name-generation.patch
+nilfs2-fix-issue-with-race-condition-of-competition-between-segments-for-dirty-blocks.patch
+fuse-readdir-check-for-slash-in-names.patch
+fuse-hotfix-truncate_pagecache-issue.patch
+libceph-unregister-request-in-__map_request-failed-and-nofail-false.patch