xfs_itable.c 17.1 KB
Newer Older
L
Linus Torvalds 已提交
1
/*
2 3
 * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc.
 * All Rights Reserved.
L
Linus Torvalds 已提交
4
 *
5 6
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
L
Linus Torvalds 已提交
7 8
 * published by the Free Software Foundation.
 *
9 10 11 12
 * This program is distributed in the hope that it would be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
L
Linus Torvalds 已提交
13
 *
14 15 16
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write the Free Software Foundation,
 * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
L
Linus Torvalds 已提交
17 18
 */
#include "xfs.h"
19
#include "xfs_fs.h"
20
#include "xfs_shared.h"
21
#include "xfs_format.h"
22 23
#include "xfs_log_format.h"
#include "xfs_trans_resv.h"
L
Linus Torvalds 已提交
24 25
#include "xfs_mount.h"
#include "xfs_inode.h"
26
#include "xfs_btree.h"
L
Linus Torvalds 已提交
27
#include "xfs_ialloc.h"
28
#include "xfs_ialloc_btree.h"
L
Linus Torvalds 已提交
29 30
#include "xfs_itable.h"
#include "xfs_error.h"
C
Christoph Hellwig 已提交
31
#include "xfs_trace.h"
D
Dave Chinner 已提交
32
#include "xfs_icache.h"
L
Linus Torvalds 已提交
33

34 35 36 37 38 39 40 41 42 43 44 45 46
/*
 * Return stat information for one inode.
 * Return 0 if ok, else errno.
 */
int
xfs_bulkstat_one_int(
	struct xfs_mount	*mp,		/* mount point for filesystem */
	xfs_ino_t		ino,		/* inode to get data for */
	void __user		*buffer,	/* buffer to place output in */
	int			ubsize,		/* size of buffer */
	bulkstat_one_fmt_pf	formatter,	/* formatter, copy to user */
	int			*ubused,	/* bytes used by me */
	int			*stat)		/* BULKSTAT_RV_... */
