xfs: remove leftover CoW reservations when remounting ro

When we're remounting the filesystem readonly, remove all CoW
preallocations prior to going ro. If the fs goes down after the ro
remount, we never clean up the staging extents, which means xfs_check
will trip over them on a subsequent run. Practically speaking, the next
mount will clean them up too, so this is unlikely to be seen. Since we
shut down the cowblocks cleaner on remount-ro, we also have to make sure
we start it back up if/when we remount-rw.

Found by adding clonerange to fsstress and running xfs/017.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>

+11 -1
+1 -1
fs/xfs/xfs_icache.c
··· 870 * based on the 'speculative_cow_prealloc_lifetime' tunable (5m by default). 871 * (We'll just piggyback on the post-EOF prealloc space workqueue.) 872 */ 873 - STATIC void 874 xfs_queue_cowblocks( 875 struct xfs_mount *mp) 876 {
··· 870 * based on the 'speculative_cow_prealloc_lifetime' tunable (5m by default). 871 * (We'll just piggyback on the post-EOF prealloc space workqueue.) 872 */ 873 + void 874 xfs_queue_cowblocks( 875 struct xfs_mount *mp) 876 {
+1
fs/xfs/xfs_icache.h
··· 81 int xfs_icache_free_cowblocks(struct xfs_mount *, struct xfs_eofblocks *); 82 int xfs_inode_free_quota_cowblocks(struct xfs_inode *ip); 83 void xfs_cowblocks_worker(struct work_struct *); 84 85 int xfs_inode_ag_iterator(struct xfs_mount *mp, 86 int (*execute)(struct xfs_inode *ip, int flags, void *args),
··· 81 int xfs_icache_free_cowblocks(struct xfs_mount *, struct xfs_eofblocks *); 82 int xfs_inode_free_quota_cowblocks(struct xfs_inode *ip); 83 void xfs_cowblocks_worker(struct work_struct *); 84 + void xfs_queue_cowblocks(struct xfs_mount *); 85 86 int xfs_inode_ag_iterator(struct xfs_mount *mp, 87 int (*execute)(struct xfs_inode *ip, int flags, void *args),
+9
fs/xfs/xfs_super.c
··· 1360 xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE); 1361 return error; 1362 } 1363 1364 /* Create the per-AG metadata reservation pool .*/ 1365 error = xfs_fs_reserve_ag_blocks(mp); ··· 1370 1371 /* rw -> ro */ 1372 if (!(mp->m_flags & XFS_MOUNT_RDONLY) && (*flags & MS_RDONLY)) { 1373 /* Free the per-AG metadata reservation pool. */ 1374 error = xfs_fs_unreserve_ag_blocks(mp); 1375 if (error) {
··· 1360 xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE); 1361 return error; 1362 } 1363 + xfs_queue_cowblocks(mp); 1364 1365 /* Create the per-AG metadata reservation pool .*/ 1366 error = xfs_fs_reserve_ag_blocks(mp); ··· 1369 1370 /* rw -> ro */ 1371 if (!(mp->m_flags & XFS_MOUNT_RDONLY) && (*flags & MS_RDONLY)) { 1372 + /* Get rid of any leftover CoW reservations... */ 1373 + cancel_delayed_work_sync(&mp->m_cowblocks_work); 1374 + error = xfs_icache_free_cowblocks(mp, NULL); 1375 + if (error) { 1376 + xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE); 1377 + return error; 1378 + } 1379 + 1380 /* Free the per-AG metadata reservation pool. */ 1381 error = xfs_fs_unreserve_ag_blocks(mp); 1382 if (error) {