All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 14/15] xfs: Add shrink data ioctl(2)
@ 2012-11-16  6:46 Jeff Liu
  0 siblings, 0 replies; only message in thread
From: Jeff Liu @ 2012-11-16  6:46 UTC (permalink / raw)
  To: xfs

So the real FS data section shrink function via ioctl(2) is here.


Signed-off-by: Jie Liu <jeff.liu@oracle.com>
---
 fs/xfs/xfs_fs.h    |    8 ++
 fs/xfs/xfs_fsops.c |  212 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 fs/xfs/xfs_fsops.h |    1 +
 fs/xfs/xfs_ioctl.c |   15 ++++
 4 files changed, 234 insertions(+), 2 deletions(-)

diff --git a/fs/xfs/xfs_fs.h b/fs/xfs/xfs_fs.h
index c459d52..3a85979 100644
--- a/fs/xfs/xfs_fs.h
+++ b/fs/xfs/xfs_fs.h
@@ -272,6 +272,13 @@ typedef struct xfs_growfs_rt {
 	__u32		extsize;	/* new realtime extent size, fsblocks */
 } xfs_growfs_rt_t;
 
+/*
+ * Structure for XFS_IOC_SHRINKFS_DATA.
+ */
+typedef struct xfs_shrinkfs_data {
+	__u64		newblocks;	/* new data subvol size, fsblocks */
+	__u32		imaxpct;	/* new inode space percentage limit */
+} xfs_shrinkfs_data_t;
 
 /*
  * Structures returned from ioctl XFS_IOC_FSBULKSTAT & XFS_IOC_FSBULKSTAT_SINGLE
@@ -489,6 +496,7 @@ typedef struct xfs_handle {
 #define XFS_IOC_SET_AGSTATE	     _IOW('X', 126, struct xfs_ioc_agstate)
 #define XFS_IOC_GET_AGSTATE	     _IOR('X', 127, struct xfs_ioc_agstate)
 #define XFS_IOC_SWAPINO		     _IOWR('X', 128, struct xfs_swapino)
+#define XFS_IOC_FSSHRINKFS_DATA	     _IOW('X', 129, struct xfs_shrinkfs_data)
 /*	XFS_IOC_GETFSUUID ---------- deprecated 140	 */
 
 
