| rjw | 1f88458 | 2022-01-06 17:20:42 +0800 | [diff] [blame] | 1 | /* | 
|  | 2 | * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc. | 
|  | 3 | * All Rights Reserved. | 
|  | 4 | * | 
|  | 5 | * This program is free software; you can redistribute it and/or | 
|  | 6 | * modify it under the terms of the GNU General Public License as | 
|  | 7 | * published by the Free Software Foundation. | 
|  | 8 | * | 
|  | 9 | * This program is distributed in the hope that it would be useful, | 
|  | 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | 12 | * GNU General Public License for more details. | 
|  | 13 | * | 
|  | 14 | * You should have received a copy of the GNU General Public License | 
|  | 15 | * along with this program; if not, write the Free Software Foundation, | 
|  | 16 | * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA | 
|  | 17 | */ | 
|  | 18 | #include "xfs.h" | 
|  | 19 | #include "xfs_fs.h" | 
|  | 20 | #include "xfs_shared.h" | 
|  | 21 | #include "xfs_format.h" | 
|  | 22 | #include "xfs_log_format.h" | 
|  | 23 | #include "xfs_trans_resv.h" | 
|  | 24 | #include "xfs_mount.h" | 
|  | 25 | #include "xfs_inode.h" | 
|  | 26 | #include "xfs_btree.h" | 
|  | 27 | #include "xfs_ialloc.h" | 
|  | 28 | #include "xfs_ialloc_btree.h" | 
|  | 29 | #include "xfs_itable.h" | 
|  | 30 | #include "xfs_error.h" | 
|  | 31 | #include "xfs_trace.h" | 
|  | 32 | #include "xfs_icache.h" | 
|  | 33 |  | 
|  | 34 | int | 
|  | 35 | xfs_internal_inum( | 
|  | 36 | xfs_mount_t	*mp, | 
|  | 37 | xfs_ino_t	ino) | 
|  | 38 | { | 
|  | 39 | return (ino == mp->m_sb.sb_rbmino || ino == mp->m_sb.sb_rsumino || | 
|  | 40 | (xfs_sb_version_hasquota(&mp->m_sb) && | 
|  | 41 | xfs_is_quota_inode(&mp->m_sb, ino))); | 
|  | 42 | } | 
|  | 43 |  | 
|  | 44 | /* | 
|  | 45 | * Return stat information for one inode. | 
|  | 46 | * Return 0 if ok, else errno. | 
|  | 47 | */ | 
|  | 48 | int | 
|  | 49 | xfs_bulkstat_one_int( | 
|  | 50 | struct xfs_mount	*mp,		/* mount point for filesystem */ | 
|  | 51 | xfs_ino_t		ino,		/* inode to get data for */ | 
|  | 52 | void __user		*buffer,	/* buffer to place output in */ | 
|  | 53 | int			ubsize,		/* size of buffer */ | 
|  | 54 | bulkstat_one_fmt_pf	formatter,	/* formatter, copy to user */ | 
|  | 55 | int			*ubused,	/* bytes used by me */ | 
|  | 56 | int			*stat)		/* BULKSTAT_RV_... */ | 
|  | 57 | { | 
|  | 58 | struct xfs_icdinode	*dic;		/* dinode core info pointer */ | 
|  | 59 | struct xfs_inode	*ip;		/* incore inode pointer */ | 
|  | 60 | struct inode		*inode; | 
|  | 61 | struct xfs_bstat	*buf;		/* return buffer */ | 
|  | 62 | int			error = 0;	/* error value */ | 
|  | 63 |  | 
|  | 64 | *stat = BULKSTAT_RV_NOTHING; | 
|  | 65 |  | 
|  | 66 | if (!buffer || xfs_internal_inum(mp, ino)) | 
|  | 67 | return -EINVAL; | 
|  | 68 |  | 
|  | 69 | buf = kmem_zalloc(sizeof(*buf), KM_SLEEP | KM_MAYFAIL); | 
|  | 70 | if (!buf) | 
|  | 71 | return -ENOMEM; | 
|  | 72 |  | 
|  | 73 | error = xfs_iget(mp, NULL, ino, | 
|  | 74 | (XFS_IGET_DONTCACHE | XFS_IGET_UNTRUSTED), | 
|  | 75 | XFS_ILOCK_SHARED, &ip); | 
|  | 76 | if (error) | 
|  | 77 | goto out_free; | 
|  | 78 |  | 
|  | 79 | ASSERT(ip != NULL); | 
|  | 80 | ASSERT(ip->i_imap.im_blkno != 0); | 
|  | 81 | inode = VFS_I(ip); | 
|  | 82 |  | 
|  | 83 | dic = &ip->i_d; | 
|  | 84 |  | 
|  | 85 | /* xfs_iget returns the following without needing | 
|  | 86 | * further change. | 
|  | 87 | */ | 
|  | 88 | buf->bs_projid_lo = dic->di_projid_lo; | 
|  | 89 | buf->bs_projid_hi = dic->di_projid_hi; | 
|  | 90 | buf->bs_ino = ino; | 
|  | 91 | buf->bs_uid = dic->di_uid; | 
|  | 92 | buf->bs_gid = dic->di_gid; | 
|  | 93 | buf->bs_size = dic->di_size; | 
|  | 94 |  | 
|  | 95 | buf->bs_nlink = inode->i_nlink; | 
|  | 96 | buf->bs_atime.tv_sec = inode->i_atime.tv_sec; | 
|  | 97 | buf->bs_atime.tv_nsec = inode->i_atime.tv_nsec; | 
|  | 98 | buf->bs_mtime.tv_sec = inode->i_mtime.tv_sec; | 
|  | 99 | buf->bs_mtime.tv_nsec = inode->i_mtime.tv_nsec; | 
|  | 100 | buf->bs_ctime.tv_sec = inode->i_ctime.tv_sec; | 
|  | 101 | buf->bs_ctime.tv_nsec = inode->i_ctime.tv_nsec; | 
|  | 102 | buf->bs_gen = inode->i_generation; | 
|  | 103 | buf->bs_mode = inode->i_mode; | 
|  | 104 |  | 
|  | 105 | buf->bs_xflags = xfs_ip2xflags(ip); | 
|  | 106 | buf->bs_extsize = dic->di_extsize << mp->m_sb.sb_blocklog; | 
|  | 107 | buf->bs_extents = dic->di_nextents; | 
|  | 108 | memset(buf->bs_pad, 0, sizeof(buf->bs_pad)); | 
|  | 109 | buf->bs_dmevmask = dic->di_dmevmask; | 
|  | 110 | buf->bs_dmstate = dic->di_dmstate; | 
|  | 111 | buf->bs_aextents = dic->di_anextents; | 
|  | 112 | buf->bs_forkoff = XFS_IFORK_BOFF(ip); | 
|  | 113 |  | 
|  | 114 | if (dic->di_version == 3) { | 
|  | 115 | if (dic->di_flags2 & XFS_DIFLAG2_COWEXTSIZE) | 
|  | 116 | buf->bs_cowextsize = dic->di_cowextsize << | 
|  | 117 | mp->m_sb.sb_blocklog; | 
|  | 118 | } | 
|  | 119 |  | 
|  | 120 | switch (dic->di_format) { | 
|  | 121 | case XFS_DINODE_FMT_DEV: | 
|  | 122 | buf->bs_rdev = ip->i_df.if_u2.if_rdev; | 
|  | 123 | buf->bs_blksize = BLKDEV_IOSIZE; | 
|  | 124 | buf->bs_blocks = 0; | 
|  | 125 | break; | 
|  | 126 | case XFS_DINODE_FMT_LOCAL: | 
|  | 127 | case XFS_DINODE_FMT_UUID: | 
|  | 128 | buf->bs_rdev = 0; | 
|  | 129 | buf->bs_blksize = mp->m_sb.sb_blocksize; | 
|  | 130 | buf->bs_blocks = 0; | 
|  | 131 | break; | 
|  | 132 | case XFS_DINODE_FMT_EXTENTS: | 
|  | 133 | case XFS_DINODE_FMT_BTREE: | 
|  | 134 | buf->bs_rdev = 0; | 
|  | 135 | buf->bs_blksize = mp->m_sb.sb_blocksize; | 
|  | 136 | buf->bs_blocks = dic->di_nblocks + ip->i_delayed_blks; | 
|  | 137 | break; | 
|  | 138 | } | 
|  | 139 | xfs_iunlock(ip, XFS_ILOCK_SHARED); | 
|  | 140 | IRELE(ip); | 
|  | 141 |  | 
|  | 142 | error = formatter(buffer, ubsize, ubused, buf); | 
|  | 143 | if (!error) | 
|  | 144 | *stat = BULKSTAT_RV_DIDONE; | 
|  | 145 |  | 
|  | 146 | out_free: | 
|  | 147 | kmem_free(buf); | 
|  | 148 | return error; | 
|  | 149 | } | 
|  | 150 |  | 
|  | 151 | /* Return 0 on success or positive error */ | 
|  | 152 | STATIC int | 
|  | 153 | xfs_bulkstat_one_fmt( | 
|  | 154 | void			__user *ubuffer, | 
|  | 155 | int			ubsize, | 
|  | 156 | int			*ubused, | 
|  | 157 | const xfs_bstat_t	*buffer) | 
|  | 158 | { | 
|  | 159 | if (ubsize < sizeof(*buffer)) | 
|  | 160 | return -ENOMEM; | 
|  | 161 | if (copy_to_user(ubuffer, buffer, sizeof(*buffer))) | 
|  | 162 | return -EFAULT; | 
|  | 163 | if (ubused) | 
|  | 164 | *ubused = sizeof(*buffer); | 
|  | 165 | return 0; | 
|  | 166 | } | 
|  | 167 |  | 
|  | 168 | int | 
|  | 169 | xfs_bulkstat_one( | 
|  | 170 | xfs_mount_t	*mp,		/* mount point for filesystem */ | 
|  | 171 | xfs_ino_t	ino,		/* inode number to get data for */ | 
|  | 172 | void		__user *buffer,	/* buffer to place output in */ | 
|  | 173 | int		ubsize,		/* size of buffer */ | 
|  | 174 | int		*ubused,	/* bytes used by me */ | 
|  | 175 | int		*stat)		/* BULKSTAT_RV_... */ | 
|  | 176 | { | 
|  | 177 | return xfs_bulkstat_one_int(mp, ino, buffer, ubsize, | 
|  | 178 | xfs_bulkstat_one_fmt, ubused, stat); | 
|  | 179 | } | 
|  | 180 |  | 
|  | 181 | /* | 
|  | 182 | * Loop over all clusters in a chunk for a given incore inode allocation btree | 
|  | 183 | * record.  Do a readahead if there are any allocated inodes in that cluster. | 
|  | 184 | */ | 
|  | 185 | STATIC void | 
|  | 186 | xfs_bulkstat_ichunk_ra( | 
|  | 187 | struct xfs_mount		*mp, | 
|  | 188 | xfs_agnumber_t			agno, | 
|  | 189 | struct xfs_inobt_rec_incore	*irec) | 
|  | 190 | { | 
|  | 191 | xfs_agblock_t			agbno; | 
|  | 192 | struct blk_plug			plug; | 
|  | 193 | int				blks_per_cluster; | 
|  | 194 | int				inodes_per_cluster; | 
|  | 195 | int				i;	/* inode chunk index */ | 
|  | 196 |  | 
|  | 197 | agbno = XFS_AGINO_TO_AGBNO(mp, irec->ir_startino); | 
|  | 198 | blks_per_cluster = xfs_icluster_size_fsb(mp); | 
|  | 199 | inodes_per_cluster = blks_per_cluster << mp->m_sb.sb_inopblog; | 
|  | 200 |  | 
|  | 201 | blk_start_plug(&plug); | 
|  | 202 | for (i = 0; i < XFS_INODES_PER_CHUNK; | 
|  | 203 | i += inodes_per_cluster, agbno += blks_per_cluster) { | 
|  | 204 | if (xfs_inobt_maskn(i, inodes_per_cluster) & ~irec->ir_free) { | 
|  | 205 | xfs_btree_reada_bufs(mp, agno, agbno, blks_per_cluster, | 
|  | 206 | &xfs_inode_buf_ops); | 
|  | 207 | } | 
|  | 208 | } | 
|  | 209 | blk_finish_plug(&plug); | 
|  | 210 | } | 
|  | 211 |  | 
|  | 212 | /* | 
|  | 213 | * Lookup the inode chunk that the given inode lives in and then get the record | 
|  | 214 | * if we found the chunk.  If the inode was not the last in the chunk and there | 
|  | 215 | * are some left allocated, update the data for the pointed-to record as well as | 
|  | 216 | * return the count of grabbed inodes. | 
|  | 217 | */ | 
|  | 218 | STATIC int | 
|  | 219 | xfs_bulkstat_grab_ichunk( | 
|  | 220 | struct xfs_btree_cur		*cur,	/* btree cursor */ | 
|  | 221 | xfs_agino_t			agino,	/* starting inode of chunk */ | 
|  | 222 | int				*icount,/* return # of inodes grabbed */ | 
|  | 223 | struct xfs_inobt_rec_incore	*irec)	/* btree record */ | 
|  | 224 | { | 
|  | 225 | int				idx;	/* index into inode chunk */ | 
|  | 226 | int				stat; | 
|  | 227 | int				error = 0; | 
|  | 228 |  | 
|  | 229 | /* Lookup the inode chunk that this inode lives in */ | 
|  | 230 | error = xfs_inobt_lookup(cur, agino, XFS_LOOKUP_LE, &stat); | 
|  | 231 | if (error) | 
|  | 232 | return error; | 
|  | 233 | if (!stat) { | 
|  | 234 | *icount = 0; | 
|  | 235 | return error; | 
|  | 236 | } | 
|  | 237 |  | 
|  | 238 | /* Get the record, should always work */ | 
|  | 239 | error = xfs_inobt_get_rec(cur, irec, &stat); | 
|  | 240 | if (error) | 
|  | 241 | return error; | 
|  | 242 | XFS_WANT_CORRUPTED_RETURN(cur->bc_mp, stat == 1); | 
|  | 243 |  | 
|  | 244 | /* Check if the record contains the inode in request */ | 
|  | 245 | if (irec->ir_startino + XFS_INODES_PER_CHUNK <= agino) { | 
|  | 246 | *icount = 0; | 
|  | 247 | return 0; | 
|  | 248 | } | 
|  | 249 |  | 
|  | 250 | idx = agino - irec->ir_startino + 1; | 
|  | 251 | if (idx < XFS_INODES_PER_CHUNK && | 
|  | 252 | (xfs_inobt_maskn(idx, XFS_INODES_PER_CHUNK - idx) & ~irec->ir_free)) { | 
|  | 253 | int	i; | 
|  | 254 |  | 
|  | 255 | /* We got a right chunk with some left inodes allocated at it. | 
|  | 256 | * Grab the chunk record.  Mark all the uninteresting inodes | 
|  | 257 | * free -- because they're before our start point. | 
|  | 258 | */ | 
|  | 259 | for (i = 0; i < idx; i++) { | 
|  | 260 | if (XFS_INOBT_MASK(i) & ~irec->ir_free) | 
|  | 261 | irec->ir_freecount++; | 
|  | 262 | } | 
|  | 263 |  | 
|  | 264 | irec->ir_free |= xfs_inobt_maskn(0, idx); | 
|  | 265 | *icount = irec->ir_count - irec->ir_freecount; | 
|  | 266 | } | 
|  | 267 |  | 
|  | 268 | return 0; | 
|  | 269 | } | 
|  | 270 |  | 
|  | 271 | #define XFS_BULKSTAT_UBLEFT(ubleft)	((ubleft) >= statstruct_size) | 
|  | 272 |  | 
|  | 273 | struct xfs_bulkstat_agichunk { | 
|  | 274 | char		__user **ac_ubuffer;/* pointer into user's buffer */ | 
|  | 275 | int		ac_ubleft;	/* bytes left in user's buffer */ | 
|  | 276 | int		ac_ubelem;	/* spaces used in user's buffer */ | 
|  | 277 | }; | 
|  | 278 |  | 
|  | 279 | /* | 
|  | 280 | * Process inodes in chunk with a pointer to a formatter function | 
|  | 281 | * that will iget the inode and fill in the appropriate structure. | 
|  | 282 | */ | 
|  | 283 | static int | 
|  | 284 | xfs_bulkstat_ag_ichunk( | 
|  | 285 | struct xfs_mount		*mp, | 
|  | 286 | xfs_agnumber_t			agno, | 
|  | 287 | struct xfs_inobt_rec_incore	*irbp, | 
|  | 288 | bulkstat_one_pf			formatter, | 
|  | 289 | size_t				statstruct_size, | 
|  | 290 | struct xfs_bulkstat_agichunk	*acp, | 
|  | 291 | xfs_agino_t			*last_agino) | 
|  | 292 | { | 
|  | 293 | char				__user **ubufp = acp->ac_ubuffer; | 
|  | 294 | int				chunkidx; | 
|  | 295 | int				error = 0; | 
|  | 296 | xfs_agino_t			agino = irbp->ir_startino; | 
|  | 297 |  | 
|  | 298 | for (chunkidx = 0; chunkidx < XFS_INODES_PER_CHUNK; | 
|  | 299 | chunkidx++, agino++) { | 
|  | 300 | int		fmterror; | 
|  | 301 | int		ubused; | 
|  | 302 |  | 
|  | 303 | /* inode won't fit in buffer, we are done */ | 
|  | 304 | if (acp->ac_ubleft < statstruct_size) | 
|  | 305 | break; | 
|  | 306 |  | 
|  | 307 | /* Skip if this inode is free */ | 
|  | 308 | if (XFS_INOBT_MASK(chunkidx) & irbp->ir_free) | 
|  | 309 | continue; | 
|  | 310 |  | 
|  | 311 | /* Get the inode and fill in a single buffer */ | 
|  | 312 | ubused = statstruct_size; | 
|  | 313 | error = formatter(mp, XFS_AGINO_TO_INO(mp, agno, agino), | 
|  | 314 | *ubufp, acp->ac_ubleft, &ubused, &fmterror); | 
|  | 315 |  | 
|  | 316 | if (fmterror == BULKSTAT_RV_GIVEUP || | 
|  | 317 | (error && error != -ENOENT && error != -EINVAL)) { | 
|  | 318 | acp->ac_ubleft = 0; | 
|  | 319 | ASSERT(error); | 
|  | 320 | break; | 
|  | 321 | } | 
|  | 322 |  | 
|  | 323 | /* be careful not to leak error if at end of chunk */ | 
|  | 324 | if (fmterror == BULKSTAT_RV_NOTHING || error) { | 
|  | 325 | error = 0; | 
|  | 326 | continue; | 
|  | 327 | } | 
|  | 328 |  | 
|  | 329 | *ubufp += ubused; | 
|  | 330 | acp->ac_ubleft -= ubused; | 
|  | 331 | acp->ac_ubelem++; | 
|  | 332 | } | 
|  | 333 |  | 
|  | 334 | /* | 
|  | 335 | * Post-update *last_agino. At this point, agino will always point one | 
|  | 336 | * inode past the last inode we processed successfully. Hence we | 
|  | 337 | * substract that inode when setting the *last_agino cursor so that we | 
|  | 338 | * return the correct cookie to userspace. On the next bulkstat call, | 
|  | 339 | * the inode under the lastino cookie will be skipped as we have already | 
|  | 340 | * processed it here. | 
|  | 341 | */ | 
|  | 342 | *last_agino = agino - 1; | 
|  | 343 |  | 
|  | 344 | return error; | 
|  | 345 | } | 
|  | 346 |  | 
|  | 347 | /* | 
|  | 348 | * Return stat information in bulk (by-inode) for the filesystem. | 
|  | 349 | */ | 
|  | 350 | int					/* error status */ | 
|  | 351 | xfs_bulkstat( | 
|  | 352 | xfs_mount_t		*mp,	/* mount point for filesystem */ | 
|  | 353 | xfs_ino_t		*lastinop, /* last inode returned */ | 
|  | 354 | int			*ubcountp, /* size of buffer/count returned */ | 
|  | 355 | bulkstat_one_pf		formatter, /* func that'd fill a single buf */ | 
|  | 356 | size_t			statstruct_size, /* sizeof struct filling */ | 
|  | 357 | char			__user *ubuffer, /* buffer with inode stats */ | 
|  | 358 | int			*done)	/* 1 if there are more stats to get */ | 
|  | 359 | { | 
|  | 360 | xfs_buf_t		*agbp;	/* agi header buffer */ | 
|  | 361 | xfs_agino_t		agino;	/* inode # in allocation group */ | 
|  | 362 | xfs_agnumber_t		agno;	/* allocation group number */ | 
|  | 363 | xfs_btree_cur_t		*cur;	/* btree cursor for ialloc btree */ | 
|  | 364 | xfs_inobt_rec_incore_t	*irbuf;	/* start of irec buffer */ | 
|  | 365 | int			nirbuf;	/* size of irbuf */ | 
|  | 366 | int			ubcount; /* size of user's buffer */ | 
|  | 367 | struct xfs_bulkstat_agichunk ac; | 
|  | 368 | int			error = 0; | 
|  | 369 |  | 
|  | 370 | /* | 
|  | 371 | * Get the last inode value, see if there's nothing to do. | 
|  | 372 | */ | 
|  | 373 | agno = XFS_INO_TO_AGNO(mp, *lastinop); | 
|  | 374 | agino = XFS_INO_TO_AGINO(mp, *lastinop); | 
|  | 375 | if (agno >= mp->m_sb.sb_agcount || | 
|  | 376 | *lastinop != XFS_AGINO_TO_INO(mp, agno, agino)) { | 
|  | 377 | *done = 1; | 
|  | 378 | *ubcountp = 0; | 
|  | 379 | return 0; | 
|  | 380 | } | 
|  | 381 |  | 
|  | 382 | ubcount = *ubcountp; /* statstruct's */ | 
|  | 383 | ac.ac_ubuffer = &ubuffer; | 
|  | 384 | ac.ac_ubleft = ubcount * statstruct_size; /* bytes */; | 
|  | 385 | ac.ac_ubelem = 0; | 
|  | 386 |  | 
|  | 387 | *ubcountp = 0; | 
|  | 388 | *done = 0; | 
|  | 389 |  | 
|  | 390 | irbuf = kmem_zalloc_large(PAGE_SIZE * 4, KM_SLEEP); | 
|  | 391 | if (!irbuf) | 
|  | 392 | return -ENOMEM; | 
|  | 393 | nirbuf = (PAGE_SIZE * 4) / sizeof(*irbuf); | 
|  | 394 |  | 
|  | 395 | /* | 
|  | 396 | * Loop over the allocation groups, starting from the last | 
|  | 397 | * inode returned; 0 means start of the allocation group. | 
|  | 398 | */ | 
|  | 399 | while (agno < mp->m_sb.sb_agcount) { | 
|  | 400 | struct xfs_inobt_rec_incore	*irbp = irbuf; | 
|  | 401 | struct xfs_inobt_rec_incore	*irbufend = irbuf + nirbuf; | 
|  | 402 | bool				end_of_ag = false; | 
|  | 403 | int				icount = 0; | 
|  | 404 | int				stat; | 
|  | 405 |  | 
|  | 406 | error = xfs_ialloc_read_agi(mp, NULL, agno, &agbp); | 
|  | 407 | if (error) | 
|  | 408 | break; | 
|  | 409 | /* | 
|  | 410 | * Allocate and initialize a btree cursor for ialloc btree. | 
|  | 411 | */ | 
|  | 412 | cur = xfs_inobt_init_cursor(mp, NULL, agbp, agno, | 
|  | 413 | XFS_BTNUM_INO); | 
|  | 414 | if (agino > 0) { | 
|  | 415 | /* | 
|  | 416 | * In the middle of an allocation group, we need to get | 
|  | 417 | * the remainder of the chunk we're in. | 
|  | 418 | */ | 
|  | 419 | struct xfs_inobt_rec_incore	r; | 
|  | 420 |  | 
|  | 421 | error = xfs_bulkstat_grab_ichunk(cur, agino, &icount, &r); | 
|  | 422 | if (error) | 
|  | 423 | goto del_cursor; | 
|  | 424 | if (icount) { | 
|  | 425 | irbp->ir_startino = r.ir_startino; | 
|  | 426 | irbp->ir_holemask = r.ir_holemask; | 
|  | 427 | irbp->ir_count = r.ir_count; | 
|  | 428 | irbp->ir_freecount = r.ir_freecount; | 
|  | 429 | irbp->ir_free = r.ir_free; | 
|  | 430 | irbp++; | 
|  | 431 | } | 
|  | 432 | /* Increment to the next record */ | 
|  | 433 | error = xfs_btree_increment(cur, 0, &stat); | 
|  | 434 | } else { | 
|  | 435 | /* Start of ag.  Lookup the first inode chunk */ | 
|  | 436 | error = xfs_inobt_lookup(cur, 0, XFS_LOOKUP_GE, &stat); | 
|  | 437 | } | 
|  | 438 | if (error || stat == 0) { | 
|  | 439 | end_of_ag = true; | 
|  | 440 | goto del_cursor; | 
|  | 441 | } | 
|  | 442 |  | 
|  | 443 | /* | 
|  | 444 | * Loop through inode btree records in this ag, | 
|  | 445 | * until we run out of inodes or space in the buffer. | 
|  | 446 | */ | 
|  | 447 | while (irbp < irbufend && icount < ubcount) { | 
|  | 448 | struct xfs_inobt_rec_incore	r; | 
|  | 449 |  | 
|  | 450 | error = xfs_inobt_get_rec(cur, &r, &stat); | 
|  | 451 | if (error || stat == 0) { | 
|  | 452 | end_of_ag = true; | 
|  | 453 | goto del_cursor; | 
|  | 454 | } | 
|  | 455 |  | 
|  | 456 | /* | 
|  | 457 | * If this chunk has any allocated inodes, save it. | 
|  | 458 | * Also start read-ahead now for this chunk. | 
|  | 459 | */ | 
|  | 460 | if (r.ir_freecount < r.ir_count) { | 
|  | 461 | xfs_bulkstat_ichunk_ra(mp, agno, &r); | 
|  | 462 | irbp->ir_startino = r.ir_startino; | 
|  | 463 | irbp->ir_holemask = r.ir_holemask; | 
|  | 464 | irbp->ir_count = r.ir_count; | 
|  | 465 | irbp->ir_freecount = r.ir_freecount; | 
|  | 466 | irbp->ir_free = r.ir_free; | 
|  | 467 | irbp++; | 
|  | 468 | icount += r.ir_count - r.ir_freecount; | 
|  | 469 | } | 
|  | 470 | error = xfs_btree_increment(cur, 0, &stat); | 
|  | 471 | if (error || stat == 0) { | 
|  | 472 | end_of_ag = true; | 
|  | 473 | goto del_cursor; | 
|  | 474 | } | 
|  | 475 | cond_resched(); | 
|  | 476 | } | 
|  | 477 |  | 
|  | 478 | /* | 
|  | 479 | * Drop the btree buffers and the agi buffer as we can't hold any | 
|  | 480 | * of the locks these represent when calling iget. If there is a | 
|  | 481 | * pending error, then we are done. | 
|  | 482 | */ | 
|  | 483 | del_cursor: | 
|  | 484 | xfs_btree_del_cursor(cur, error ? | 
|  | 485 | XFS_BTREE_ERROR : XFS_BTREE_NOERROR); | 
|  | 486 | xfs_buf_relse(agbp); | 
|  | 487 | if (error) | 
|  | 488 | break; | 
|  | 489 | /* | 
|  | 490 | * Now format all the good inodes into the user's buffer. The | 
|  | 491 | * call to xfs_bulkstat_ag_ichunk() sets up the agino pointer | 
|  | 492 | * for the next loop iteration. | 
|  | 493 | */ | 
|  | 494 | irbufend = irbp; | 
|  | 495 | for (irbp = irbuf; | 
|  | 496 | irbp < irbufend && ac.ac_ubleft >= statstruct_size; | 
|  | 497 | irbp++) { | 
|  | 498 | error = xfs_bulkstat_ag_ichunk(mp, agno, irbp, | 
|  | 499 | formatter, statstruct_size, &ac, | 
|  | 500 | &agino); | 
|  | 501 | if (error) | 
|  | 502 | break; | 
|  | 503 |  | 
|  | 504 | cond_resched(); | 
|  | 505 | } | 
|  | 506 |  | 
|  | 507 | /* | 
|  | 508 | * If we've run out of space or had a formatting error, we | 
|  | 509 | * are now done | 
|  | 510 | */ | 
|  | 511 | if (ac.ac_ubleft < statstruct_size || error) | 
|  | 512 | break; | 
|  | 513 |  | 
|  | 514 | if (end_of_ag) { | 
|  | 515 | agno++; | 
|  | 516 | agino = 0; | 
|  | 517 | } | 
|  | 518 | } | 
|  | 519 | /* | 
|  | 520 | * Done, we're either out of filesystem or space to put the data. | 
|  | 521 | */ | 
|  | 522 | kmem_free(irbuf); | 
|  | 523 | *ubcountp = ac.ac_ubelem; | 
|  | 524 |  | 
|  | 525 | /* | 
|  | 526 | * We found some inodes, so clear the error status and return them. | 
|  | 527 | * The lastino pointer will point directly at the inode that triggered | 
|  | 528 | * any error that occurred, so on the next call the error will be | 
|  | 529 | * triggered again and propagated to userspace as there will be no | 
|  | 530 | * formatted inodes in the buffer. | 
|  | 531 | */ | 
|  | 532 | if (ac.ac_ubelem) | 
|  | 533 | error = 0; | 
|  | 534 |  | 
|  | 535 | /* | 
|  | 536 | * If we ran out of filesystem, lastino will point off the end of | 
|  | 537 | * the filesystem so the next call will return immediately. | 
|  | 538 | */ | 
|  | 539 | *lastinop = XFS_AGINO_TO_INO(mp, agno, agino); | 
|  | 540 | if (agno >= mp->m_sb.sb_agcount) | 
|  | 541 | *done = 1; | 
|  | 542 |  | 
|  | 543 | return error; | 
|  | 544 | } | 
|  | 545 |  | 
|  | 546 | int | 
|  | 547 | xfs_inumbers_fmt( | 
|  | 548 | void			__user *ubuffer, /* buffer to write to */ | 
|  | 549 | const struct xfs_inogrp	*buffer,	/* buffer to read from */ | 
|  | 550 | long			count,		/* # of elements to read */ | 
|  | 551 | long			*written)	/* # of bytes written */ | 
|  | 552 | { | 
|  | 553 | if (copy_to_user(ubuffer, buffer, count * sizeof(*buffer))) | 
|  | 554 | return -EFAULT; | 
|  | 555 | *written = count * sizeof(*buffer); | 
|  | 556 | return 0; | 
|  | 557 | } | 
|  | 558 |  | 
|  | 559 | /* | 
|  | 560 | * Return inode number table for the filesystem. | 
|  | 561 | */ | 
|  | 562 | int					/* error status */ | 
|  | 563 | xfs_inumbers( | 
|  | 564 | struct xfs_mount	*mp,/* mount point for filesystem */ | 
|  | 565 | xfs_ino_t		*lastino,/* last inode returned */ | 
|  | 566 | int			*count,/* size of buffer/count returned */ | 
|  | 567 | void			__user *ubuffer,/* buffer with inode descriptions */ | 
|  | 568 | inumbers_fmt_pf		formatter) | 
|  | 569 | { | 
|  | 570 | xfs_agnumber_t		agno = XFS_INO_TO_AGNO(mp, *lastino); | 
|  | 571 | xfs_agino_t		agino = XFS_INO_TO_AGINO(mp, *lastino); | 
|  | 572 | struct xfs_btree_cur	*cur = NULL; | 
|  | 573 | struct xfs_buf		*agbp = NULL; | 
|  | 574 | struct xfs_inogrp	*buffer; | 
|  | 575 | int			bcount; | 
|  | 576 | int			left = *count; | 
|  | 577 | int			bufidx = 0; | 
|  | 578 | int			error = 0; | 
|  | 579 |  | 
|  | 580 | *count = 0; | 
|  | 581 | if (agno >= mp->m_sb.sb_agcount || | 
|  | 582 | *lastino != XFS_AGINO_TO_INO(mp, agno, agino)) | 
|  | 583 | return error; | 
|  | 584 |  | 
|  | 585 | bcount = MIN(left, (int)(PAGE_SIZE / sizeof(*buffer))); | 
|  | 586 | buffer = kmem_zalloc(bcount * sizeof(*buffer), KM_SLEEP); | 
|  | 587 | do { | 
|  | 588 | struct xfs_inobt_rec_incore	r; | 
|  | 589 | int				stat; | 
|  | 590 |  | 
|  | 591 | if (!agbp) { | 
|  | 592 | error = xfs_ialloc_read_agi(mp, NULL, agno, &agbp); | 
|  | 593 | if (error) | 
|  | 594 | break; | 
|  | 595 |  | 
|  | 596 | cur = xfs_inobt_init_cursor(mp, NULL, agbp, agno, | 
|  | 597 | XFS_BTNUM_INO); | 
|  | 598 | error = xfs_inobt_lookup(cur, agino, XFS_LOOKUP_GE, | 
|  | 599 | &stat); | 
|  | 600 | if (error) | 
|  | 601 | break; | 
|  | 602 | if (!stat) | 
|  | 603 | goto next_ag; | 
|  | 604 | } | 
|  | 605 |  | 
|  | 606 | error = xfs_inobt_get_rec(cur, &r, &stat); | 
|  | 607 | if (error) | 
|  | 608 | break; | 
|  | 609 | if (!stat) | 
|  | 610 | goto next_ag; | 
|  | 611 |  | 
|  | 612 | agino = r.ir_startino + XFS_INODES_PER_CHUNK - 1; | 
|  | 613 | buffer[bufidx].xi_startino = | 
|  | 614 | XFS_AGINO_TO_INO(mp, agno, r.ir_startino); | 
|  | 615 | buffer[bufidx].xi_alloccount = r.ir_count - r.ir_freecount; | 
|  | 616 | buffer[bufidx].xi_allocmask = ~r.ir_free; | 
|  | 617 | if (++bufidx == bcount) { | 
|  | 618 | long	written; | 
|  | 619 |  | 
|  | 620 | error = formatter(ubuffer, buffer, bufidx, &written); | 
|  | 621 | if (error) | 
|  | 622 | break; | 
|  | 623 | ubuffer += written; | 
|  | 624 | *count += bufidx; | 
|  | 625 | bufidx = 0; | 
|  | 626 | } | 
|  | 627 | if (!--left) | 
|  | 628 | break; | 
|  | 629 |  | 
|  | 630 | error = xfs_btree_increment(cur, 0, &stat); | 
|  | 631 | if (error) | 
|  | 632 | break; | 
|  | 633 | if (stat) | 
|  | 634 | continue; | 
|  | 635 |  | 
|  | 636 | next_ag: | 
|  | 637 | xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); | 
|  | 638 | cur = NULL; | 
|  | 639 | xfs_buf_relse(agbp); | 
|  | 640 | agbp = NULL; | 
|  | 641 | agino = 0; | 
|  | 642 | agno++; | 
|  | 643 | } while (agno < mp->m_sb.sb_agcount); | 
|  | 644 |  | 
|  | 645 | if (!error) { | 
|  | 646 | if (bufidx) { | 
|  | 647 | long	written; | 
|  | 648 |  | 
|  | 649 | error = formatter(ubuffer, buffer, bufidx, &written); | 
|  | 650 | if (!error) | 
|  | 651 | *count += bufidx; | 
|  | 652 | } | 
|  | 653 | *lastino = XFS_AGINO_TO_INO(mp, agno, agino); | 
|  | 654 | } | 
|  | 655 |  | 
|  | 656 | kmem_free(buffer); | 
|  | 657 | if (cur) | 
|  | 658 | xfs_btree_del_cursor(cur, (error ? XFS_BTREE_ERROR : | 
|  | 659 | XFS_BTREE_NOERROR)); | 
|  | 660 | if (agbp) | 
|  | 661 | xfs_buf_relse(agbp); | 
|  | 662 |  | 
|  | 663 | return error; | 
|  | 664 | } |