L
Linus Torvalds 已提交
47
{
48 49
	struct xfs_icdinode	*dic;		/* dinode core info pointer */
	struct xfs_inode	*ip;		/* incore inode pointer */
50
	struct inode		*inode;
51 52 53 54 55 56
	struct xfs_bstat	*buf;		/* return buffer */
	int			error = 0;	/* error value */

	*stat = BULKSTAT_RV_NOTHING;

	if (!buffer || xfs_internal_inum(mp, ino))
D
Dave Chinner 已提交
57
		return -EINVAL;
58

59
	buf = kmem_zalloc(sizeof(*buf), KM_SLEEP | KM_MAYFAIL);
60
	if (!buf)
D
Dave Chinner 已提交
61
		return -ENOMEM;
L
Linus Torvalds 已提交
62

63
	error = xfs_iget(mp, NULL, ino,
64 65
			 (XFS_IGET_DONTCACHE | XFS_IGET_UNTRUSTED),
			 XFS_ILOCK_SHARED, &ip);
66
	if (error)
67
		goto out_free;
L
Linus Torvalds 已提交
68 69

	ASSERT(ip != NULL);
70
	ASSERT(ip->i_imap.im_blkno != 0);
71
	inode = VFS_I(ip);
L
Linus Torvalds 已提交
72 73 74 75 76 77

	dic = &ip->i_d;

	/* xfs_iget returns the following without needing
	 * further change.
	 */
78 79
	buf->bs_projid_lo = dic->di_projid_lo;
	buf->bs_projid_hi = dic->di_projid_hi;
L
Linus Torvalds 已提交
80 81 82 83
	buf->bs_ino = ino;
	buf->bs_uid = dic->di_uid;
	buf->bs_gid = dic->di_gid;
	buf->bs_size = dic->di_size;
84

85
	buf->bs_nlink = inode->i_nlink;
86 87 88 89 90 91
	buf->bs_atime.tv_sec = inode->i_atime.tv_sec;
	buf->bs_atime.tv_nsec = inode->i_atime.tv_nsec;
	buf->bs_mtime.tv_sec = inode->i_mtime.tv_sec;
	buf->bs_mtime.tv_nsec = inode->i_mtime.tv_nsec;
	buf->bs_ctime.tv_sec = inode->i_ctime.tv_sec;
	buf->bs_ctime.tv_nsec = inode->i_ctime.tv_nsec;
92
	buf->bs_gen = inode->i_generation;
D
Dave Chinner 已提交
93
	buf->bs_mode = inode->i_mode;
94

L
Linus Torvalds 已提交
95 96 97 98 99 100 101
	buf->bs_xflags = xfs_ip2xflags(ip);
	buf->bs_extsize = dic->di_extsize << mp->m_sb.sb_blocklog;
	buf->bs_extents = dic->di_nextents;
	memset(buf->bs_pad, 0, sizeof(buf->bs_pad));
	buf->bs_dmevmask = dic->di_dmevmask;
	buf->bs_dmstate = dic->di_dmstate;
	buf->bs_aextents = dic->di_anextents;
102
	buf->bs_forkoff = XFS_IFORK_BOFF(ip);
L
Linus Torvalds 已提交
103

104 105 106 107 108 109
	if (dic->di_version == 3) {
		if (dic->di_flags2 & XFS_DIFLAG2_COWEXTSIZE)
			buf->bs_cowextsize = dic->di_cowextsize <<
					mp->m_sb.sb_blocklog;
	}

L
Linus Torvalds 已提交
110 111
	switch (dic->di_format) {
	case XFS_DINODE_FMT_DEV:
C
Christoph Hellwig 已提交
112
		buf->bs_rdev = sysv_encode_dev(inode->i_rdev);
L
Linus Torvalds 已提交
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
		buf->bs_blksize = BLKDEV_IOSIZE;
		buf->bs_blocks = 0;
		break;
	case XFS_DINODE_FMT_LOCAL:
		buf->bs_rdev = 0;
		buf->bs_blksize = mp->m_sb.sb_blocksize;
		buf->bs_blocks = 0;
		break;
	case XFS_DINODE_FMT_EXTENTS:
	case XFS_DINODE_FMT_BTREE:
		buf->bs_rdev = 0;
		buf->bs_blksize = mp->m_sb.sb_blocksize;
		buf->bs_blocks = dic->di_nblocks + ip->i_delayed_blks;
		break;
	}
C
Christoph Hellwig 已提交
128 129
	xfs_iunlock(ip, XFS_ILOCK_SHARED);
	IRELE(ip);
L
Linus Torvalds 已提交
130

131 132 133
	error = formatter(buffer, ubsize, ubused, buf);
	if (!error)
		*stat = BULKSTAT_RV_DIDONE;
L
Linus Torvalds 已提交
134

135 136 137
 out_free:
	kmem_free(buf);
	return error;
L
Linus Torvalds 已提交
138 139
}

140
/* Return 0 on success or positive error */
141 142 143
STATIC int
xfs_bulkstat_one_fmt(
	void			__user *ubuffer,
144 145
	int			ubsize,
	int			*ubused,
146 147
	const xfs_bstat_t	*buffer)
{
148
	if (ubsize < sizeof(*buffer))
D
Dave Chinner 已提交
149
		return -ENOMEM;
150
	if (copy_to_user(ubuffer, buffer, sizeof(*buffer)))
D
Dave Chinner 已提交
151
		return -EFAULT;
152 153 154
	if (ubused)
		*ubused = sizeof(*buffer);
	return 0;
155 156
}

157 158 159 160 161 162 163 164 165 166
int
xfs_bulkstat_one(
	xfs_mount_t	*mp,		/* mount point for filesystem */
	xfs_ino_t	ino,		/* inode number to get data for */
	void		__user *buffer,	/* buffer to place output in */
	int		ubsize,		/* size of buffer */
	int		*ubused,	/* bytes used by me */
	int		*stat)		/* BULKSTAT_RV_... */
{
	return xfs_bulkstat_one_int(mp, ino, buffer, ubsize,
167
				    xfs_bulkstat_one_fmt, ubused, stat);
168 169
}

J
Jie Liu 已提交
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
/*
 * Loop over all clusters in a chunk for a given incore inode allocation btree
 * record.  Do a readahead if there are any allocated inodes in that cluster.
 */