diff --git a/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c
index 04a21d1..e5aa564 100644
--- a/fs/xfs/xfs_fsops.c
+++ b/fs/xfs/xfs_fsops.c
@@ -579,8 +579,6 @@ xfs_growfs_log_private(
  * point - exported through ioctls: XFS_IOC_FSGROWFSDATA, XFS_IOC_FSGROWFSLOG,
  * XFS_IOC_FSGROWFSRT
  */
-
-
 int
 xfs_growfs_data(
 	xfs_mount_t		*mp,
@@ -948,6 +946,216 @@ error0:
 	return error;
 }
 
+static int
+xfs_shrinkfs_process_ag(
+	xfs_mount_t		*mp,
+	xfs_trans_t		*tp,
+	xfs_agnumber_t		agno,
+	xfs_rfsblock_t		tsize,
+	xfs_extlen_t		*nfree)
+{
+	xfs_perag_t		*pag;
+	bool			empty;
+	int			error;
+
+	/*
+	 * The a.g. state must has already been set to offline
+	 * by xfs_shrinkfs(8).
+	 */
+	pag = xfs_perag_get(mp, agno);
+	if (!(pag->pag_state & XFS_AG_STATE_ALLOC_DENY)) {
+		xfs_perag_put(pag);
+		return XFS_ERROR(EINVAL);
+	}
+	xfs_perag_put(pag);
+
+	error = xfs_ag_is_empty(mp, agno, &empty);
+	if (error)
+		goto error0;
+
+	if (!empty)
+		error = xfs_truncate_ag(mp, agno, tsize, nfree);
+	else {
+		/*
+		 * The Primary AG must not be empty except at the
+		 * invitial phase(mkfs.xfs).  But we should not
+		 * remove it anyway.
+		 */
+		if (agno == 0) {
+			error = XFS_ERROR(EINVAL);
+			goto error0;
+		}
+		error = xfs_remove_empty_ag(mp, agno, nfree);
+	}
+
+error0:
+	if (error)
+		*nfree = 0;
+
+	return error;
+}
+
+static int
+xfs_shrinkfs_data_private(
+	xfs_mount_t		*mp,
+	xfs_shrinkfs_data_t	*in)
+{
+	xfs_agnumber_t		oagcount; /* old AG count */
+	xfs_agnumber_t		nagcount; /* new AG count */
+	xfs_agnumber_t		agno;
+	xfs_rfsblock_t		nb, nb_mod;
+	xfs_rfsblock_t		new;
+	xfs_rfsblock_t		tsize;
+	xfs_rfsblock_t		nfree;
+	xfs_trans_t		*tp;
+	int			pct;
+	int			dpct;
+	int			error;
+
+	new = nb = in->newblocks;
+	pct = in->imaxpct;
+
+	if (new > mp->m_sb.sb_dblocks)
+		return XFS_ERROR(EINVAL);
+	if (new == mp->m_sb.sb_dblocks)
+		return 0;
+	if (pct < 0 || pct > 100)
+		return XFS_ERROR(EINVAL);
+
+	tsize = mp->m_sb.sb_dblocks - new;
+
+	/*
+	 * If the filesystem has internal logs, cannot shrink beyond the
+	 * end block of the log area for now.
+	 */
+	if (mp->m_sb.sb_logstart > 0 &&
+	    new < mp->m_sb.sb_logstart + mp->m_sb.sb_logblocks)
+		return XFS_ERROR(EINVAL);
+
+	nb_mod = do_div(new, mp->m_sb.sb_agblocks);
+	nagcount = new + (nb_mod != 0);
+	if (nb_mod && nb_mod < XFS_MIN_AG_BLOCKS) {
+		nagcount--;
+		nb_mod = 0;
+		nb = (xfs_rfsblock_t)nagcount * mp->m_sb.sb_agblocks;
+	}
+
+	tp = xfs_trans_alloc(mp, XFS_TRANS_SHRINKFS);
+	tp->t_flags |= XFS_TRANS_RESERVE;
+	error = xfs_trans_reserve(tp, XFS_SHRINKFS_SPACE_RES(mp),
+				  XFS_SHRINKDATA_LOG_RES(mp),
+				  0, 0, 0);
+	if (error) {
+		xfs_trans_cancel(tp, 0);
+		goto out;
+	}
+
+	oagcount = mp->m_sb.sb_agcount;
+	nfree = 0;
+	for (agno = nagcount - 1; agno < oagcount; agno++) {
+		xfs_extlen_t		freed;
+
+		error = xfs_shrinkfs_process_ag(mp, tp, agno, tsize, &freed);
+		if (error)
+			goto out_trans_cancel;
+		nfree += freed;
+		tsize -= freed;
+	}
+
+	xfs_trans_agblocks_delta(tp, -nfree);
+
+	/*
+	 * Update superblock to reflect current agcount if possbile.
+	 */
+	if (nagcount < oagcount)
+		xfs_trans_mod_sb(tp, XFS_TRANS_SB_AGCOUNT, nagcount - oagcount);
+
+	xfs_trans_mod_sb(tp, XFS_TRANS_SB_FDBLOCKS, -nfree);
+
+	/*
+	 * Update superblock to reflect current data blocks.
+	 */
+	xfs_trans_mod_sb(tp, XFS_TRANS_SB_DBLOCKS, -nfree);
+	dpct = pct - mp->m_sb.sb_imax_pct;
+	if (dpct)
+		xfs_trans_mod_sb(tp, XFS_TRANS_SB_IMAXPCT, dpct);
+	error = xfs_trans_commit(tp, 0);
+	if (error)
+		goto out;
+
+	/* FIXME: iterate perag to find out the maximum agi */
+	if (mp->m_maxagi > nagcount)
+		mp->m_maxagi = nagcount;
+	if (!mp->m_sb.sb_imax_pct)
+		mp->m_maxicount = 0;
+	else {
+		__uint64_t icount = mp->m_sb.sb_dblocks * mp->m_sb.sb_imax_pct;
+		do_div(icount, 100);
+		mp->m_maxicount = icount << mp->m_sb.sb_inopblog;
+	}
+	xfs_set_low_space_thresholds(mp);
+
+	/*
+	 * Update secondary superblocks.
+	 */
+	for (agno = 1; agno < nagcount; agno++) {
+		xfs_buf_t	*bp = NULL;
+
+		error = xfs_trans_read_buf(mp, NULL, mp->m_ddev_targp,
+				XFS_AGB_TO_DADDR(mp, agno, XFS_SB_BLOCK(mp)),
+				XFS_FSS_TO_BB(mp, 1), 0, &bp);
+		if (error) {
+			xfs_warn(mp,
+		"error %d reading secondary superblock for ag %d",
+				error, agno);
+			break;
+		}
+
+		xfs_sb_to_disk(XFS_BUF_TO_SBP(bp), &mp->m_sb, XFS_SB_ALL_BITS);
+		/*
+		 * If we get an error writing out the alternate superblocks,
+		 * just issue a warning and continue.  The real work is
+		 * already done and committed.
+		 */
+		error = xfs_bwrite(bp);
+		xfs_buf_relse(bp);
+		if (error) {
+			xfs_warn(mp,
+		"write error %d updating secondary superblock for ag %d",
+				error, agno);
+			break; /* no point in continuing */
+		}
+	}
+
+out:
+	return error;
+
+out_trans_cancel:
+	xfs_trans_cancel(tp, XFS_TRANS_ABORT);
+	return error;
+}
+
+/*
+ * Interface of shrinking file system data section via ioctl(2).
+ */
+int
+xfs_shrinkfs_data(
+	xfs_mount_t		*mp,
+	xfs_shrinkfs_data_t	*in)
+{
+	int error;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return XFS_ERROR(EPERM);
+
+	if (!mutex_trylock(&mp->m_shrinklock))
+		return XFS_ERROR(EWOULDBLOCK);
+	error = xfs_shrinkfs_data_private(mp, in);
+	mutex_unlock(&mp->m_shrinklock);
+
+	return error;
+}
+
 /*
  * exported through ioctl XFS_IOC_FSCOUNTS
  */
diff --git a/fs/xfs/xfs_fsops.h b/fs/xfs/xfs_fsops.h
index 1b6a98b..40be112 100644
--- a/fs/xfs/xfs_fsops.h
+++ b/fs/xfs/xfs_fsops.h
@@ -26,5 +26,6 @@ extern int xfs_reserve_blocks(xfs_mount_t *mp, __uint64_t *inval,
 				xfs_fsop_resblks_t *outval);
 extern int xfs_fs_goingdown(xfs_mount_t *mp, __uint32_t inflags);
 extern int xfs_fs_log_dummy(struct xfs_mount *mp);
+extern int xfs_shrinkfs_data(xfs_mount_t *mp, xfs_shrinkfs_data_t *in);
 
 #endif	/* __XFS_FSOPS_H__ */
diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
index 0e0c03f..41b2900 100644
--- a/fs/xfs/xfs_ioctl.c
+++ b/fs/xfs/xfs_ioctl.c
@@ -1649,6 +1649,21 @@ xfs_file_ioctl(
 		return -error;
 	}
 
+	case XFS_IOC_FSSHRINKFS_DATA: {
+		xfs_shrinkfs_data_t	in;
+
+		if (copy_from_user(&in, arg, sizeof(in)))
+			return -XFS_ERROR(EFAULT);
+
+		error = mnt_want_write_file(filp);
+		if (error)
+			return error;
+
+		error = xfs_shrinkfs_data(mp, &in);
+		mnt_drop_write_file(filp);
+		return -error;
+	}
+
 	default:
 		return -ENOTTY;
 	}
-- 
1.7.4.1

_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2012-11-16  6:45 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-11-16  6:46 [PATCH 14/15] xfs: Add shrink data ioctl(2) Jeff Liu

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.