aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Chinner <david@fromorbit.com>2014-08-03 23:54:46 -0400
committerDave Chinner <david@fromorbit.com>2014-08-03 23:54:46 -0400
commitb076d8720d793cde04b75b4941b8774e209649b4 (patch)
tree14f0aa5ac5850e2077076062340eb1ef15f7ccf1
parent4d7eece2c0dad832c5f224629eba3cced3f2d6cd (diff)
parent1e773c4989d2dfe08332b4c18f7e1d7ad633015c (diff)
Merge branch 'xfs-bulkstat-refactor' into for-next
-rw-r--r--fs/xfs/xfs_ioctl.c4
-rw-r--r--fs/xfs/xfs_ioctl32.c2
-rw-r--r--fs/xfs/xfs_itable.c569
-rw-r--r--fs/xfs/xfs_itable.h23
4 files changed, 283 insertions, 315 deletions
diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
index 30983b8ceaa1..494237ed4a65 100644
--- a/fs/xfs/xfs_ioctl.c
+++ b/fs/xfs/xfs_ioctl.c
@@ -796,8 +796,8 @@ xfs_ioc_bulkstat(
796 error = xfs_inumbers(mp, &inlast, &count, 796 error = xfs_inumbers(mp, &inlast, &count,
797 bulkreq.ubuffer, xfs_inumbers_fmt); 797 bulkreq.ubuffer, xfs_inumbers_fmt);
798 else if (cmd == XFS_IOC_FSBULKSTAT_SINGLE) 798 else if (cmd == XFS_IOC_FSBULKSTAT_SINGLE)
799 error = xfs_bulkstat_single(mp, &inlast, 799 error = xfs_bulkstat_one(mp, inlast, bulkreq.ubuffer,
800 bulkreq.ubuffer, &done); 800 sizeof(xfs_bstat_t), NULL, &done);
801 else /* XFS_IOC_FSBULKSTAT */ 801 else /* XFS_IOC_FSBULKSTAT */
802 error = xfs_bulkstat(mp, &inlast, &count, xfs_bulkstat_one, 802 error = xfs_bulkstat(mp, &inlast, &count, xfs_bulkstat_one,
803 sizeof(xfs_bstat_t), bulkreq.ubuffer, 803 sizeof(xfs_bstat_t), bulkreq.ubuffer,
diff --git a/fs/xfs/xfs_ioctl32.c b/fs/xfs/xfs_ioctl32.c
index e65ea67e3ae3..cf63418bf05f 100644
--- a/fs/xfs/xfs_ioctl32.c
+++ b/fs/xfs/xfs_ioctl32.c
@@ -102,7 +102,7 @@ xfs_compat_growfs_rt_copyin(
102STATIC int 102STATIC int
103xfs_inumbers_fmt_compat( 103xfs_inumbers_fmt_compat(
104 void __user *ubuffer, 104 void __user *ubuffer,
105 const xfs_inogrp_t *buffer, 105 const struct xfs_inogrp *buffer,
106 long count, 106 long count,
107 long *written) 107 long *written)
108{ 108{
diff --git a/fs/xfs/xfs_itable.c b/fs/xfs/xfs_itable.c
index 7e54992bcae9..f71be9c68017 100644
--- a/fs/xfs/xfs_itable.c
+++ b/fs/xfs/xfs_itable.c
@@ -76,10 +76,8 @@ xfs_bulkstat_one_int(
76 error = xfs_iget(mp, NULL, ino, 76 error = xfs_iget(mp, NULL, ino,
77 (XFS_IGET_DONTCACHE | XFS_IGET_UNTRUSTED), 77 (XFS_IGET_DONTCACHE | XFS_IGET_UNTRUSTED),
78 XFS_ILOCK_SHARED, &ip); 78 XFS_ILOCK_SHARED, &ip);
79 if (error) { 79 if (error)
80 *stat = BULKSTAT_RV_NOTHING;
81 goto out_free; 80 goto out_free;
82 }
83 81
84 ASSERT(ip != NULL); 82 ASSERT(ip != NULL);
85 ASSERT(ip->i_imap.im_blkno != 0); 83 ASSERT(ip->i_imap.im_blkno != 0);
@@ -136,7 +134,6 @@ xfs_bulkstat_one_int(
136 IRELE(ip); 134 IRELE(ip);
137 135
138 error = formatter(buffer, ubsize, ubused, buf); 136 error = formatter(buffer, ubsize, ubused, buf);
139
140 if (!error) 137 if (!error)
141 *stat = BULKSTAT_RV_DIDONE; 138 *stat = BULKSTAT_RV_DIDONE;
142 139
@@ -175,9 +172,170 @@ xfs_bulkstat_one(
175 xfs_bulkstat_one_fmt, ubused, stat); 172 xfs_bulkstat_one_fmt, ubused, stat);
176} 173}
177 174
175/*
176 * Loop over all clusters in a chunk for a given incore inode allocation btree
177 * record. Do a readahead if there are any allocated inodes in that cluster.
178 */
179STATIC void
180xfs_bulkstat_ichunk_ra(
181 struct xfs_mount *mp,
182 xfs_agnumber_t agno,
183 struct xfs_inobt_rec_incore *irec)
184{
185 xfs_agblock_t agbno;
186 struct blk_plug plug;
187 int blks_per_cluster;
188 int inodes_per_cluster;
189 int i; /* inode chunk index */
190
191 agbno = XFS_AGINO_TO_AGBNO(mp, irec->ir_startino);
192 blks_per_cluster = xfs_icluster_size_fsb(mp);
193 inodes_per_cluster = blks_per_cluster << mp->m_sb.sb_inopblog;
194
195 blk_start_plug(&plug);
196 for (i = 0; i < XFS_INODES_PER_CHUNK;
197 i += inodes_per_cluster, agbno += blks_per_cluster) {
198 if (xfs_inobt_maskn(i, inodes_per_cluster) & ~irec->ir_free) {
199 xfs_btree_reada_bufs(mp, agno, agbno, blks_per_cluster,
200 &xfs_inode_buf_ops);
201 }
202 }
203 blk_finish_plug(&plug);
204}
205
206/*
207 * Lookup the inode chunk that the given inode lives in and then get the record
208 * if we found the chunk. If the inode was not the last in the chunk and there
209 * are some left allocated, update the data for the pointed-to record as well as
210 * return the count of grabbed inodes.
211 */
212STATIC int
213xfs_bulkstat_grab_ichunk(
214 struct xfs_btree_cur *cur, /* btree cursor */
215 xfs_agino_t agino, /* starting inode of chunk */
216 int *icount,/* return # of inodes grabbed */
217 struct xfs_inobt_rec_incore *irec) /* btree record */
218{
219 int idx; /* index into inode chunk */
220 int stat;
221 int error = 0;
222
223 /* Lookup the inode chunk that this inode lives in */
224 error = xfs_inobt_lookup(cur, agino, XFS_LOOKUP_LE, &stat);
225 if (error)
226 return error;
227 if (!stat) {
228 *icount = 0;
229 return error;
230 }
231
232 /* Get the record, should always work */
233 error = xfs_inobt_get_rec(cur, irec, &stat);
234 if (error)
235 return error;
236 XFS_WANT_CORRUPTED_RETURN(stat == 1);
237
238 /* Check if the record contains the inode in request */
239 if (irec->ir_startino + XFS_INODES_PER_CHUNK <= agino)
240 return -EINVAL;
241
242 idx = agino - irec->ir_startino + 1;
243 if (idx < XFS_INODES_PER_CHUNK &&
244 (xfs_inobt_maskn(idx, XFS_INODES_PER_CHUNK - idx) & ~irec->ir_free)) {
245 int i;
246
247 /* We got a right chunk with some left inodes allocated at it.
248 * Grab the chunk record. Mark all the uninteresting inodes
249 * free -- because they're before our start point.
250 */
251 for (i = 0; i < idx; i++) {
252 if (XFS_INOBT_MASK(i) & ~irec->ir_free)
253 irec->ir_freecount++;
254 }
255
256 irec->ir_free |= xfs_inobt_maskn(0, idx);
257 *icount = XFS_INODES_PER_CHUNK - irec->ir_freecount;
258 }
259
260 return 0;
261}
262
178#define XFS_BULKSTAT_UBLEFT(ubleft) ((ubleft) >= statstruct_size) 263#define XFS_BULKSTAT_UBLEFT(ubleft) ((ubleft) >= statstruct_size)
179 264
180/* 265/*
266 * Process inodes in chunk with a pointer to a formatter function
267 * that will iget the inode and fill in the appropriate structure.
268 */
269int
270xfs_bulkstat_ag_ichunk(
271 struct xfs_mount *mp,
272 xfs_agnumber_t agno,
273 struct xfs_inobt_rec_incore *irbp,
274 bulkstat_one_pf formatter,
275 size_t statstruct_size,
276 struct xfs_bulkstat_agichunk *acp)
277{
278 xfs_ino_t lastino = acp->ac_lastino;
279 char __user **ubufp = acp->ac_ubuffer;
280 int ubleft = acp->ac_ubleft;
281 int ubelem = acp->ac_ubelem;
282 int chunkidx, clustidx;
283 int error = 0;
284 xfs_agino_t agino;
285
286 for (agino = irbp->ir_startino, chunkidx = clustidx = 0;
287 XFS_BULKSTAT_UBLEFT(ubleft) &&
288 irbp->ir_freecount < XFS_INODES_PER_CHUNK;
289 chunkidx++, clustidx++, agino++) {
290 int fmterror; /* bulkstat formatter result */
291 int ubused;
292 xfs_ino_t ino = XFS_AGINO_TO_INO(mp, agno, agino);
293
294 ASSERT(chunkidx < XFS_INODES_PER_CHUNK);
295
296 /* Skip if this inode is free */
297 if (XFS_INOBT_MASK(chunkidx) & irbp->ir_free) {
298 lastino = ino;
299 continue;
300 }
301
302 /*
303 * Count used inodes as free so we can tell when the
304 * chunk is used up.
305 */