aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_inode.c
diff options
context:
space:
mode:
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 f43a6e01d68..6f156faf9d4 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