STATIC void
xfs_bulkstat_ichunk_ra(
	struct xfs_mount		*mp,
	xfs_agnumber_t			agno,
	struct xfs_inobt_rec_incore	*irec)
{
	xfs_agblock_t			agbno;
	struct blk_plug			plug;
	int				blks_per_cluster;
	int				inodes_per_cluster;
	int				i;	/* inode chunk index */

	agbno = XFS_AGINO_TO_AGBNO(mp, irec->ir_startino);
	blks_per_cluster = xfs_icluster_size_fsb(mp);
	inodes_per_cluster = blks_per_cluster << mp->m_sb.sb_inopblog;

	blk_start_plug(&plug);
	for (i = 0; i < XFS_INODES_PER_CHUNK;
	     i += inodes_per_cluster, agbno += blks_per_cluster) {
		if (xfs_inobt_maskn(i, inodes_per_cluster) & ~irec->ir_free) {
			xfs_btree_reada_bufs(mp, agno, agbno, blks_per_cluster,
					     &xfs_inode_buf_ops);
		}
	}
	blk_finish_plug(&plug);
}

201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230
/*
 * Lookup the inode chunk that the given inode lives in and then get the record
 * if we found the chunk.  If the inode was not the last in the chunk and there
 * are some left allocated, update the data for the pointed-to record as well as
 * return the count of grabbed inodes.
 */
STATIC int
xfs_bulkstat_grab_ichunk(
	struct xfs_btree_cur		*cur,	/* btree cursor */
	xfs_agino_t			agino,	/* starting inode of chunk */
	int				*icount,/* return # of inodes grabbed */
	struct xfs_inobt_rec_incore	*irec)	/* btree record */
{
	int				idx;	/* index into inode chunk */
	int				stat;
	int				error = 0;

	/* Lookup the inode chunk that this inode lives in */
	error = xfs_inobt_lookup(cur, agino, XFS_LOOKUP_LE, &stat);
	if (error)
		return error;
	if (!stat) {
		*icount = 0;
		return error;
	}

	/* Get the record, should always work */
	error = xfs_inobt_get_rec(cur, irec, &stat);
	if (error)
		return error;
231
	XFS_WANT_CORRUPTED_RETURN(cur->bc_mp, stat == 1);
232 233

	/* Check if the record contains the inode in request */
234 235 236 237
	if (irec->ir_startino + XFS_INODES_PER_CHUNK <= agino) {
		*icount = 0;
		return 0;
	}
238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253

	idx = agino - irec->ir_startino + 1;
	if (idx < XFS_INODES_PER_CHUNK &&
	    (xfs_inobt_maskn(idx, XFS_INODES_PER_CHUNK - idx) & ~irec->ir_free)) {
		int	i;

		/* We got a right chunk with some left inodes allocated at it.
		 * Grab the chunk record.  Mark all the uninteresting inodes
		 * free -- because they're before our start point.
		 */
		for (i = 0; i < idx; i++) {
			if (XFS_INOBT_MASK(i) & ~irec->ir_free)
				irec->ir_freecount++;
		}

		irec->ir_free |= xfs_inobt_maskn(0, idx);
254
		*icount = irec->ir_count - irec->ir_freecount;
255 256 257 258 259
	}

	return 0;
}

260 261
#define XFS_BULKSTAT_UBLEFT(ubleft)	((ubleft) >= statstruct_size)

262 263 264 265 266 267
struct xfs_bulkstat_agichunk {
	char		__user **ac_ubuffer;/* pointer into user's buffer */
	int		ac_ubleft;	/* bytes left in user's buffer */
	int		ac_ubelem;	/* spaces used in user's buffer */
};

J
Jie Liu 已提交
268 269 270 271
/*
 * Process inodes in chunk with a pointer to a formatter function
 * that will iget the inode and fill in the appropriate structure.
 */
272
static int
J
Jie Liu 已提交
273 274 275 276 277 278
xfs_bulkstat_ag_ichunk(
	struct xfs_mount		*mp,
	xfs_agnumber_t			agno,
	struct xfs_inobt_rec_incore	*irbp,
	bulkstat_one_pf			formatter,
	size_t				statstruct_size,
279
	struct xfs_bulkstat_agichunk	*acp,
280
	xfs_agino_t			*last_agino)
