alistair23-linux/fs/ocfs2
Ashish Samant 4131d53810 ocfs2: fix double put of recount tree in ocfs2_lock_refcount_tree()
In ocfs2_lock_refcount_tree, if ocfs2_read_refcount_block() returns an
error, we do ocfs2_refcount_tree_put twice (once in
ocfs2_unlock_refcount_tree and once outside it), thereby reducing the
refcount of the refcount tree twice, but we dont delete the tree in this
case.  This will make refcnt of the tree = 0 and the
ocfs2_refcount_tree_put will eventually call ocfs2_mark_lockres_freeing,
setting OCFS2_LOCK_FREEING for the refcount_tree->rf_lockres.

The error returned by ocfs2_read_refcount_block is propagated all the
way back and for next iteration of write, ocfs2_lock_refcount_tree gets
the same tree back from ocfs2_get_refcount_tree because we havent
deleted the tree.  Now we have the same tree, but OCFS2_LOCK_FREEING is
set for rf_lockres and eventually, when _ocfs2_lock_refcount_tree is
called in this iteration, BUG_ON( __ocfs2_cluster_lock:1395 ERROR:
Cluster lock called on freeing lockres T00000000000000000386019775b08d!
flags 0x81) is triggerred.

Call stack:

  (loop16,11155,0):ocfs2_lock_refcount_tree:482 ERROR: status = -5
  (loop16,11155,0):ocfs2_refcount_cow_hunk:3497 ERROR: status = -5
  (loop16,11155,0):ocfs2_refcount_cow:3560 ERROR: status = -5
  (loop16,11155,0):ocfs2_prepare_inode_for_refcount:2111 ERROR: status = -5
  (loop16,11155,0):ocfs2_prepare_inode_for_write:2190 ERROR: status = -5
  (loop16,11155,0):ocfs2_file_write_iter:2331 ERROR: status = -5
  (loop16,11155,0):__ocfs2_cluster_lock:1395 ERROR: bug expression:
  lockres->l_flags & OCFS2_LOCK_FREEING

  (loop16,11155,0):__ocfs2_cluster_lock:1395 ERROR: Cluster lock called on
  freeing lockres T00000000000000000386019775b08d! flags 0x81

  kernel BUG at fs/ocfs2/dlmglue.c:1395!

  invalid opcode: 0000 [#1] SMP  CPU 0
  Modules linked in: tun ocfs2 jbd2 xen_blkback xen_netback xen_gntdev .. sd_mod crc_t10dif ext3 jbd mbcache
  RIP: __ocfs2_cluster_lock+0x31c/0x740 [ocfs2]
  RSP: e02b:ffff88017c0138a0  EFLAGS: 00010086
  Process loop16 (pid: 11155, threadinfo ffff88017c010000, task ffff8801b5374300)
  Call Trace:
     ocfs2_refcount_lock+0xae/0x130 [ocfs2]
     __ocfs2_lock_refcount_tree+0x29/0xe0 [ocfs2]
     ocfs2_lock_refcount_tree+0xdd/0x320 [ocfs2]
     ocfs2_refcount_cow_hunk+0x1cb/0x440 [ocfs2]
     ocfs2_refcount_cow+0xa9/0x1d0 [ocfs2]
     ocfs2_prepare_inode_for_refcount+0x115/0x200 [ocfs2]
     ocfs2_prepare_inode_for_write+0x33b/0x470 [ocfs2]
     ocfs2_file_write_iter+0x220/0x8c0 [ocfs2]
     aio_write_iter+0x2e/0x30

Fix this by avoiding the second call to ocfs2_refcount_tree_put()

Link: http://lkml.kernel.org/r/1473984404-32011-1-git-send-email-ashish.samant@oracle.com
Signed-off-by: Ashish Samant <ashish.samant@oracle.com>
Reviewed-by: Eric Ren <zren@suse.com>
Cc: Mark Fasheh <mfasheh@versity.com>
Cc: Joel Becker <jlbec@evilplan.org>
Cc: Junxiao Bi <junxiao.bi@oracle.com>
Cc: Joseph Qi <jiangqi903@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2016-12-12 18:55:06 -08:00
..
cluster fs/ocfs2/cluster: remove deprecated create_singlethread_workqueue() 2016-10-07 18:46:26 -07:00
dlm ocfs2/dlm: clean up deadcode in dlm_master_request_handler() 2016-12-12 18:55:06 -08:00
dlmfs Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs 2016-10-10 20:16:43 -07:00
acl.c Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs 2016-10-10 20:16:43 -07:00
acl.h ocfs2: fix posix_acl_create deadlock 2016-05-12 15:52:50 -07:00
alloc.c Merge remote-tracking branch 'ovl/rename2' into for-linus 2016-10-10 23:02:51 -04:00
alloc.h ocfs2: retry on ENOSPC if sufficient space in truncate log 2016-08-02 17:31:41 -04:00
aops.c ocfs2: clean up unused 'page' parameter in ocfs2_write_end_nolock() 2016-12-12 18:55:06 -08:00
aops.h ocfs2: clean up unused 'page' parameter in ocfs2_write_end_nolock() 2016-12-12 18:55:06 -08:00
blockcheck.c
blockcheck.h
buffer_head_io.c Merge branch 'for-4.8/core' of git://git.kernel.dk/linux-block 2016-07-26 15:03:07 -07:00
buffer_head_io.h
dcache.c
dcache.h
dir.c ocfs2: fix not enough credit panic 2016-11-11 08:12:37 -08:00
dir.h
dlmglue.c ocfs2: remove obscure BUG_ON in dlmglue 2016-07-26 16:19:19 -07:00
dlmglue.h
export.c
export.h
extent_map.c
extent_map.h
file.c Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs 2016-10-10 20:16:43 -07:00
file.h
filecheck.c
filecheck.h
heartbeat.c
heartbeat.h
inode.c ocfs2: fix improper handling of return errno 2016-05-26 15:35:44 -07:00
inode.h ocfs2: fix undefined struct variable in inode.h 2016-10-07 18:46:26 -07:00
ioctl.c
ioctl.h
journal.c ocfs2: improve recovery performance 2016-07-26 16:19:19 -07:00
journal.h jbd2: add support for avoiding data writes during transaction commits 2016-04-24 00:56:07 -04:00
Kconfig
localalloc.c ocfs2: fix occurring deadlock by changing ocfs2_wq from global to local 2016-03-25 16:37:42 -07:00
localalloc.h
locks.c
locks.h
Makefile ocfs2: disable BUG assertions in reading blocks 2016-06-24 17:23:52 -07:00
mmap.c ocfs2: clean up unused 'page' parameter in ocfs2_write_end_nolock() 2016-12-12 18:55:06 -08:00
mmap.h
move_extents.c fs: Replace CURRENT_TIME with current_time() for inode timestamps 2016-09-27 21:06:21 -04:00
move_extents.h
namei.c Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs 2016-10-10 20:16:43 -07:00
namei.h
ocfs1_fs_compat.h
ocfs2.h mm, fs: get rid of PAGE_CACHE_* and page_cache_{get,release} macros 2016-04-04 10:41:08 -07:00
ocfs2_fs.h ocfs2: fix comment in struct ocfs2_extended_slot 2016-05-19 19:12:14 -07:00
ocfs2_ioctl.h
ocfs2_lockid.h
ocfs2_lockingver.h
ocfs2_trace.h switch generic_file_splice_read() to use of ->read_iter() 2016-10-05 18:23:56 -04:00
quota.h
quota_global.c quota: use time64_t internally 2016-06-19 18:09:31 +02:00
quota_local.c
refcounttree.c ocfs2: fix double put of recount tree in ocfs2_lock_refcount_tree() 2016-12-12 18:55:06 -08:00
refcounttree.h
reservations.c
reservations.h
resize.c ocfs2: solve a problem of crossing the boundary in updating backups 2016-03-25 16:37:42 -07:00
resize.h
slot_map.c ocfs2: clean up an unneeded goto in ocfs2_put_slot() 2016-05-19 19:12:14 -07:00
slot_map.h
stack_o2cb.c
stack_user.c ocfs2: ensure that dlm lockspace is created by kernel module 2016-08-02 17:31:41 -04:00
stackglue.c ocfs2: fix a redundant re-initialization 2016-07-26 16:19:19 -07:00
stackglue.h
suballoc.c ocfs2: fix double unlock in case retry after free truncate log 2016-09-19 15:36:17 -07:00
suballoc.h
super.c fs/ocfs2/super: remove deprecated create_singlethread_workqueue() 2016-10-07 18:46:26 -07:00
super.h ocfs2: fix occurring deadlock by changing ocfs2_wq from global to local 2016-03-25 16:37:42 -07:00
symlink.c vfs: Remove {get,set,remove}xattr inode operations 2016-10-07 21:48:36 -04:00
symlink.h
sysfile.c
sysfile.h
uptodate.c
uptodate.h
xattr.c fs: Replace CURRENT_TIME with current_time() for inode timestamps 2016-09-27 21:06:21 -04:00
xattr.h ocfs2: fix posix_acl_create deadlock 2016-05-12 15:52:50 -07:00