aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_inode.c
diff options
context:
space:
mode:
authorDavid Chinner <dgc@sgi.com>2008-03-05 21:43:34 -0500
committerLachlan McIlroy <lachlan@redback.melbourne.sgi.com>2008-04-17 21:37:19 -0400
commit4ae29b4321b99b711bcfde5527c4fbf249eac60f (patch)
treea508c4574d61a9d1713e6674a5b6c6817616120b /fs/xfs/xfs_inode.c
parente9a56b7cdaf6129892fd7c8d950b71a1a4304bb0 (diff)
[XFS] Factor xfs_itobp() and xfs_inotobp().
The only difference between the functions is one passes an inode for the lookup, the other passes an inode number. However, they don't do the same validity checking or set all the same state on the buffer that is returned yet they should. Factor the functions into a common implementation. SGI-PV: 970925 SGI-Modid: xfs-linux-melb:xfs-kern:30500a Signed-off-by: David Chinner <dgc@sgi.com> Signed-off-by: Lachlan McIlroy <lachlan@sgi.com>
Diffstat (limited to 'fs/xfs/xfs_inode.c')
-rw-r--r--fs/xfs/xfs_inode.c261
1 files changed, 106 insertions, 155 deletions
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index f43a6e01d68f..6f156faf9d46 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -126,6 +126,85 @@ xfs_inobp_check(
126#endif 126#endif
127 127
128/* 128/*
129 * Find the buffer associated with the given inode map
130 * We do basic validation checks on the buffer once it has been
131 * retrieved from disk.
132 */
133STATIC int
134xfs_imap_to_bp(
135 xfs_mount_t *mp,
136 xfs_trans_t *tp,
137 xfs_imap_t *imap,
138 xfs_buf_t **bpp,
139 uint buf_flags,
140 uint imap_flags)
141{
142 int error;
143 int i;
144 int ni;
145 xfs_buf_t *bp;
146
147 error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, imap->im_blkno,
148 (int)imap->im_len, XFS_BUF_LOCK, &bp);
149 if (error) {
150 cmn_err(CE_WARN, "xfs_imap_to_bp: xfs_trans_read_buf()returned "
151 "an error %d on %s. Returning error.",
152 error, mp->m_fsname);
153 return error;
154 }
155
156 /*
157 * Validate the magic number and version of every inode in the buffer
158 * (if DEBUG kernel) or the first inode in the buffer, otherwise.
159 */
160#ifdef DEBUG
161 ni = BBTOB(imap->im_len) >> mp->m_sb.sb_inodelog;
162#else /* usual case */
163 ni = 1;
164#endif
165
166 for (i = 0; i < ni; i++) {
167 int di_ok;
168 xfs_dinode_t *dip;
169
170 dip = (xfs_dinode_t *)xfs_buf_offset(bp,
171 (i << mp->m_sb.sb_inodelog));
172 di_ok = be16_to_cpu(dip->di_core.di_magic) == XFS_DINODE_MAGIC &&
173 XFS_DINODE_GOOD_VERSION(dip->di_core.di_version);
174 if (unlikely(XFS_TEST_ERROR(!di_ok, mp,
175 XFS_ERRTAG_ITOBP_INOTOBP,
176 XFS_RANDOM_ITOBP_INOTOBP))) {
177 if (imap_flags & XFS_IMAP_BULKSTAT) {
178 xfs_trans_brelse(tp, bp);
179 return XFS_ERROR(EINVAL);
180 }
181 XFS_CORRUPTION_ERROR("xfs_imap_to_bp",
182 XFS_ERRLEVEL_HIGH, mp, dip);
183#ifdef DEBUG
184 cmn_err(CE_PANIC,
185 "Device %s - bad inode magic/vsn "
186 "daddr %lld #%d (magic=%x)",
187 XFS_BUFTARG_NAME(mp->m_ddev_targp),
188 (unsigned long long)imap->im_blkno, i,
189 be16_to_cpu(dip->di_core.di_magic));
190#endif
191 xfs_trans_brelse(tp, bp);
192 return XFS_ERROR(EFSCORRUPTED);
193 }
194 }
195
196 xfs_inobp_check(mp, bp);
197
198 /*
199 * Mark the buffer as an inode buffer now that it looks good
200 */
201 XFS_BUF_SET_VTYPE(bp, B_FS_INO);
202
203 *bpp = bp;
204 return 0;
205}
206
207/*
129 * This routine is called to map an inode number within a file 208 * This routine is called to map an inode number within a file
130 * system to the buffer containing the on-disk version of the 209 * system to the buffer containing the on-disk version of the
131 * inode. It returns a pointer to the buffer containing the 210 * inode. It returns a pointer to the buffer containing the
@@ -147,72 +226,19 @@ xfs_inotobp(
147 xfs_buf_t **bpp, 226 xfs_buf_t **bpp,
148 int *offset) 227 int *offset)
149{ 228{
150 int di_ok;
151 xfs_imap_t imap; 229 xfs_imap_t imap;
152 xfs_buf_t *bp; 230 xfs_buf_t *bp;
153 int error; 231 int error;
154 xfs_dinode_t *dip;
155 232
156 /*
157 * Call the space management code to find the location of the
158 * inode on disk.
159 */
160 imap.im_blkno = 0; 233 imap.im_blkno = 0;
161 error = xfs_imap(mp, tp, ino, &imap, XFS_IMAP_LOOKUP); 234 error = xfs_imap(mp, tp, ino, &imap, XFS_IMAP_LOOKUP);
162 if (error != 0) { 235 if (error)
163 cmn_err(CE_WARN,
164 "xfs_inotobp: xfs_imap() returned an "
165 "error %d on %s. Returning error.", error, mp->m_fsname);
166 return error; 236 return error;
167 }
168
169 /*
170 * If the inode number maps to a block outside the bounds of the
171 * file system then return NULL rather than calling read_buf
172 * and panicing when we get an error from the driver.
173 */
174 if ((imap.im_blkno + imap.im_len) >
175 XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks)) {
176 cmn_err(CE_WARN,
177 "xfs_inotobp: inode number (%llu + %d) maps to a block outside the bounds "
178 "of the file system %s. Returning EINVAL.",
179 (unsigned long long)imap.im_blkno,
180 imap.im_len, mp->m_fsname);
181 return XFS_ERROR(EINVAL);
182 }
183
184 /*
185 * Read in the buffer. If tp is NULL, xfs_trans_read_buf() will
186 * default to just a read_buf() call.
187 */
188 error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, imap.im_blkno,
189 (int)imap.im_len, XFS_BUF_LOCK, &bp);
190 237
191 if (error) { 238 error = xfs_imap_to_bp(mp, tp, &imap, &bp, XFS_BUF_LOCK, 0);
192 cmn_err(CE_WARN, 239 if (error)
193 "xfs_inotobp: xfs_trans_read_buf() returned an "
194 "error %d on %s. Returning error.", error, mp->m_fsname);
195 return error; 240 return error;
196 }
197 dip = (xfs_dinode_t *)xfs_buf_offset(bp, 0);
198 di_ok =
199 be16_to_cpu(dip->di_core.di_magic) == XFS_DINODE_MAGIC &&
200 XFS_DINODE_GOOD_VERSION(dip->di_core.di_version);
201 if (unlikely(XFS_TEST_ERROR(!di_ok, mp, XFS_ERRTAG_ITOBP_INOTOBP,
202 XFS_RANDOM_ITOBP_INOTOBP))) {
203 XFS_CORRUPTION_ERROR("xfs_inotobp", XFS_ERRLEVEL_LOW, mp, dip);
204 xfs_trans_brelse(tp, bp);
205 cmn_err(CE_WARN,
206 "xfs_inotobp: XFS_TEST_ERROR() returned an "
207 "error on %s. Returning EFSCORRUPTED.", mp->m_fsname);
208 return XFS_ERROR(EFSCORRUPTED);
209 }
210 241
211 xfs_inobp_check(mp, bp);
212
213 /*
214 * Set *dipp to point to the on-disk inode in the buffer.
215 */
216 *dipp = (xfs_dinode_t *)xfs_buf_offset(bp, imap.im_boffset); 242 *dipp = (xfs_dinode_t *)xfs_buf_offset(bp, imap.im_boffset);
217 *bpp = bp; 243 *bpp = bp;
218 *offset = imap.im_boffset; 244 *offset = imap.im_boffset;
@@ -253,41 +279,15 @@ xfs_itobp(
253 xfs_imap_t imap; 279 xfs_imap_t imap;
254 xfs_buf_t *bp; 280 xfs_buf_t *bp;
255 int error; 281 int error;
256 int i;
257 int ni;
258 282
259 if (ip->i_blkno == (xfs_daddr_t)0) { 283 if (ip->i_blkno == (xfs_daddr_t)0) {
260 /*
261 * Call the space management code to find the location of the
262 * inode on disk.
263 */
264 imap.im_blkno = bno; 284 imap.im_blkno = bno;
265 if ((error = xfs_imap(mp, tp, ip->i_ino, &imap, 285 error = xfs_imap(mp, tp, ip->i_ino, &imap,
266 XFS_IMAP_LOOKUP | imap_flags))) 286 XFS_IMAP_LOOKUP | imap_flags);
287 if (error)
267 return error; 288 return error;
268 289
269 /* 290 /*
270 * If the inode number maps to a block outside the bounds
271 * of the file system then return NULL rather than calling
272 * read_buf and panicing when we get an error from the
273 * driver.
274 */
275 if ((imap.im_blkno + imap.im_len) >
276 XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks)) {
277#ifdef DEBUG
278 xfs_fs_cmn_err(CE_ALERT, mp, "xfs_itobp: "
279 "(imap.im_blkno (0x%llx) "
280 "+ imap.im_len (0x%llx)) > "
281 " XFS_FSB_TO_BB(mp, "
282 "mp->m_sb.sb_dblocks) (0x%llx)",
283 (unsigned long long) imap.im_blkno,
284 (unsigned long long) imap.im_len,
285 XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks));
286#endif /* DEBUG */
287 return XFS_ERROR(EINVAL);
288 }
289
290 /*
291 * Fill in the fields in the inode that will be used to 291 * Fill in the fields in the inode that will be used to
292 * map the inode to its buffer from now on. 292 * map the inode to its buffer from now on.
293 */ 293 */
@@ -305,76 +305,10 @@ xfs_itobp(
305 } 305 }
306 ASSERT(bno == 0 || bno == imap.im_blkno); 306 ASSERT(bno == 0 || bno == imap.im_blkno);
307 307
308 /* 308 error = xfs_imap_to_bp(mp, tp, &imap, &bp, XFS_BUF_LOCK, imap_flags);
309 * Read in the buffer. If tp is NULL, xfs_trans_read_buf() will 309 if (error)
310 * default to just a read_buf() call.
311 */
312 error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, imap.im_blkno,
313 (int)imap.im_len, XFS_BUF_LOCK, &bp);
314 if (error) {
315#ifdef DEBUG
316 xfs_fs_cmn_err(CE_ALERT, mp, "xfs_itobp: "
317 "xfs_trans_read_buf() returned error %d, "
318 "imap.im_blkno 0x%llx, imap.im_len 0x%llx",
319 error, (unsigned long long) imap.im_blkno,
320 (unsigned long long) imap.im_len);
321#endif /* DEBUG */
322 return error; 310 return error;
323 }
324
325 /*
326 * Validate the magic number and version of every inode in the buffer
327 * (if DEBUG kernel) or the first inode in the buffer, otherwise.
328 * No validation is done here in userspace (xfs_repair).
329 */
330#if !defined(__KERNEL__)
331 ni = 0;
332#elif defined(DEBUG)
333 ni = BBTOB(imap.im_len) >> mp->m_sb.sb_inodelog;
334#else /* usual case */
335 ni = 1;
336#endif
337
338 for (i = 0; i < ni; i++) {
339 int di_ok;
340 xfs_dinode_t *dip;
341 311
342 dip = (xfs_dinode_t *)xfs_buf_offset(bp,
343 (i << mp->m_sb.sb_inodelog));
344 di_ok = be16_to_cpu(dip->di_core.di_magic) == XFS_DINODE_MAGIC &&
345 XFS_DINODE_GOOD_VERSION(dip->di_core.di_version);
346 if (unlikely(XFS_TEST_ERROR(!di_ok, mp,
347 XFS_ERRTAG_ITOBP_INOTOBP,
348 XFS_RANDOM_ITOBP_INOTOBP))) {
349 if (imap_flags & XFS_IMAP_BULKSTAT) {
350 xfs_trans_brelse(tp, bp);
351 return XFS_ERROR(EINVAL);
352 }
353#ifdef DEBUG
354 cmn_err(CE_ALERT,
355 "Device %s - bad inode magic/vsn "
356 "daddr %lld #%d (magic=%x)",
357 XFS_BUFTARG_NAME(mp->m_ddev_targp),
358 (unsigned long long)imap.im_blkno, i,
359 be16_to_cpu(dip->di_core.di_magic));
360#endif
361 XFS_CORRUPTION_ERROR("xfs_itobp", XFS_ERRLEVEL_HIGH,
362 mp, dip);
363 xfs_trans_brelse(tp, bp);
364 return XFS_ERROR(EFSCORRUPTED);
365 }
366 }
367
368 xfs_inobp_check(mp, bp);
369
370 /*
371 * Mark the buffer as an inode buffer now that it looks good
372 */
373 XFS_BUF_SET_VTYPE(bp, B_FS_INO);
374
375 /*
376 * Set *dipp to point to the on-disk inode in the buffer.
377 */
378 *dipp = (xfs_dinode_t *)xfs_buf_offset(bp, imap.im_boffset); 312 *dipp = (xfs_dinode_t *)xfs_buf_offset(bp, imap.im_boffset);
379 *bpp = bp; 313 *bpp = bp;
380 return 0; 314 return 0;
@@ -2678,14 +2612,31 @@ xfs_imap(
2678 fsbno = imap->im_blkno ? 2612 fsbno = imap->im_blkno ?
2679 XFS_DADDR_TO_FSB(mp, imap->im_blkno) : NULLFSBLOCK; 2613 XFS_DADDR_TO_FSB(mp, imap->im_blkno) : NULLFSBLOCK;
2680 error = xfs_dilocate(mp, tp, ino, &fsbno, &len, &off, flags); 2614 error = xfs_dilocate(mp, tp, ino, &fsbno, &len, &off, flags);
2681 if (error != 0) { 2615 if (error)
2682 return error; 2616 return error;
2683 } 2617
2684 imap->im_blkno = XFS_FSB_TO_DADDR(mp, fsbno); 2618 imap->im_blkno = XFS_FSB_TO_DADDR(mp, fsbno);
2685 imap->im_len = XFS_FSB_TO_BB(mp, len); 2619 imap->im_len = XFS_FSB_TO_BB(mp, len);
2686 imap->im_agblkno = XFS_FSB_TO_AGBNO(mp, fsbno); 2620 imap->im_agblkno = XFS_FSB_TO_AGBNO(mp, fsbno);
2687 imap->im_ioffset = (ushort)off; 2621 imap->im_ioffset = (ushort)off;
2688 imap->im_boffset = (ushort)(off << mp->m_sb.sb_inodelog); 2622 imap->im_boffset = (ushort)(off << mp->m_sb.sb_inodelog);
2623
2624 /*
2625 * If the inode number maps to a block outside the bounds
2626 * of the file system then return NULL rather than calling
2627 * read_buf and panicing when we get an error from the
2628 * driver.
2629 */
2630 if ((imap->im_blkno + imap->im_len) >
2631 XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks)) {
2632 xfs_fs_cmn_err(CE_ALERT, mp, "xfs_imap: "
2633 "(imap->im_blkno (0x%llx) + imap->im_len (0x%llx)) > "
2634 " XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks) (0x%llx)",
2635 (unsigned long long) imap->im_blkno,
2636 (unsigned long long) imap->im_len,
2637 XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks));
2638 return EINVAL;
2639 }
2689 return 0; 2640 return 0;
2690} 2641}
2691 2642