J
Jie Liu 已提交
281 282
{
	char				__user **ubufp = acp->ac_ubuffer;
283
	int				chunkidx;
J
Jie Liu 已提交
284
	int				error = 0;
285
	xfs_agino_t			agino = irbp->ir_startino;
J
Jie Liu 已提交
286

287 288 289
	for (chunkidx = 0; chunkidx < XFS_INODES_PER_CHUNK;
	     chunkidx++, agino++) {
		int		fmterror;
J
Jie Liu 已提交
290
		int		ubused;
291 292 293 294

		/* inode won't fit in buffer, we are done */
		if (acp->ac_ubleft < statstruct_size)
			break;
J
Jie Liu 已提交
295 296

		/* Skip if this inode is free */
297
		if (XFS_INOBT_MASK(chunkidx) & irbp->ir_free)
J
Jie Liu 已提交
298 299 300 301
			continue;

		/* Get the inode and fill in a single buffer */
		ubused = statstruct_size;
302 303 304
		error = formatter(mp, XFS_AGINO_TO_INO(mp, agno, agino),
				  *ubufp, acp->ac_ubleft, &ubused, &fmterror);

305 306 307
		if (fmterror == BULKSTAT_RV_GIVEUP ||
		    (error && error != -ENOENT && error != -EINVAL)) {
			acp->ac_ubleft = 0;
J
Jie Liu 已提交
308 309 310
			ASSERT(error);
			break;
		}
311 312 313 314 315 316 317 318 319 320 321

		/* be careful not to leak error if at end of chunk */
		if (fmterror == BULKSTAT_RV_NOTHING || error) {
			error = 0;
			continue;
		}

		*ubufp += ubused;
		acp->ac_ubleft -= ubused;
		acp->ac_ubelem++;
	}
J
Jie Liu 已提交
322

323 324 325 326 327 328 329 330 331 332
	/*
	 * Post-update *last_agino. At this point, agino will always point one
	 * inode past the last inode we processed successfully. Hence we
	 * substract that inode when setting the *last_agino cursor so that we
	 * return the correct cookie to userspace. On the next bulkstat call,
	 * the inode under the lastino cookie will be skipped as we have already
	 * processed it here.
	 */
	*last_agino = agino - 1;

J
Jie Liu 已提交
333 334 335
	return error;
}

L
Linus Torvalds 已提交
336 337 338 339 340 341 342 343 344 345 346
/*
 * Return stat information in bulk (by-inode) for the filesystem.
 */
int					/* error status */
xfs_bulkstat(
	xfs_mount_t		*mp,	/* mount point for filesystem */
	xfs_ino_t		*lastinop, /* last inode returned */
	int			*ubcountp, /* size of buffer/count returned */
	bulkstat_one_pf		formatter, /* func that'd fill a single buf */
	size_t			statstruct_size, /* sizeof struct filling */
	char			__user *ubuffer, /* buffer with inode stats */
347
	int			*done)	/* 1 if there are more stats to get */
