]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - db/inode.c
xfs_db: add a superblock info command
[thirdparty/xfsprogs-dev.git] / db / inode.c
1 /*
2 * Copyright (c) 2000-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
19 #include "libxfs.h"
20 #include "command.h"
21 #include "type.h"
22 #include "faddr.h"
23 #include "fprint.h"
24 #include "field.h"
25 #include "inode.h"
26 #include "io.h"
27 #include "print.h"
28 #include "block.h"
29 #include "bit.h"
30 #include "output.h"
31 #include "init.h"
32
33 static int inode_a_bmbt_count(void *obj, int startoff);
34 static int inode_a_bmx_count(void *obj, int startoff);
35 static int inode_a_count(void *obj, int startoff);
36 static int inode_a_offset(void *obj, int startoff, int idx);
37 static int inode_a_sfattr_count(void *obj, int startoff);
38 static int inode_core_nlinkv2_count(void *obj, int startoff);
39 static int inode_core_onlink_count(void *obj, int startoff);
40 static int inode_core_projid_count(void *obj, int startoff);
41 static int inode_core_nlinkv1_count(void *obj, int startoff);
42 static int inode_f(int argc, char **argv);
43 static int inode_u_offset(void *obj, int startoff, int idx);
44 static int inode_u_bmbt_count(void *obj, int startoff);
45 static int inode_u_bmx_count(void *obj, int startoff);
46 static int inode_u_c_count(void *obj, int startoff);
47 static int inode_u_dev_count(void *obj, int startoff);
48 static int inode_u_muuid_count(void *obj, int startoff);
49 static int inode_u_sfdir2_count(void *obj, int startoff);
50 static int inode_u_sfdir3_count(void *obj, int startoff);
51 static int inode_u_symlink_count(void *obj, int startoff);
52
53 static const cmdinfo_t inode_cmd =
54 { "inode", NULL, inode_f, 0, 1, 1, "[inode#]",
55 "set current inode", NULL };
56
57 const field_t inode_hfld[] = {
58 { "", FLDT_INODE, OI(0), C1, 0, TYP_NONE },
59 { NULL }
60 };
61 const field_t inode_crc_hfld[] = {
62 { "", FLDT_INODE_CRC, OI(0), C1, 0, TYP_NONE },
63 { NULL }
64 };
65
66 /* XXX: fix this up! */
67 #define OFF(f) bitize(offsetof(xfs_dinode_t, di_ ## f))
68 const field_t inode_flds[] = {
69 { "core", FLDT_DINODE_CORE, OI(OFF(magic)), C1, 0, TYP_NONE },
70 { "next_unlinked", FLDT_AGINO, OI(OFF(next_unlinked)), C1, 0,
71 TYP_INODE },
72 { "u", FLDT_DINODE_U, inode_u_offset, C1, FLD_OFFSET, TYP_NONE },
73 { "a", FLDT_DINODE_A, inode_a_offset, inode_a_count,
74 FLD_COUNT|FLD_OFFSET, TYP_NONE },
75 { NULL }
76 };
77 const field_t inode_crc_flds[] = {
78 { "core", FLDT_DINODE_CORE, OI(OFF(magic)), C1, 0, TYP_NONE },
79 { "next_unlinked", FLDT_AGINO, OI(OFF(next_unlinked)), C1, 0,
80 TYP_INODE },
81 { "v3", FLDT_DINODE_V3, OI(OFF(magic)), C1, 0, TYP_NONE },
82 { "u3", FLDT_DINODE_U, inode_u_offset, C1, FLD_OFFSET, TYP_NONE },
83 { "a", FLDT_DINODE_A, inode_a_offset, inode_a_count,
84 FLD_COUNT|FLD_OFFSET, TYP_NONE },
85 { NULL }
86 };
87
88
89 #define COFF(f) bitize(offsetof(xfs_dinode_t, di_ ## f))
90 const field_t inode_core_flds[] = {
91 { "magic", FLDT_UINT16X, OI(COFF(magic)), C1, 0, TYP_NONE },
92 { "mode", FLDT_UINT16O, OI(COFF(mode)), C1, 0, TYP_NONE },
93 { "version", FLDT_INT8D, OI(COFF(version)), C1, 0, TYP_NONE },
94 { "format", FLDT_DINODE_FMT, OI(COFF(format)), C1, 0, TYP_NONE },
95 { "nlinkv1", FLDT_UINT16D, OI(COFF(onlink)), inode_core_nlinkv1_count,
96 FLD_COUNT, TYP_NONE },
97 { "nlinkv2", FLDT_UINT32D, OI(COFF(nlink)), inode_core_nlinkv2_count,
98 FLD_COUNT, TYP_NONE },
99 { "onlink", FLDT_UINT16D, OI(COFF(onlink)), inode_core_onlink_count,
100 FLD_COUNT, TYP_NONE },
101 { "projid_lo", FLDT_UINT16D, OI(COFF(projid_lo)),
102 inode_core_projid_count, FLD_COUNT, TYP_NONE },
103 { "projid_hi", FLDT_UINT16D, OI(COFF(projid_hi)),
104 inode_core_projid_count, FLD_COUNT, TYP_NONE },
105 { "pad", FLDT_UINT8X, OI(OFF(pad)), CI(6), FLD_ARRAY|FLD_SKIPALL, TYP_NONE },
106 { "uid", FLDT_UINT32D, OI(COFF(uid)), C1, 0, TYP_NONE },
107 { "gid", FLDT_UINT32D, OI(COFF(gid)), C1, 0, TYP_NONE },
108 { "flushiter", FLDT_UINT16D, OI(COFF(flushiter)), C1, 0, TYP_NONE },
109 { "atime", FLDT_TIMESTAMP, OI(COFF(atime)), C1, 0, TYP_NONE },
110 { "mtime", FLDT_TIMESTAMP, OI(COFF(mtime)), C1, 0, TYP_NONE },
111 { "ctime", FLDT_TIMESTAMP, OI(COFF(ctime)), C1, 0, TYP_NONE },
112 { "size", FLDT_FSIZE, OI(COFF(size)), C1, 0, TYP_NONE },
113 { "nblocks", FLDT_DRFSBNO, OI(COFF(nblocks)), C1, 0, TYP_NONE },
114 { "extsize", FLDT_EXTLEN, OI(COFF(extsize)), C1, 0, TYP_NONE },
115 { "nextents", FLDT_EXTNUM, OI(COFF(nextents)), C1, 0, TYP_NONE },
116 { "naextents", FLDT_AEXTNUM, OI(COFF(anextents)), C1, 0, TYP_NONE },
117 { "forkoff", FLDT_UINT8D, OI(COFF(forkoff)), C1, 0, TYP_NONE },
118 { "aformat", FLDT_DINODE_FMT, OI(COFF(aformat)), C1, 0, TYP_NONE },
119 { "dmevmask", FLDT_UINT32X, OI(COFF(dmevmask)), C1, 0, TYP_NONE },
120 { "dmstate", FLDT_UINT16D, OI(COFF(dmstate)), C1, 0, TYP_NONE },
121 { "flags", FLDT_UINT16X, OI(COFF(flags)), C1, FLD_SKIPALL, TYP_NONE },
122 { "newrtbm", FLDT_UINT1,
123 OI(COFF(flags) + bitsz(uint16_t) - XFS_DIFLAG_NEWRTBM_BIT - 1), C1,
124 0, TYP_NONE },
125 { "prealloc", FLDT_UINT1,
126 OI(COFF(flags) + bitsz(uint16_t) - XFS_DIFLAG_PREALLOC_BIT - 1), C1,
127 0, TYP_NONE },
128 { "realtime", FLDT_UINT1,
129 OI(COFF(flags) + bitsz(uint16_t) - XFS_DIFLAG_REALTIME_BIT - 1), C1,
130 0, TYP_NONE },
131 { "immutable", FLDT_UINT1,
132 OI(COFF(flags) + bitsz(uint16_t) - XFS_DIFLAG_IMMUTABLE_BIT-1), C1,
133 0, TYP_NONE },
134 { "append", FLDT_UINT1,
135 OI(COFF(flags) + bitsz(uint16_t) - XFS_DIFLAG_APPEND_BIT - 1), C1,
136 0, TYP_NONE },
137 { "sync", FLDT_UINT1,
138 OI(COFF(flags) + bitsz(uint16_t) - XFS_DIFLAG_SYNC_BIT - 1), C1,
139 0, TYP_NONE },
140 { "noatime", FLDT_UINT1,
141 OI(COFF(flags) + bitsz(uint16_t) - XFS_DIFLAG_NOATIME_BIT - 1), C1,
142 0, TYP_NONE },
143 { "nodump", FLDT_UINT1,
144 OI(COFF(flags) + bitsz(uint16_t) - XFS_DIFLAG_NODUMP_BIT - 1), C1,
145 0, TYP_NONE },
146 { "rtinherit", FLDT_UINT1,
147 OI(COFF(flags) + bitsz(uint16_t) - XFS_DIFLAG_RTINHERIT_BIT-1), C1,
148 0, TYP_NONE },
149 { "projinherit", FLDT_UINT1,
150 OI(COFF(flags) + bitsz(uint16_t) - XFS_DIFLAG_PROJINHERIT_BIT-1), C1,
151 0, TYP_NONE },
152 { "nosymlinks", FLDT_UINT1,
153 OI(COFF(flags) + bitsz(uint16_t) - XFS_DIFLAG_NOSYMLINKS_BIT-1), C1,
154 0, TYP_NONE },
155 { "extsz", FLDT_UINT1,
156 OI(COFF(flags) + bitsz(uint16_t) - XFS_DIFLAG_EXTSIZE_BIT-1), C1,
157 0, TYP_NONE },
158 { "extszinherit", FLDT_UINT1,
159 OI(COFF(flags) + bitsz(uint16_t) - XFS_DIFLAG_EXTSZINHERIT_BIT-1), C1,
160 0, TYP_NONE },
161 { "nodefrag", FLDT_UINT1,
162 OI(COFF(flags) + bitsz(uint16_t) - XFS_DIFLAG_NODEFRAG_BIT-1), C1,
163 0, TYP_NONE },
164 { "filestream", FLDT_UINT1,
165 OI(COFF(flags) + bitsz(uint16_t) - XFS_DIFLAG_FILESTREAM_BIT-1), C1,
166 0, TYP_NONE },
167 { "gen", FLDT_UINT32D, OI(COFF(gen)), C1, 0, TYP_NONE },
168 { NULL }
169 };
170
171 const field_t inode_v3_flds[] = {
172 { "crc", FLDT_CRC, OI(COFF(crc)), C1, 0, TYP_NONE },
173 { "change_count", FLDT_UINT64D, OI(COFF(changecount)), C1, 0, TYP_NONE },
174 { "lsn", FLDT_UINT64X, OI(COFF(lsn)), C1, 0, TYP_NONE },
175 { "flags2", FLDT_UINT64X, OI(COFF(flags2)), C1, 0, TYP_NONE },
176 { "cowextsize", FLDT_EXTLEN, OI(COFF(cowextsize)), C1, 0, TYP_NONE },
177 { "pad2", FLDT_UINT8X, OI(OFF(pad2)), CI(12), FLD_ARRAY|FLD_SKIPALL, TYP_NONE },
178 { "crtime", FLDT_TIMESTAMP, OI(COFF(crtime)), C1, 0, TYP_NONE },
179 { "inumber", FLDT_INO, OI(COFF(ino)), C1, 0, TYP_NONE },
180 { "uuid", FLDT_UUID, OI(COFF(uuid)), C1, 0, TYP_NONE },
181 { "reflink", FLDT_UINT1,
182 OI(COFF(flags2) + bitsz(uint64_t) - XFS_DIFLAG2_REFLINK_BIT-1), C1,
183 0, TYP_NONE },
184 { "cowextsz", FLDT_UINT1,
185 OI(COFF(flags2) + bitsz(uint64_t) - XFS_DIFLAG2_COWEXTSIZE_BIT-1), C1,
186 0, TYP_NONE },
187 { NULL }
188 };
189
190
191 #define TOFF(f) bitize(offsetof(xfs_timestamp_t, t_ ## f))
192 const field_t timestamp_flds[] = {
193 { "sec", FLDT_TIME, OI(TOFF(sec)), C1, 0, TYP_NONE },
194 { "nsec", FLDT_NSEC, OI(TOFF(nsec)), C1, 0, TYP_NONE },
195 { NULL }
196 };
197
198 const field_t inode_u_flds[] = {
199 { "bmbt", FLDT_BMROOTD, NULL, inode_u_bmbt_count, FLD_COUNT, TYP_NONE },
200 { "bmx", FLDT_BMAPBTDREC, NULL, inode_u_bmx_count, FLD_ARRAY|FLD_COUNT,
201 TYP_NONE },
202 { "c", FLDT_CHARNS, NULL, inode_u_c_count, FLD_COUNT, TYP_NONE },
203 { "dev", FLDT_DEV, NULL, inode_u_dev_count, FLD_COUNT, TYP_NONE },
204 { "muuid", FLDT_UUID, NULL, inode_u_muuid_count, FLD_COUNT, TYP_NONE },
205 { "sfdir2", FLDT_DIR2SF, NULL, inode_u_sfdir2_count, FLD_COUNT, TYP_NONE },
206 { "sfdir3", FLDT_DIR3SF, NULL, inode_u_sfdir3_count, FLD_COUNT, TYP_NONE },
207 { "symlink", FLDT_CHARNS, NULL, inode_u_symlink_count, FLD_COUNT,
208 TYP_NONE },
209 { NULL }
210 };
211
212 const field_t inode_a_flds[] = {
213 { "bmbt", FLDT_BMROOTA, NULL, inode_a_bmbt_count, FLD_COUNT, TYP_NONE },
214 { "bmx", FLDT_BMAPBTAREC, NULL, inode_a_bmx_count, FLD_ARRAY|FLD_COUNT,
215 TYP_NONE },
216 { "sfattr", FLDT_ATTRSHORT, NULL, inode_a_sfattr_count, FLD_COUNT,
217 TYP_NONE },
218 { NULL }
219 };
220
221 static const char *dinode_fmt_name[] =
222 { "dev", "local", "extents", "btree", "uuid" };
223 static const int dinode_fmt_name_size =
224 sizeof(dinode_fmt_name) / sizeof(dinode_fmt_name[0]);
225
226 /*ARGSUSED*/
227 int
228 fp_dinode_fmt(
229 void *obj,
230 int bit,
231 int count,
232 char *fmtstr,
233 int size,
234 int arg,
235 int base,
236 int array)
237 {
238 int bitpos;
239 xfs_dinode_fmt_t f;
240 int i;
241
242 for (i = 0, bitpos = bit; i < count; i++, bitpos += size) {
243 f = (xfs_dinode_fmt_t)getbitval(obj, bitpos, size, BVUNSIGNED);
244 if (array)
245 dbprintf("%d:", i + base);
246 if (f < 0 || f >= dinode_fmt_name_size)
247 dbprintf("%d", (int)f);
248 else
249 dbprintf("%d (%s)", (int)f, dinode_fmt_name[(int)f]);
250 if (i < count - 1)
251 dbprintf(" ");
252 }
253 return 1;
254 }
255
256 static int
257 inode_a_bmbt_count(
258 void *obj,
259 int startoff)
260 {
261 xfs_dinode_t *dip;
262
263 ASSERT(bitoffs(startoff) == 0);
264 ASSERT(obj == iocur_top->data);
265 dip = obj;
266 if (!XFS_DFORK_Q(dip))
267 return 0;
268 ASSERT((char *)XFS_DFORK_APTR(dip) - (char *)dip == byteize(startoff));
269 return dip->di_aformat == XFS_DINODE_FMT_BTREE;
270 }
271
272 static int
273 inode_a_bmx_count(
274 void *obj,
275 int startoff)
276 {
277 xfs_dinode_t *dip;
278
279 ASSERT(bitoffs(startoff) == 0);
280 ASSERT(obj == iocur_top->data);
281 dip = obj;
282 if (!XFS_DFORK_Q(dip))
283 return 0;
284 ASSERT((char *)XFS_DFORK_APTR(dip) - (char *)dip == byteize(startoff));
285 return dip->di_aformat == XFS_DINODE_FMT_EXTENTS ?
286 be16_to_cpu(dip->di_anextents) : 0;
287 }
288
289 static int
290 inode_a_count(
291 void *obj,
292 int startoff)
293 {
294 xfs_dinode_t *dip;
295
296 ASSERT(startoff == 0);
297 dip = obj;
298 return XFS_DFORK_Q(dip);
299 }
300
301 static int
302 inode_a_offset(
303 void *obj,
304 int startoff,
305 int idx)
306 {
307 xfs_dinode_t *dip;
308
309 ASSERT(startoff == 0);
310 ASSERT(idx == 0);
311 dip = obj;
312 ASSERT(XFS_DFORK_Q(dip));
313 return bitize((int)((char *)XFS_DFORK_APTR(dip) - (char *)dip));
314 }
315
316 static int
317 inode_a_sfattr_count(
318 void *obj,
319 int startoff)
320 {
321 xfs_dinode_t *dip;
322
323 ASSERT(bitoffs(startoff) == 0);
324 ASSERT(obj == iocur_top->data);
325 dip = obj;
326 if (!XFS_DFORK_Q(dip))
327 return 0;
328 ASSERT((char *)XFS_DFORK_APTR(dip) - (char *)dip == byteize(startoff));
329 return dip->di_aformat == XFS_DINODE_FMT_LOCAL;
330 }
331
332 int
333 inode_a_size(
334 void *obj,
335 int startoff,
336 int idx)
337 {
338 xfs_attr_shortform_t *asf;
339 xfs_dinode_t *dip;
340
341 ASSERT(startoff == 0);
342 ASSERT(idx == 0);
343 dip = obj;
344 switch (dip->di_aformat) {
345 case XFS_DINODE_FMT_LOCAL:
346 asf = (xfs_attr_shortform_t *)XFS_DFORK_APTR(dip);
347 return bitize(be16_to_cpu(asf->hdr.totsize));
348 case XFS_DINODE_FMT_EXTENTS:
349 return (int)be16_to_cpu(dip->di_anextents) *
350 bitsz(xfs_bmbt_rec_t);
351 case XFS_DINODE_FMT_BTREE:
352 return bitize((int)XFS_DFORK_ASIZE(dip, mp));
353 default:
354 return 0;
355 }
356 }
357
358 static int
359 inode_core_nlinkv1_count(
360 void *obj,
361 int startoff)
362 {
363 xfs_dinode_t *dic;
364
365 ASSERT(startoff == 0);
366 ASSERT(obj == iocur_top->data);
367 dic = obj;
368 return dic->di_version == 1;
369 }
370
371 static int
372 inode_core_nlinkv2_count(
373 void *obj,
374 int startoff)
375 {
376 xfs_dinode_t *dic;
377
378 ASSERT(startoff == 0);
379 ASSERT(obj == iocur_top->data);
380 dic = obj;
381 return dic->di_version >= 2;
382 }
383
384 static int
385 inode_core_onlink_count(
386 void *obj,
387 int startoff)
388 {
389 xfs_dinode_t *dic;
390
391 ASSERT(startoff == 0);
392 ASSERT(obj == iocur_top->data);
393 dic = obj;
394 return dic->di_version >= 2;
395 }
396
397 static int
398 inode_core_projid_count(
399 void *obj,
400 int startoff)
401 {
402 xfs_dinode_t *dic;
403
404 ASSERT(startoff == 0);
405 ASSERT(obj == iocur_top->data);
406 dic = obj;
407 return dic->di_version >= 2;
408 }
409
410 static int
411 inode_f(
412 int argc,
413 char **argv)
414 {
415 xfs_ino_t ino;
416 char *p;
417
418 if (argc > 1) {
419 ino = strtoull(argv[1], &p, 0);
420 if (*p != '\0') {
421 dbprintf(_("bad value for inode number %s\n"), argv[1]);
422 return 0;
423 }
424 set_cur_inode(ino);
425 } else if (iocur_top->ino == NULLFSINO)
426 dbprintf(_("no current inode\n"));
427 else
428 dbprintf(_("current inode number is %lld\n"), iocur_top->ino);
429 return 0;
430 }
431
432 void
433 inode_init(void)
434 {
435 add_command(&inode_cmd);
436 }
437
438 typnm_t
439 inode_next_type(void)
440 {
441 switch (iocur_top->mode & S_IFMT) {
442 case S_IFDIR:
443 return TYP_DIR2;
444 case S_IFLNK:
445 return TYP_SYMLINK;
446 case S_IFREG:
447 if (iocur_top->ino == mp->m_sb.sb_rbmino)
448 return TYP_RTBITMAP;
449 else if (iocur_top->ino == mp->m_sb.sb_rsumino)
450 return TYP_RTSUMMARY;
451 else if (iocur_top->ino == mp->m_sb.sb_uquotino ||
452 iocur_top->ino == mp->m_sb.sb_gquotino ||
453 iocur_top->ino == mp->m_sb.sb_pquotino)
454 return TYP_DQBLK;
455 else
456 return TYP_DATA;
457 default:
458 return TYP_NONE;
459 }
460 }
461
462 int
463 inode_size(
464 void *obj,
465 int startoff,
466 int idx)
467 {
468 return bitize(mp->m_sb.sb_inodesize);
469 }
470
471 static int
472 inode_u_offset(
473 void *obj,
474 int startoff,
475 int idx)
476 {
477 xfs_dinode_t *dip;
478
479 ASSERT(startoff == 0);
480 ASSERT(idx == 0);
481 dip = obj;
482 return bitize((int)((char *)XFS_DFORK_DPTR(dip) - (char *)dip));
483 }
484
485 static int
486 inode_u_bmbt_count(
487 void *obj,
488 int startoff)
489 {
490 xfs_dinode_t *dip;
491
492 ASSERT(bitoffs(startoff) == 0);
493 ASSERT(obj == iocur_top->data);
494 dip = obj;
495 ASSERT((char *)XFS_DFORK_DPTR(dip) - (char *)dip == byteize(startoff));
496 return dip->di_format == XFS_DINODE_FMT_BTREE;
497 }
498
499 static int
500 inode_u_bmx_count(
501 void *obj,
502 int startoff)
503 {
504 xfs_dinode_t *dip;
505
506 ASSERT(bitoffs(startoff) == 0);
507 ASSERT(obj == iocur_top->data);
508 dip = obj;
509 ASSERT((char *)XFS_DFORK_DPTR(dip) - (char *)dip == byteize(startoff));
510 return dip->di_format == XFS_DINODE_FMT_EXTENTS ?
511 be32_to_cpu(dip->di_nextents) : 0;
512 }
513
514 static int
515 inode_u_c_count(
516 void *obj,
517 int startoff)
518 {
519 xfs_dinode_t *dip;
520
521 ASSERT(bitoffs(startoff) == 0);
522 ASSERT(obj == iocur_top->data);
523 dip = obj;
524 ASSERT((char *)XFS_DFORK_DPTR(dip) - (char *)dip == byteize(startoff));
525 return dip->di_format == XFS_DINODE_FMT_LOCAL &&
526 (be16_to_cpu(dip->di_mode) & S_IFMT) == S_IFREG ?
527 (int)be64_to_cpu(dip->di_size) : 0;
528 }
529
530 static int
531 inode_u_dev_count(
532 void *obj,
533 int startoff)
534 {
535 xfs_dinode_t *dip;
536
537 ASSERT(bitoffs(startoff) == 0);
538 ASSERT(obj == iocur_top->data);
539 dip = obj;
540 ASSERT((char *)XFS_DFORK_DPTR(dip) - (char *)dip == byteize(startoff));
541 return dip->di_format == XFS_DINODE_FMT_DEV;
542 }
543
544 static int
545 inode_u_muuid_count(
546 void *obj,
547 int startoff)
548 {
549 xfs_dinode_t *dip;
550
551 ASSERT(bitoffs(startoff) == 0);
552 ASSERT(obj == iocur_top->data);
553 dip = obj;
554 ASSERT((char *)XFS_DFORK_DPTR(dip) - (char *)dip == byteize(startoff));
555 return dip->di_format == XFS_DINODE_FMT_UUID;
556 }
557
558 static int
559 inode_u_sfdir2_count(
560 void *obj,
561 int startoff)
562 {
563 xfs_dinode_t *dip;
564
565 ASSERT(bitoffs(startoff) == 0);
566 ASSERT(obj == iocur_top->data);
567 dip = obj;
568 ASSERT((char *)XFS_DFORK_DPTR(dip) - (char *)dip == byteize(startoff));
569 return dip->di_format == XFS_DINODE_FMT_LOCAL &&
570 (be16_to_cpu(dip->di_mode) & S_IFMT) == S_IFDIR &&
571 !xfs_sb_version_hasftype(&mp->m_sb);
572 }
573
574 static int
575 inode_u_sfdir3_count(
576 void *obj,
577 int startoff)
578 {
579 xfs_dinode_t *dip;
580
581 ASSERT(bitoffs(startoff) == 0);
582 ASSERT(obj == iocur_top->data);
583 dip = obj;
584 ASSERT((char *)XFS_DFORK_DPTR(dip) - (char *)dip == byteize(startoff));
585 return dip->di_format == XFS_DINODE_FMT_LOCAL &&
586 (be16_to_cpu(dip->di_mode) & S_IFMT) == S_IFDIR &&
587 xfs_sb_version_hasftype(&mp->m_sb);
588 }
589
590 int
591 inode_u_size(
592 void *obj,
593 int startoff,
594 int idx)
595 {
596 xfs_dinode_t *dip;
597
598 ASSERT(startoff == 0);
599 ASSERT(idx == 0);
600 dip = obj;
601 switch (dip->di_format) {
602 case XFS_DINODE_FMT_DEV:
603 return bitsz(xfs_dev_t);
604 case XFS_DINODE_FMT_LOCAL:
605 return bitize((int)be64_to_cpu(dip->di_size));
606 case XFS_DINODE_FMT_EXTENTS:
607 return (int)be32_to_cpu(dip->di_nextents) *
608 bitsz(xfs_bmbt_rec_t);
609 case XFS_DINODE_FMT_BTREE:
610 return bitize((int)XFS_DFORK_DSIZE(dip, mp));
611 case XFS_DINODE_FMT_UUID:
612 return bitsz(uuid_t);
613 default:
614 return 0;
615 }
616 }
617
618 static int
619 inode_u_symlink_count(
620 void *obj,
621 int startoff)
622 {
623 xfs_dinode_t *dip;
624
625 ASSERT(bitoffs(startoff) == 0);
626 ASSERT(obj == iocur_top->data);
627 dip = obj;
628 ASSERT((char *)XFS_DFORK_DPTR(dip) - (char *)dip == byteize(startoff));
629 return dip->di_format == XFS_DINODE_FMT_LOCAL &&
630 (be16_to_cpu(dip->di_mode) & S_IFMT) == S_IFLNK ?
631 (int)be64_to_cpu(dip->di_size) : 0;
632 }
633
634 /*
635 * We are now using libxfs for our IO backend, so we should always try to use
636 * inode cluster buffers rather than filesystem block sized buffers for reading
637 * inodes. This means that we always use the same buffers as libxfs operations
638 * does, and that avoids buffer cache issues caused by overlapping buffers. This
639 * can be seen clearly when trying to read the root inode. Much of this logic is
640 * similar to libxfs_imap().
641 */
642 void
643 set_cur_inode(
644 xfs_ino_t ino)
645 {
646 xfs_agblock_t agbno;
647 xfs_agino_t agino;
648 xfs_agnumber_t agno;
649 xfs_dinode_t *dip;
650 int offset;
651 int numblks = blkbb;
652 xfs_agblock_t cluster_agbno;
653
654
655 agno = XFS_INO_TO_AGNO(mp, ino);
656 agino = XFS_INO_TO_AGINO(mp, ino);
657 agbno = XFS_AGINO_TO_AGBNO(mp, agino);
658 offset = XFS_AGINO_TO_OFFSET(mp, agino);
659 if (agno >= mp->m_sb.sb_agcount || agbno >= mp->m_sb.sb_agblocks ||
660 offset >= mp->m_sb.sb_inopblock ||
661 XFS_AGINO_TO_INO(mp, agno, agino) != ino) {
662 dbprintf(_("bad inode number %lld\n"), ino);
663 return;
664 }
665 cur_agno = agno;
666
667 if (mp->m_inode_cluster_size > mp->m_sb.sb_blocksize &&
668 mp->m_inoalign_mask) {
669 xfs_agblock_t chunk_agbno;
670 xfs_agblock_t offset_agbno;
671 int blks_per_cluster;
672
673 blks_per_cluster = mp->m_inode_cluster_size >>
674 mp->m_sb.sb_blocklog;
675 offset_agbno = agbno & mp->m_inoalign_mask;
676 chunk_agbno = agbno - offset_agbno;
677 cluster_agbno = chunk_agbno +
678 ((offset_agbno / blks_per_cluster) * blks_per_cluster);
679 offset += ((agbno - cluster_agbno) * mp->m_sb.sb_inopblock);
680 numblks = XFS_FSB_TO_BB(mp, blks_per_cluster);
681 } else
682 cluster_agbno = agbno;
683
684 /*
685 * First set_cur to the block with the inode
686 * then use off_cur to get the right part of the buffer.
687 */
688 ASSERT(typtab[TYP_INODE].typnm == TYP_INODE);
689
690 /* ingore ring update here, do it explicitly below */
691 set_cur(&typtab[TYP_INODE], XFS_AGB_TO_DADDR(mp, agno, cluster_agbno),
692 numblks, DB_RING_IGN, NULL);
693 off_cur(offset << mp->m_sb.sb_inodelog, mp->m_sb.sb_inodesize);
694 if (!iocur_top->data)
695 return;
696 dip = iocur_top->data;
697 iocur_top->ino_buf = 1;
698 iocur_top->ino = ino;
699 iocur_top->mode = be16_to_cpu(dip->di_mode);
700 if ((iocur_top->mode & S_IFMT) == S_IFDIR)
701 iocur_top->dirino = ino;
702
703 if (xfs_sb_version_hascrc(&mp->m_sb)) {
704 iocur_top->ino_crc_ok = libxfs_verify_cksum((char *)dip,
705 mp->m_sb.sb_inodesize,
706 XFS_DINODE_CRC_OFF);
707 if (!iocur_top->ino_crc_ok)
708 dbprintf(
709 _("Metadata CRC error detected for ino %lld\n"),
710 ino);
711 }
712
713 /* track updated info in ring */
714 ring_add();
715 }
716
717 void
718 xfs_inode_set_crc(
719 struct xfs_buf *bp)
720 {
721 ASSERT(iocur_top->ino_buf);
722 ASSERT(iocur_top->bp == bp);
723
724 libxfs_dinode_calc_crc(mp, iocur_top->data);
725 iocur_top->ino_crc_ok = 1;
726 }