From: Dave Hansen The mnt->__mnt_writers can go negative for a time if a pair of mnt_want_write()/mnt_drop_write() calls is done on a different cpu, but for the same mount. This part is expected. The lock_and_coalesce..() function should make that count positive (or at least 0). Hugh Dickins had found a bug in the unionfs code which caused a permanent imbalance in this code, and eventually underflowed the atomic_t mnt->__mnt_writers. It also locked up the while() loop that expects the count to go up after it is coalesced. The following patch won't fix such a unionfs bug, but it will keep the loop from locking up. It will also warn a lot earlier that something funky is going on. Signed-off-by: Dave Hansen Cc: Erez Zadok Cc: Hugh Dickins Cc: Christoph Hellwig Signed-off-by: Andrew Morton --- fs/namespace.c | 31 ++++++++++++++++++++++--------- include/linux/mount.h | 1 + 2 files changed, 23 insertions(+), 9 deletions(-) diff -puN fs/namespace.c~r-o-bind-mounts-track-number-of-mount-writer-fix-buggy-loop fs/namespace.c --- a/fs/namespace.c~r-o-bind-mounts-track-number-of-mount-writer-fix-buggy-loop +++ a/fs/namespace.c @@ -224,16 +224,29 @@ static void lock_and_coalesce_cpu_mnt_wr */ static void handle_write_count_underflow(struct vfsmount *mnt) { - while (atomic_read(&mnt->__mnt_writers) < - MNT_WRITER_UNDERFLOW_LIMIT) { - /* - * It isn't necessary to hold all of the locks - * at the same time, but doing it this way makes - * us share a lot more code. - */ - lock_and_coalesce_cpu_mnt_writer_counts(); - mnt_unlock_cpus(); + if (atomic_read(&mnt->__mnt_writers) >= + MNT_WRITER_UNDERFLOW_LIMIT) + return; + /* + * It isn't necessary to hold all of the locks + * at the same time, but doing it this way makes + * us share a lot more code. + */ + lock_and_coalesce_cpu_mnt_writer_counts(); + /* + * If coalescing the per-cpu writer counts did not + * get us back to a positive writer count, we have + * a bug. + */ + if ((atomic_read(&mnt->__mnt_writers) < 0) && + !(mnt->mnt_flags & MNT_IMBALANCED_WRITE_COUNT)) { + printk("leak detected on mount(%p) writers count: %d\n", + mnt, atomic_read(&mnt->__mnt_writers)); + WARN_ON(1); + /* use the flag to keep the dmesg spam down */ + mnt->mnt_flags |= MNT_IMBALANCED_WRITE_COUNT; } + mnt_unlock_cpus(); } /** diff -puN include/linux/mount.h~r-o-bind-mounts-track-number-of-mount-writer-fix-buggy-loop include/linux/mount.h --- a/include/linux/mount.h~r-o-bind-mounts-track-number-of-mount-writer-fix-buggy-loop +++ a/include/linux/mount.h @@ -31,6 +31,7 @@ struct mnt_namespace; #define MNT_RELATIME 0x20 #define MNT_SHRINKABLE 0x100 +#define MNT_IMBALANCED_WRITE_COUNT 0x200 /* just for debugging */ #define MNT_SHARED 0x1000 /* if the vfsmount is a shared mount */ #define MNT_UNBINDABLE 0x2000 /* if the vfsmount is a unbindable mount */ _