L
Linus Torvalds 已提交
348 349 350 351 352
{
	xfs_buf_t		*agbp;	/* agi header buffer */
	xfs_agino_t		agino;	/* inode # in allocation group */
	xfs_agnumber_t		agno;	/* allocation group number */
	xfs_btree_cur_t		*cur;	/* btree cursor for ialloc btree */
353
	xfs_inobt_rec_incore_t	*irbuf;	/* start of irec buffer */
L
Linus Torvalds 已提交
354 355
	int			nirbuf;	/* size of irbuf */
	int			ubcount; /* size of user's buffer */
356
	struct xfs_bulkstat_agichunk ac;
357
	int			error = 0;
L
Linus Torvalds 已提交
358 359 360 361

	/*
	 * Get the last inode value, see if there's nothing to do.
	 */
362 363
	agno = XFS_INO_TO_AGNO(mp, *lastinop);
	agino = XFS_INO_TO_AGINO(mp, *lastinop);
L
Linus Torvalds 已提交
364
	if (agno >= mp->m_sb.sb_agcount ||
365
	    *lastinop != XFS_AGINO_TO_INO(mp, agno, agino)) {
L
Linus Torvalds 已提交
366 367 368 369
		*done = 1;
		*ubcountp = 0;
		return 0;
	}
370

L
Linus Torvalds 已提交
371
	ubcount = *ubcountp; /* statstruct's */
372 373 374 375 376
	ac.ac_ubuffer = &ubuffer;
	ac.ac_ubleft = ubcount * statstruct_size; /* bytes */;
	ac.ac_ubelem = 0;

	*ubcountp = 0;
L
Linus Torvalds 已提交
377
	*done = 0;
378

D
Darrick J. Wong 已提交
379
	irbuf = kmem_zalloc_large(PAGE_SIZE * 4, KM_SLEEP);
380
	if (!irbuf)
D
Dave Chinner 已提交
381
		return -ENOMEM;
D
Darrick J. Wong 已提交
382
	nirbuf = (PAGE_SIZE * 4) / sizeof(*irbuf);
383

L
Linus Torvalds 已提交
384 385 386 387
	/*
	 * Loop over the allocation groups, starting from the last
	 * inode returned; 0 means start of the allocation group.
	 */
388 389 390 391 392 393 394
	while (agno < mp->m_sb.sb_agcount) {
		struct xfs_inobt_rec_incore	*irbp = irbuf;
		struct xfs_inobt_rec_incore	*irbufend = irbuf + nirbuf;
		bool				end_of_ag = false;
		int				icount = 0;
		int				stat;

L
Linus Torvalds 已提交
395
		error = xfs_ialloc_read_agi(mp, NULL, agno, &agbp);
396 397
		if (error)
			break;
L
Linus Torvalds 已提交
398 399 400
		/*
		 * Allocate and initialize a btree cursor for ialloc btree.
		 */
401 402
		cur = xfs_inobt_init_cursor(mp, NULL, agbp, agno,
					    XFS_BTNUM_INO);
L
Linus Torvalds 已提交
403 404
		if (agino > 0) {
			/*
405 406
			 * In the middle of an allocation group, we need to get
			 * the remainder of the chunk we're in.
L
Linus Torvalds 已提交
407
			 */
408 409 410 411
			struct xfs_inobt_rec_incore	r;

			error = xfs_bulkstat_grab_ichunk(cur, agino, &icount, &r);
			if (error)
412
				goto del_cursor;
413
			if (icount) {
414
				irbp->ir_startino = r.ir_startino;
415 416
				irbp->ir_holemask = r.ir_holemask;
				irbp->ir_count = r.ir_count;
417 418
				irbp->ir_freecount = r.ir_freecount;
				irbp->ir_free = r.ir_free;
L
Linus Torvalds 已提交
419 420
				irbp++;
			}
421
			/* Increment to the next record */
422
			error = xfs_btree_increment(cur, 0, &stat);
L
Linus Torvalds 已提交
423
		} else {
424
			/* Start of ag.  Lookup the first inode chunk */
425
			error = xfs_inobt_lookup(cur, 0, XFS_LOOKUP_GE, &stat);
L
Linus Torvalds 已提交
426
		}
427
		if (error || stat == 0) {
428
			end_of_ag = true;
429
			goto del_cursor;
430
		}
431

L
Linus Torvalds 已提交
432 433 434 435 436
		/*
		 * Loop through inode btree records in this ag,
		 * until we run out of inodes or space in the buffer.
		 */
		while (irbp < irbufend && icount < ubcount) {
437
			struct xfs_inobt_rec_incore	r;
438

439 440
			error = xfs_inobt_get_rec(cur, &r, &stat);
			if (error || stat == 0) {
441
				end_of_ag = true;
442
				goto del_cursor;
L
Linus Torvalds 已提交
443
			}
444

L
Linus Torvalds 已提交
445 446
			/*
			 * If this chunk has any allocated inodes, save it.
447
			 * Also start read-ahead now for this chunk.
L
Linus Torvalds 已提交
448
			 */
449
			if (r.ir_freecount < r.ir_count) {
J
Jie Liu 已提交
450
				xfs_bulkstat_ichunk_ra(mp, agno, &r);
451
				irbp->ir_startino = r.ir_startino;
452 453
				irbp->ir_holemask = r.ir_holemask;
				irbp->ir_count = r.ir_count;
454 455
				irbp->ir_freecount = r.ir_freecount;
				irbp->ir_free = r.ir_free;
L
Linus Torvalds 已提交
456
				irbp++;
457
				icount += r.ir_count - r.ir_freecount;
L
Linus Torvalds 已提交
458
			}
459 460
			error = xfs_btree_increment(cur, 0, &stat);
			if (error || stat == 0) {
461
				end_of_ag = true;
462 463
				goto del_cursor;
			}
464
			cond_resched();
L
Linus Torvalds 已提交
465
		}
466

L
Linus Torvalds 已提交
467
		/*
468 469 470
		 * Drop the btree buffers and the agi buffer as we can't hold any
		 * of the locks these represent when calling iget. If there is a
		 * pending error, then we are done.
L
Linus Torvalds 已提交
471
		 */
472
del_cursor:
473 474
		xfs_btree_del_cursor(cur, error ?
					  XFS_BTREE_ERROR : XFS_BTREE_NOERROR);
L
Linus Torvalds 已提交
475
		xfs_buf_relse(agbp);
476 477
		if (error)
			break;
L
Linus Torvalds 已提交
478
		/*
479 480 481
		 * Now format all the good inodes into the user's buffer. The
		 * call to xfs_bulkstat_ag_ichunk() sets up the agino pointer
		 * for the next loop iteration.
L
Linus Torvalds 已提交
482 483 484
		 */
		irbufend = irbp;
		for (irbp = irbuf;
485
		     irbp < irbufend && ac.ac_ubleft >= statstruct_size;
486
		     irbp++) {
J
Jie Liu 已提交
487
			error = xfs_bulkstat_ag_ichunk(mp, agno, irbp,
488
					formatter, statstruct_size, &ac,
489
					&agino);
J
Jie Liu 已提交
490
			if (error)
491
				break;
J
Jie Liu 已提交
492

493
			cond_resched();
L
Linus Torvalds 已提交
494
		}
495

496 497 498 499 500
		/*
		 * If we've run out of space or had a formatting error, we
		 * are now done
		 */
		if (ac.ac_ubleft < statstruct_size || error)
L
Linus Torvalds 已提交
501
			break;
502 503 504 505

		if (end_of_ag) {
			agno++;
			agino = 0;
506
		}
L
Linus Torvalds 已提交
507 508 509 510
	}
	/*
	 * Done, we're either out of filesystem or space to put the data.
	 */
511
	kmem_free(irbuf);
512
	*ubcountp = ac.ac_ubelem;
513

514
	/*
515 516 517 518 519
	 * We found some inodes, so clear the error status and return them.
	 * The lastino pointer will point directly at the inode that triggered
	 * any error that occurred, so on the next call the error will be
	 * triggered again and propagated to userspace as there will be no
	 * formatted inodes in the buffer.
520
	 */
521
	if (ac.ac_ubelem)
522 523
		error = 0;

524 525 526 527 528 529
	/*
	 * If we ran out of filesystem, lastino will point off the end of
	 * the filesystem so the next call will return immediately.
	 */
	*lastinop = XFS_AGINO_TO_INO(mp, agno, agino);
	if (agno >= mp->m_sb.sb_agcount)
L
Linus Torvalds 已提交
530 531
		*done = 1;

532
	return error;
L
Linus Torvalds 已提交
533 534
}

