From 19f354d4c3f4c48bf6b2a86227d8e3050e5f7d50 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 20 May 2008 11:31:13 +1000 Subject: [PATCH] [XFS] sort out opening and closing of the block devices Currently closing the rt/log block device is done in the wrong spot, and far too early. So revampt it: - xfs_blkdev_put moved out of xfs_free_buftarg into the caller so that it is done after tearing down the buftarg completely. - call to xfs_unmountfs_close moved from xfs_mountfs into caller so that it's done after tearing down the filesystem completely. - xfs_unmountfs_close is renamed to xfs_close_devices and made static in xfs_super.c - opening of the block devices is split into a helper xfs_open_devices that is symetric in use to xfs_close_devices - xfs_unmountfs can now lose struct cred - error handling around device opening sanitized in xfs_fs_fill_super SGI-PV: 981951 SGI-Modid: xfs-linux-melb:xfs-kern:31193a Signed-off-by: Christoph Hellwig Signed-off-by: David Chinner Signed-off-by: Lachlan McIlroy --- fs/xfs/linux-2.6/xfs_buf.c | 5 +- fs/xfs/linux-2.6/xfs_buf.h | 2 +- fs/xfs/linux-2.6/xfs_super.c | 192 ++++++++++++++++++++++------------- fs/xfs/linux-2.6/xfs_super.h | 3 - fs/xfs/xfs_mount.c | 13 +-- fs/xfs/xfs_mount.h | 3 +- 6 files changed, 123 insertions(+), 95 deletions(-) diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c index ed03c6d3c9c..9cc8f021309 100644 --- a/fs/xfs/linux-2.6/xfs_buf.c +++ b/fs/xfs/linux-2.6/xfs_buf.c @@ -1427,13 +1427,10 @@ xfs_unregister_buftarg( void xfs_free_buftarg( - xfs_buftarg_t *btp, - int external) + xfs_buftarg_t *btp) { xfs_flush_buftarg(btp, 1); xfs_blkdev_issue_flush(btp); - if (external) - xfs_blkdev_put(btp->bt_bdev); xfs_free_bufhash(btp); iput(btp->bt_mapping->host); diff --git a/fs/xfs/linux-2.6/xfs_buf.h b/fs/xfs/linux-2.6/xfs_buf.h index f948ec7ba9a..29d1d4adc07 100644 --- a/fs/xfs/linux-2.6/xfs_buf.h +++ b/fs/xfs/linux-2.6/xfs_buf.h @@ -429,7 +429,7 @@ static inline void xfs_bdwrite(void *mp, xfs_buf_t *bp) * Handling of buftargs. */ extern xfs_buftarg_t *xfs_alloc_buftarg(struct block_device *, int); -extern void xfs_free_buftarg(xfs_buftarg_t *, int); +extern void xfs_free_buftarg(xfs_buftarg_t *); extern void xfs_wait_buftarg(xfs_buftarg_t *); extern int xfs_setsize_buftarg(xfs_buftarg_t *, unsigned int, unsigned int); extern int xfs_flush_buftarg(xfs_buftarg_t *, int); diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c index 4b6ddf88d44..055faa06ca2 100644 --- a/fs/xfs/linux-2.6/xfs_super.c +++ b/fs/xfs/linux-2.6/xfs_super.c @@ -766,6 +766,103 @@ xfs_blkdev_issue_flush( blkdev_issue_flush(buftarg->bt_bdev, NULL); } +STATIC void +xfs_close_devices( + struct xfs_mount *mp) +{ + if (mp->m_logdev_targp && mp->m_logdev_targp != mp->m_ddev_targp) { + xfs_free_buftarg(mp->m_logdev_targp); + xfs_blkdev_put(mp->m_logdev_targp->bt_bdev); + } + if (mp->m_rtdev_targp) { + xfs_free_buftarg(mp->m_rtdev_targp); + xfs_blkdev_put(mp->m_rtdev_targp->bt_bdev); + } + xfs_free_buftarg(mp->m_ddev_targp); +} + +/* + * The file system configurations are: + * (1) device (partition) with data and internal log + * (2) logical volume with data and log subvolumes. + * (3) logical volume with data, log, and realtime subvolumes. + * + * We only have to handle opening the log and realtime volumes here if + * they are present. The data subvolume has already been opened by + * get_sb_bdev() and is stored in sb->s_bdev. + */ +STATIC int +xfs_open_devices( + struct xfs_mount *mp, + struct xfs_mount_args *args) +{ + struct block_device *ddev = mp->m_super->s_bdev; + struct block_device *logdev = NULL, *rtdev = NULL; + int error; + + /* + * Open real time and log devices - order is important. + */ + if (args->logname[0]) { + error = xfs_blkdev_get(mp, args->logname, &logdev); + if (error) + goto out; + } + + if (args->rtname[0]) { + error = xfs_blkdev_get(mp, args->rtname, &rtdev); + if (error) + goto out_close_logdev; + + if (rtdev == ddev || rtdev == logdev) { + cmn_err(CE_WARN, + "XFS: Cannot mount filesystem with identical rtdev and ddev/logdev."); + error = EINVAL; + goto out_close_rtdev; + } + } + + /* + * Setup xfs_mount buffer target pointers + */ + error = ENOMEM; + mp->m_ddev_targp = xfs_alloc_buftarg(ddev, 0); + if (!mp->m_ddev_targp) + goto out_close_rtdev; + + if (rtdev) { + mp->m_rtdev_targp = xfs_alloc_buftarg(rtdev, 1); + if (!mp->m_rtdev_targp) + goto out_free_ddev_targ; + } + + if (logdev && logdev != ddev) { + mp->m_logdev_targp = xfs_alloc_buftarg(logdev, 1); + if (!mp->m_logdev_targp) + goto out_free_rtdev_targ; + } else { + mp->m_logdev_targp = mp->m_ddev_targp; + } + + return 0; + + out_free_rtdev_targ: + if (mp->m_rtdev_targp) + xfs_free_buftarg(mp->m_rtdev_targp); + out_free_ddev_targ: + xfs_free_buftarg(mp->m_ddev_targp); + out_close_rtdev: + if (rtdev) + xfs_blkdev_put(rtdev); + out_close_logdev: + if (logdev && logdev != ddev) + xfs_blkdev_put(logdev); + out: + return error; +} + + + /* * XFS AIL push thread support */ @@ -1138,7 +1235,8 @@ xfs_fs_put_super( unmount_event_flags); } - xfs_unmountfs(mp, NULL); + xfs_unmountfs(mp); + xfs_close_devices(mp); xfs_qmops_put(mp); xfs_dmops_put(mp); kmem_free(mp); @@ -1585,16 +1683,6 @@ xfs_finish_flags( return 0; } -/* - * The file system configurations are: - * (1) device (partition) with data and internal log - * (2) logical volume with data and log subvolumes. - * (3) logical volume with data, log, and realtime subvolumes. - * - * We only have to handle opening the log and realtime volumes here if - * they are present. The data subvolume has already been opened by - * get_sb_bdev() and is stored in vfsp->vfs_super->s_bdev. - */ STATIC int xfs_fs_fill_super( struct super_block *sb, @@ -1604,8 +1692,6 @@ xfs_fs_fill_super( struct inode *root; struct xfs_mount *mp = NULL; struct xfs_mount_args *args = xfs_args_allocate(sb, silent); - struct block_device *ddev = sb->s_bdev; - struct block_device *logdev = NULL, *rtdev = NULL; int flags = 0, error; mp = xfs_mount_init(); @@ -1634,61 +1720,14 @@ xfs_fs_fill_super( goto fail_vfsop; error = xfs_qmops_get(mp, args); if (error) - goto fail_vfsop; + goto out_put_dmops; if (args->flags & XFSMNT_QUIET) flags |= XFS_MFSI_QUIET; - /* - * Open real time and log devices - order is important. - */ - if (args->logname[0]) { - error = xfs_blkdev_get(mp, args->logname, &logdev); - if (error) - goto fail_vfsop; - } - if (args->rtname[0]) { - error = xfs_blkdev_get(mp, args->rtname, &rtdev); - if (error) { - xfs_blkdev_put(logdev); - goto fail_vfsop; - } - - if (rtdev == ddev || rtdev == logdev) { - cmn_err(CE_WARN, - "XFS: Cannot mount filesystem with identical rtdev and ddev/logdev."); - xfs_blkdev_put(logdev); - xfs_blkdev_put(rtdev); - error = EINVAL; - goto fail_vfsop; - } - } - - /* - * Setup xfs_mount buffer target pointers - */ - error = ENOMEM; - mp->m_ddev_targp = xfs_alloc_buftarg(ddev, 0); - if (!mp->m_ddev_targp) { - xfs_blkdev_put(logdev); - xfs_blkdev_put(rtdev); - goto fail_vfsop; - } - if (rtdev) { - mp->m_rtdev_targp = xfs_alloc_buftarg(rtdev, 1); - if (!mp->m_rtdev_targp) { - xfs_blkdev_put(logdev); - xfs_blkdev_put(rtdev); - goto error0; - } - } - mp->m_logdev_targp = (logdev && logdev != ddev) ? - xfs_alloc_buftarg(logdev, 1) : mp->m_ddev_targp; - if (!mp->m_logdev_targp) { - xfs_blkdev_put(logdev); - xfs_blkdev_put(rtdev); - goto error0; - } + error = xfs_open_devices(mp, args); + if (error) + goto out_put_qmops; /* * Setup flags based on mount(2) options and then the superblock @@ -1708,7 +1747,9 @@ xfs_fs_fill_super( */ error = xfs_setsize_buftarg(mp->m_ddev_targp, mp->m_sb.sb_blocksize, mp->m_sb.sb_sectsize); - if (!error && logdev && logdev != ddev) { + if (error) + goto error2; + if (mp->m_logdev_targp && mp->m_logdev_targp != mp->m_ddev_targp) { unsigned int log_sector_size = BBSIZE; if (xfs_sb_version_hassector(&mp->m_sb)) @@ -1716,13 +1757,16 @@ xfs_fs_fill_super( error = xfs_setsize_buftarg(mp->m_logdev_targp, mp->m_sb.sb_blocksize, log_sector_size); + if (error) + goto error2; } - if (!error && rtdev) + if (mp->m_rtdev_targp) { error = xfs_setsize_buftarg(mp->m_rtdev_targp, mp->m_sb.sb_blocksize, mp->m_sb.sb_sectsize); - if (error) - goto error2; + if (error) + goto error2; + } if (mp->m_flags & XFS_MOUNT_BARRIER) xfs_mountfs_check_barriers(mp); @@ -1778,13 +1822,14 @@ xfs_fs_fill_super( xfs_freesb(mp); error1: xfs_binval(mp->m_ddev_targp); - if (logdev && logdev != ddev) + if (mp->m_logdev_targp && mp->m_logdev_targp != mp->m_ddev_targp) xfs_binval(mp->m_logdev_targp); - if (rtdev) + if (mp->m_rtdev_targp) xfs_binval(mp->m_rtdev_targp); - error0: - xfs_unmountfs_close(mp, NULL); + xfs_close_devices(mp); + out_put_qmops: xfs_qmops_put(mp); + out_put_dmops: xfs_dmops_put(mp); goto fail_vfsop; @@ -1810,7 +1855,8 @@ xfs_fs_fill_super( IRELE(mp->m_rootip); - xfs_unmountfs(mp, NULL); + xfs_unmountfs(mp); + xfs_close_devices(mp); xfs_qmops_put(mp); xfs_dmops_put(mp); kmem_free(mp); diff --git a/fs/xfs/linux-2.6/xfs_super.h b/fs/xfs/linux-2.6/xfs_super.h index 3efb7c6d330..212bdc7a789 100644 --- a/fs/xfs/linux-2.6/xfs_super.h +++ b/fs/xfs/linux-2.6/xfs_super.h @@ -107,9 +107,6 @@ extern void xfs_initialize_vnode(struct xfs_mount *mp, bhv_vnode_t *vp, extern void xfs_flush_inode(struct xfs_inode *); extern void xfs_flush_device(struct xfs_inode *); -extern int xfs_blkdev_get(struct xfs_mount *, const char *, - struct block_device **); -extern void xfs_blkdev_put(struct block_device *); extern void xfs_blkdev_issue_flush(struct xfs_buftarg *); extern const struct export_operations xfs_export_operations; diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c index ee5df5fae82..c67f8a9ae41 100644 --- a/fs/xfs/xfs_mount.c +++ b/fs/xfs/xfs_mount.c @@ -1278,7 +1278,7 @@ xfs_mountfs( * log and makes sure that incore structures are freed. */ int -xfs_unmountfs(xfs_mount_t *mp, struct cred *cr) +xfs_unmountfs(xfs_mount_t *mp) { __uint64_t resblks; int error = 0; @@ -1345,7 +1345,6 @@ xfs_unmountfs(xfs_mount_t *mp, struct cred *cr) */ ASSERT(mp->m_inodes == NULL); - xfs_unmountfs_close(mp, cr); if ((mp->m_flags & XFS_MOUNT_NOUUID) == 0) uuid_table_remove(&mp->m_sb.sb_uuid); @@ -1356,16 +1355,6 @@ xfs_unmountfs(xfs_mount_t *mp, struct cred *cr) return 0; } -void -xfs_unmountfs_close(xfs_mount_t *mp, struct cred *cr) -{ - if (mp->m_logdev_targp && mp->m_logdev_targp != mp->m_ddev_targp) - xfs_free_buftarg(mp->m_logdev_targp, 1); - if (mp->m_rtdev_targp) - xfs_free_buftarg(mp->m_rtdev_targp, 1); - xfs_free_buftarg(mp->m_ddev_targp, 0); -} - STATIC void xfs_unmountfs_wait(xfs_mount_t *mp) { diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h index 4aff0c125ad..5acde7fd9c0 100644 --- a/fs/xfs/xfs_mount.h +++ b/fs/xfs/xfs_mount.h @@ -518,8 +518,7 @@ extern void xfs_mount_free(xfs_mount_t *mp); extern int xfs_mountfs(xfs_mount_t *mp, int); extern void xfs_mountfs_check_barriers(xfs_mount_t *mp); -extern int xfs_unmountfs(xfs_mount_t *, struct cred *); -extern void xfs_unmountfs_close(xfs_mount_t *, struct cred *); +extern int xfs_unmountfs(xfs_mount_t *); extern int xfs_unmountfs_writesb(xfs_mount_t *); extern int xfs_unmount_flush(xfs_mount_t *, int); extern int xfs_mod_incore_sb(xfs_mount_t *, xfs_sb_field_t, int64_t, int); -- 2.41.0