535 536 537
int
xfs_inumbers_fmt(
	void			__user *ubuffer, /* buffer to write to */
J
Jie Liu 已提交
538
	const struct xfs_inogrp	*buffer,	/* buffer to read from */
539 540 541 542 543 544 545 546 547
	long			count,		/* # of elements to read */
	long			*written)	/* # of bytes written */
{
	if (copy_to_user(ubuffer, buffer, count * sizeof(*buffer)))
		return -EFAULT;
	*written = count * sizeof(*buffer);
	return 0;
}

L
Linus Torvalds 已提交
548 549 550 551 552
/*
 * Return inode number table for the filesystem.
 */
int					/* error status */
xfs_inumbers(
J
Jie Liu 已提交
553 554 555 556 557
	struct xfs_mount	*mp,/* mount point for filesystem */
	xfs_ino_t		*lastino,/* last inode returned */
	int			*count,/* size of buffer/count returned */
	void			__user *ubuffer,/* buffer with inode descriptions */
	inumbers_fmt_pf		formatter)
L
Linus Torvalds 已提交
558
{
J
Jie Liu 已提交
559 560 561
	xfs_agnumber_t		agno = XFS_INO_TO_AGNO(mp, *lastino);
	xfs_agino_t		agino = XFS_INO_TO_AGINO(mp, *lastino);
	struct xfs_btree_cur	*cur = NULL;
562
	struct xfs_buf		*agbp = NULL;
J
Jie Liu 已提交
563 564 565 566 567 568
	struct xfs_inogrp	*buffer;
	int			bcount;
	int			left = *count;
	int			bufidx = 0;
	int			error = 0;

L
Linus Torvalds 已提交
569
	*count = 0;
J
Jie Liu 已提交
570 571 572 573
	if (agno >= mp->m_sb.sb_agcount ||
	    *lastino != XFS_AGINO_TO_INO(mp, agno, agino))
		return error;

574
	bcount = MIN(left, (int)(PAGE_SIZE / sizeof(*buffer)));
575
	buffer = kmem_zalloc(bcount * sizeof(*buffer), KM_SLEEP);
576
	do {
J
Jie Liu 已提交
577 578 579
		struct xfs_inobt_rec_incore	r;
		int				stat;

580
		if (!agbp) {
L
Linus Torvalds 已提交
581
			error = xfs_ialloc_read_agi(mp, NULL, agno, &agbp);
582 583 584
			if (error)
				break;

585 586
			cur = xfs_inobt_init_cursor(mp, NULL, agbp, agno,
						    XFS_BTNUM_INO);
587
			error = xfs_inobt_lookup(cur, agino, XFS_LOOKUP_GE,
J
Jie Liu 已提交
588
						 &stat);
589 590 591 592
			if (error)
				break;
			if (!stat)
				goto next_ag;
L
Linus Torvalds 已提交
593
		}
594

J
Jie Liu 已提交
595
		error = xfs_inobt_get_rec(cur, &r, &stat);
596 597 598 599 600
		if (error)
			break;
		if (!stat)
			goto next_ag;

601 602 603
		agino = r.ir_startino + XFS_INODES_PER_CHUNK - 1;
		buffer[bufidx].xi_startino =
			XFS_AGINO_TO_INO(mp, agno, r.ir_startino);
604
		buffer[bufidx].xi_alloccount = r.ir_count - r.ir_freecount;
605
		buffer[bufidx].xi_allocmask = ~r.ir_free;
606 607 608
		if (++bufidx == bcount) {
			long	written;

J
Jie Liu 已提交
609 610
			error = formatter(ubuffer, buffer, bufidx, &written);
			if (error)
L
Linus Torvalds 已提交
611
				break;
612
			ubuffer += written;
L
Linus Torvalds 已提交
613 614 615
			*count += bufidx;
			bufidx = 0;
		}
616 617 618 619 620 621 622 623 624 625 626 627 628 629 630
		if (!--left)
			break;

		error = xfs_btree_increment(cur, 0, &stat);
		if (error)
			break;
		if (stat)
			continue;

next_ag:
		xfs_btree_del_cursor(cur, XFS_BTREE_ERROR);
		cur = NULL;
		xfs_buf_relse(agbp);
		agbp = NULL;
		agino = 0;
631 632
		agno++;
	} while (agno < mp->m_sb.sb_agcount);
633

L
Linus Torvalds 已提交
634 635
	if (!error) {
		if (bufidx) {
636 637
			long	written;

J
Jie Liu 已提交
638 639
			error = formatter(ubuffer, buffer, bufidx, &written);
			if (!error)
L
Linus Torvalds 已提交
640 641 642 643
				*count += bufidx;
		}
		*lastino = XFS_AGINO_TO_INO(mp, agno, agino);
	}
644

645
	kmem_free(buffer);
L
Linus Torvalds 已提交
646 647 648 649 650
	if (cur)
		xfs_btree_del_cursor(cur, (error ? XFS_BTREE_ERROR :
					   XFS_BTREE_NOERROR));
	if (agbp)
		xfs_buf_relse(agbp);
651

L
Linus Torvalds 已提交
652 653
	return error;
}