diff options
Diffstat (limited to 'fs/xfs/xfs_ialloc.c')
-rw-r--r-- | fs/xfs/xfs_ialloc.c | 449 |
1 files changed, 272 insertions, 177 deletions
diff --git a/fs/xfs/xfs_ialloc.c b/fs/xfs/xfs_ialloc.c index aad8c5da38af..e6ebbaeb4dc6 100644 --- a/fs/xfs/xfs_ialloc.c +++ b/fs/xfs/xfs_ialloc.c | |||
@@ -41,68 +41,6 @@ | |||
41 | #include "xfs_error.h" | 41 | #include "xfs_error.h" |
42 | #include "xfs_bmap.h" | 42 | #include "xfs_bmap.h" |
43 | 43 | ||
44 | /* | ||
45 | * Log specified fields for the inode given by bp and off. | ||
46 | */ | ||
47 | STATIC void | ||
48 | xfs_ialloc_log_di( | ||
49 | xfs_trans_t *tp, /* transaction pointer */ | ||
50 | xfs_buf_t *bp, /* inode buffer */ | ||
51 | int off, /* index of inode in buffer */ | ||
52 | int fields) /* bitmask of fields to log */ | ||
53 | { | ||
54 | int first; /* first byte number */ | ||
55 | int ioffset; /* off in bytes */ | ||
56 | int last; /* last byte number */ | ||
57 | xfs_mount_t *mp; /* mount point structure */ | ||
58 | static const short offsets[] = { /* field offsets */ | ||
59 | /* keep in sync with bits */ | ||
60 | offsetof(xfs_dinode_core_t, di_magic), | ||
61 | offsetof(xfs_dinode_core_t, di_mode), | ||
62 | offsetof(xfs_dinode_core_t, di_version), | ||
63 | offsetof(xfs_dinode_core_t, di_format), | ||
64 | offsetof(xfs_dinode_core_t, di_onlink), | ||
65 | offsetof(xfs_dinode_core_t, di_uid), | ||
66 | offsetof(xfs_dinode_core_t, di_gid), | ||
67 | offsetof(xfs_dinode_core_t, di_nlink), | ||
68 | offsetof(xfs_dinode_core_t, di_projid), | ||
69 | offsetof(xfs_dinode_core_t, di_pad), | ||
70 | offsetof(xfs_dinode_core_t, di_atime), | ||
71 | offsetof(xfs_dinode_core_t, di_mtime), | ||
72 | offsetof(xfs_dinode_core_t, di_ctime), | ||
73 | offsetof(xfs_dinode_core_t, di_size), | ||
74 | offsetof(xfs_dinode_core_t, di_nblocks), | ||
75 | offsetof(xfs_dinode_core_t, di_extsize), | ||
76 | offsetof(xfs_dinode_core_t, di_nextents), | ||
77 | offsetof(xfs_dinode_core_t, di_anextents), | ||
78 | offsetof(xfs_dinode_core_t, di_forkoff), | ||
79 | offsetof(xfs_dinode_core_t, di_aformat), | ||
80 | offsetof(xfs_dinode_core_t, di_dmevmask), | ||
81 | offsetof(xfs_dinode_core_t, di_dmstate), | ||
82 | offsetof(xfs_dinode_core_t, di_flags), | ||
83 | offsetof(xfs_dinode_core_t, di_gen), | ||
84 | offsetof(xfs_dinode_t, di_next_unlinked), | ||
85 | offsetof(xfs_dinode_t, di_u), | ||
86 | offsetof(xfs_dinode_t, di_a), | ||
87 | sizeof(xfs_dinode_t) | ||
88 | }; | ||
89 | |||
90 | |||
91 | ASSERT(offsetof(xfs_dinode_t, di_core) == 0); | ||
92 | ASSERT((fields & (XFS_DI_U|XFS_DI_A)) == 0); | ||
93 | mp = tp->t_mountp; | ||
94 | /* | ||
95 | * Get the inode-relative first and last bytes for these fields | ||
96 | */ | ||
97 | xfs_btree_offsets(fields, offsets, XFS_DI_NUM_BITS, &first, &last); | ||
98 | /* | ||
99 | * Convert to buffer offsets and log it. | ||
100 | */ | ||
101 | ioffset = off << mp->m_sb.sb_inodelog; | ||
102 | first += ioffset; | ||
103 | last += ioffset; | ||
104 | xfs_trans_log_buf(tp, bp, first, last); | ||
105 | } | ||
106 | 44 | ||
107 | /* | 45 | /* |
108 | * Allocation group level functions. | 46 | * Allocation group level functions. |
@@ -119,6 +57,102 @@ xfs_ialloc_cluster_alignment( | |||
119 | } | 57 | } |
120 | 58 | ||
121 | /* | 59 | /* |
60 | * Lookup the record equal to ino in the btree given by cur. | ||
61 | */ | ||
62 | STATIC int /* error */ | ||
63 | xfs_inobt_lookup_eq( | ||
64 | struct xfs_btree_cur *cur, /* btree cursor */ | ||
65 | xfs_agino_t ino, /* starting inode of chunk */ | ||
66 | __int32_t fcnt, /* free inode count */ | ||
67 | xfs_inofree_t free, /* free inode mask */ | ||
68 | int *stat) /* success/failure */ | ||
69 | { | ||
70 | cur->bc_rec.i.ir_startino = ino; | ||
71 | cur->bc_rec.i.ir_freecount = fcnt; | ||
72 | cur->bc_rec.i.ir_free = free; | ||
73 | return xfs_btree_lookup(cur, XFS_LOOKUP_EQ, stat); | ||
74 | } | ||
75 | |||
76 | /* | ||
77 | * Lookup the first record greater than or equal to ino | ||
78 | * in the btree given by cur. | ||
79 | */ | ||
80 | int /* error */ | ||
81 | xfs_inobt_lookup_ge( | ||
82 | struct xfs_btree_cur *cur, /* btree cursor */ | ||
83 | xfs_agino_t ino, /* starting inode of chunk */ | ||
84 | __int32_t fcnt, /* free inode count */ | ||
85 | xfs_inofree_t free, /* free inode mask */ | ||
86 | int *stat) /* success/failure */ | ||
87 | { | ||
88 | cur->bc_rec.i.ir_startino = ino; | ||
89 | cur->bc_rec.i.ir_freecount = fcnt; | ||
90 | cur->bc_rec.i.ir_free = free; | ||
91 | return xfs_btree_lookup(cur, XFS_LOOKUP_GE, stat); | ||
92 | } | ||
93 | |||
94 | /* | ||
95 | * Lookup the first record less than or equal to ino | ||
96 | * in the btree given by cur. | ||
97 | */ | ||
98 | int /* error */ | ||
99 | xfs_inobt_lookup_le( | ||
100 | struct xfs_btree_cur *cur, /* btree cursor */ | ||
101 | xfs_agino_t ino, /* starting inode of chunk */ | ||
102 | __int32_t fcnt, /* free inode count */ | ||
103 | xfs_inofree_t free, /* free inode mask */ | ||
104 | int *stat) /* success/failure */ | ||
105 | { | ||
106 | cur->bc_rec.i.ir_startino = ino; | ||
107 | cur->bc_rec.i.ir_freecount = fcnt; | ||
108 | cur->bc_rec.i.ir_free = free; | ||
109 | return xfs_btree_lookup(cur, XFS_LOOKUP_LE, stat); | ||
110 | } | ||
111 | |||
112 | /* | ||
113 | * Update the record referred to by cur to the value given | ||
114 | * by [ino, fcnt, free]. | ||
115 | * This either works (return 0) or gets an EFSCORRUPTED error. | ||
116 | */ | ||
117 | STATIC int /* error */ | ||
118 | xfs_inobt_update( | ||
119 | struct xfs_btree_cur *cur, /* btree cursor */ | ||
120 | xfs_agino_t ino, /* starting inode of chunk */ | ||
121 | __int32_t fcnt, /* free inode count */ | ||
122 | xfs_inofree_t free) /* free inode mask */ | ||
123 | { | ||
124 | union xfs_btree_rec rec; | ||
125 | |||
126 | rec.inobt.ir_startino = cpu_to_be32(ino); | ||
127 | rec.inobt.ir_freecount = cpu_to_be32(fcnt); | ||
128 | rec.inobt.ir_free = cpu_to_be64(free); | ||
129 | return xfs_btree_update(cur, &rec); | ||
130 | } | ||
131 | |||
132 | /* | ||
133 | * Get the data from the pointed-to record. | ||
134 | */ | ||
135 | int /* error */ | ||
136 | xfs_inobt_get_rec( | ||
137 | struct xfs_btree_cur *cur, /* btree cursor */ | ||
138 | xfs_agino_t *ino, /* output: starting inode of chunk */ | ||
139 | __int32_t *fcnt, /* output: number of free inodes */ | ||
140 | xfs_inofree_t *free, /* output: free inode mask */ | ||
141 | int *stat) /* output: success/failure */ | ||
142 | { | ||
143 | union xfs_btree_rec *rec; | ||
144 | int error; | ||
145 | |||
146 | error = xfs_btree_get_rec(cur, &rec, stat); | ||
147 | if (!error && *stat == 1) { | ||
148 | *ino = be32_to_cpu(rec->inobt.ir_startino); | ||
149 | *fcnt = be32_to_cpu(rec->inobt.ir_freecount); | ||
150 | *free = be64_to_cpu(rec->inobt.ir_free); | ||
151 | } | ||
152 | return error; | ||
153 | } | ||
154 | |||
155 | /* | ||
122 | * Allocate new inodes in the allocation group specified by agbp. | 156 | * Allocate new inodes in the allocation group specified by agbp. |
123 | * Return 0 for success, else error code. | 157 | * Return 0 for success, else error code. |
124 | */ | 158 | */ |
@@ -287,9 +321,9 @@ xfs_ialloc_ag_alloc( | |||
287 | * able to use the file system. | 321 | * able to use the file system. |
288 | */ | 322 | */ |
289 | if (xfs_sb_version_hasnlink(&args.mp->m_sb)) | 323 | if (xfs_sb_version_hasnlink(&args.mp->m_sb)) |
290 | version = XFS_DINODE_VERSION_2; | 324 | version = 2; |
291 | else | 325 | else |
292 | version = XFS_DINODE_VERSION_1; | 326 | version = 1; |
293 | 327 | ||
294 | /* | 328 | /* |
295 | * Seed the new inode cluster with a random generation number. This | 329 | * Seed the new inode cluster with a random generation number. This |
@@ -310,18 +344,25 @@ xfs_ialloc_ag_alloc( | |||
310 | XFS_BUF_LOCK); | 344 | XFS_BUF_LOCK); |
311 | ASSERT(fbuf); | 345 | ASSERT(fbuf); |
312 | ASSERT(!XFS_BUF_GETERROR(fbuf)); | 346 | ASSERT(!XFS_BUF_GETERROR(fbuf)); |
347 | |||
313 | /* | 348 | /* |
314 | * Set initial values for the inodes in this buffer. | 349 | * Initialize all inodes in this buffer and then log them. |
350 | * | ||
351 | * XXX: It would be much better if we had just one transaction to | ||
352 | * log a whole cluster of inodes instead of all the indivdual | ||
353 | * transactions causing a lot of log traffic. | ||
315 | */ | 354 | */ |
316 | xfs_biozero(fbuf, 0, ninodes << args.mp->m_sb.sb_inodelog); | 355 | xfs_biozero(fbuf, 0, ninodes << args.mp->m_sb.sb_inodelog); |
317 | for (i = 0; i < ninodes; i++) { | 356 | for (i = 0; i < ninodes; i++) { |
357 | int ioffset = i << args.mp->m_sb.sb_inodelog; | ||
358 | uint isize = sizeof(struct xfs_dinode); | ||
359 | |||
318 | free = XFS_MAKE_IPTR(args.mp, fbuf, i); | 360 | free = XFS_MAKE_IPTR(args.mp, fbuf, i); |
319 | free->di_core.di_magic = cpu_to_be16(XFS_DINODE_MAGIC); | 361 | free->di_magic = cpu_to_be16(XFS_DINODE_MAGIC); |
320 | free->di_core.di_version = version; | 362 | free->di_version = version; |
321 | free->di_core.di_gen = cpu_to_be32(gen); | 363 | free->di_gen = cpu_to_be32(gen); |
322 | free->di_next_unlinked = cpu_to_be32(NULLAGINO); | 364 | free->di_next_unlinked = cpu_to_be32(NULLAGINO); |
323 | xfs_ialloc_log_di(tp, fbuf, i, | 365 | xfs_trans_log_buf(tp, fbuf, ioffset, ioffset + isize - 1); |
324 | XFS_DI_CORE_BITS | XFS_DI_NEXT_UNLINKED); | ||
325 | } | 366 | } |
326 | xfs_trans_inode_alloc_buf(tp, fbuf); | 367 | xfs_trans_inode_alloc_buf(tp, fbuf); |
327 | } | 368 | } |
@@ -335,8 +376,7 @@ xfs_ialloc_ag_alloc( | |||
335 | /* | 376 | /* |
336 | * Insert records describing the new inode chunk into the btree. | 377 | * Insert records describing the new inode chunk into the btree. |
337 | */ | 378 | */ |
338 | cur = xfs_btree_init_cursor(args.mp, tp, agbp, agno, | 379 | cur = xfs_inobt_init_cursor(args.mp, tp, agbp, agno); |
339 | XFS_BTNUM_INO, (xfs_inode_t *)0, 0); | ||
340 | for (thisino = newino; | 380 | for (thisino = newino; |
341 | thisino < newino + newlen; | 381 | thisino < newino + newlen; |
342 | thisino += XFS_INODES_PER_CHUNK) { | 382 | thisino += XFS_INODES_PER_CHUNK) { |
@@ -346,7 +386,7 @@ xfs_ialloc_ag_alloc( | |||
346 | return error; | 386 | return error; |
347 | } | 387 | } |
348 | ASSERT(i == 0); | 388 | ASSERT(i == 0); |
349 | if ((error = xfs_inobt_insert(cur, &i))) { | 389 | if ((error = xfs_btree_insert(cur, &i))) { |
350 | xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); | 390 | xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); |
351 | return error; | 391 | return error; |
352 | } | 392 | } |
@@ -676,8 +716,7 @@ nextag: | |||
676 | */ | 716 | */ |
677 | agno = tagno; | 717 | agno = tagno; |
678 | *IO_agbp = NULL; | 718 | *IO_agbp = NULL; |
679 | cur = xfs_btree_init_cursor(mp, tp, agbp, be32_to_cpu(agi->agi_seqno), | 719 | cur = xfs_inobt_init_cursor(mp, tp, agbp, be32_to_cpu(agi->agi_seqno)); |
680 | XFS_BTNUM_INO, (xfs_inode_t *)0, 0); | ||
681 | /* | 720 | /* |
682 | * If pagino is 0 (this is the root inode allocation) use newino. | 721 | * If pagino is 0 (this is the root inode allocation) use newino. |
683 | * This must work because we've just allocated some. | 722 | * This must work because we've just allocated some. |
@@ -697,7 +736,7 @@ nextag: | |||
697 | goto error0; | 736 | goto error0; |
698 | XFS_WANT_CORRUPTED_GOTO(i == 1, error0); | 737 | XFS_WANT_CORRUPTED_GOTO(i == 1, error0); |
699 | freecount += rec.ir_freecount; | 738 | freecount += rec.ir_freecount; |
700 | if ((error = xfs_inobt_increment(cur, 0, &i))) | 739 | if ((error = xfs_btree_increment(cur, 0, &i))) |
701 | goto error0; | 740 | goto error0; |
702 | } while (i == 1); | 741 | } while (i == 1); |
703 | 742 | ||
@@ -741,7 +780,7 @@ nextag: | |||
741 | /* | 780 | /* |
742 | * Search left with tcur, back up 1 record. | 781 | * Search left with tcur, back up 1 record. |
743 | */ | 782 | */ |
744 | if ((error = xfs_inobt_decrement(tcur, 0, &i))) | 783 | if ((error = xfs_btree_decrement(tcur, 0, &i))) |
745 | goto error1; | 784 | goto error1; |
746 | doneleft = !i; | 785 | doneleft = !i; |
747 | if (!doneleft) { | 786 | if (!doneleft) { |
@@ -755,7 +794,7 @@ nextag: | |||
755 | /* | 794 | /* |
756 | * Search right with cur, go forward 1 record. | 795 | * Search right with cur, go forward 1 record. |
757 | */ | 796 | */ |
758 | if ((error = xfs_inobt_increment(cur, 0, &i))) | 797 | if ((error = xfs_btree_increment(cur, 0, &i))) |
759 | goto error1; | 798 | goto error1; |
760 | doneright = !i; | 799 | doneright = !i; |
761 | if (!doneright) { | 800 | if (!doneright) { |
@@ -817,7 +856,7 @@ nextag: | |||
817 | * further left. | 856 | * further left. |
818 | */ | 857 | */ |
819 | if (useleft) { | 858 | if (useleft) { |
820 | if ((error = xfs_inobt_decrement(tcur, 0, | 859 | if ((error = xfs_btree_decrement(tcur, 0, |
821 | &i))) | 860 | &i))) |
822 | goto error1; | 861 | goto error1; |
823 | doneleft = !i; | 862 | doneleft = !i; |
@@ -837,7 +876,7 @@ nextag: | |||
837 | * further right. | 876 | * further right. |
838 | */ | 877 | */ |
839 | else { | 878 | else { |
840 | if ((error = xfs_inobt_increment(cur, 0, | 879 | if ((error = xfs_btree_increment(cur, 0, |
841 | &i))) | 880 | &i))) |
842 | goto error1; | 881 | goto error1; |
843 | doneright = !i; | 882 | doneright = !i; |
@@ -892,7 +931,7 @@ nextag: | |||
892 | XFS_WANT_CORRUPTED_GOTO(i == 1, error0); | 931 | XFS_WANT_CORRUPTED_GOTO(i == 1, error0); |
893 | if (rec.ir_freecount > 0) | 932 | if (rec.ir_freecount > 0) |
894 | break; | 933 | break; |
895 | if ((error = xfs_inobt_increment(cur, 0, &i))) | 934 | if ((error = xfs_btree_increment(cur, 0, &i))) |
896 | goto error0; | 935 | goto error0; |
897 | XFS_WANT_CORRUPTED_GOTO(i == 1, error0); | 936 | XFS_WANT_CORRUPTED_GOTO(i == 1, error0); |
898 | } | 937 | } |
@@ -926,7 +965,7 @@ nextag: | |||
926 | goto error0; | 965 | goto error0; |
927 | XFS_WANT_CORRUPTED_GOTO(i == 1, error0); | 966 | XFS_WANT_CORRUPTED_GOTO(i == 1, error0); |
928 | freecount += rec.ir_freecount; | 967 | freecount += rec.ir_freecount; |
929 | if ((error = xfs_inobt_increment(cur, 0, &i))) | 968 | if ((error = xfs_btree_increment(cur, 0, &i))) |
930 | goto error0; | 969 | goto error0; |
931 | } while (i == 1); | 970 | } while (i == 1); |
932 | ASSERT(freecount == be32_to_cpu(agi->agi_freecount) || | 971 | ASSERT(freecount == be32_to_cpu(agi->agi_freecount) || |
@@ -1022,8 +1061,7 @@ xfs_difree( | |||
1022 | /* | 1061 | /* |
1023 | * Initialize the cursor. | 1062 | * Initialize the cursor. |
1024 | */ | 1063 | */ |
1025 | cur = xfs_btree_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_INO, | 1064 | cur = xfs_inobt_init_cursor(mp, tp, agbp, agno); |
1026 | (xfs_inode_t *)0, 0); | ||
1027 | #ifdef DEBUG | 1065 | #ifdef DEBUG |
1028 | if (cur->bc_nlevels == 1) { | 1066 | if (cur->bc_nlevels == 1) { |
1029 | int freecount = 0; | 1067 | int freecount = 0; |
@@ -1036,7 +1074,7 @@ xfs_difree( | |||
1036 | goto error0; | 1074 | goto error0; |
1037 | if (i) { | 1075 | if (i) { |
1038 | freecount += rec.ir_freecount; | 1076 | freecount += rec.ir_freecount; |
1039 | if ((error = xfs_inobt_increment(cur, 0, &i))) | 1077 | if ((error = xfs_btree_increment(cur, 0, &i))) |
1040 | goto error0; | 1078 | goto error0; |
1041 | } | 1079 | } |
1042 | } while (i == 1); | 1080 | } while (i == 1); |
@@ -1098,8 +1136,8 @@ xfs_difree( | |||
1098 | xfs_trans_mod_sb(tp, XFS_TRANS_SB_ICOUNT, -ilen); | 1136 | xfs_trans_mod_sb(tp, XFS_TRANS_SB_ICOUNT, -ilen); |
1099 | xfs_trans_mod_sb(tp, XFS_TRANS_SB_IFREE, -(ilen - 1)); | 1137 | xfs_trans_mod_sb(tp, XFS_TRANS_SB_IFREE, -(ilen - 1)); |
1100 | 1138 | ||
1101 | if ((error = xfs_inobt_delete(cur, &i))) { | 1139 | if ((error = xfs_btree_delete(cur, &i))) { |
1102 | cmn_err(CE_WARN, "xfs_difree: xfs_inobt_delete returned an error %d on %s.\n", | 1140 | cmn_err(CE_WARN, "xfs_difree: xfs_btree_delete returned an error %d on %s.\n", |
1103 | error, mp->m_fsname); | 1141 | error, mp->m_fsname); |
1104 | goto error0; | 1142 | goto error0; |
1105 | } | 1143 | } |
@@ -1141,7 +1179,7 @@ xfs_difree( | |||
1141 | goto error0; | 1179 | goto error0; |
1142 | if (i) { | 1180 | if (i) { |
1143 | freecount += rec.ir_freecount; | 1181 | freecount += rec.ir_freecount; |
1144 | if ((error = xfs_inobt_increment(cur, 0, &i))) | 1182 | if ((error = xfs_btree_increment(cur, 0, &i))) |
1145 | goto error0; | 1183 | goto error0; |
1146 | } | 1184 | } |
1147 | } while (i == 1); | 1185 | } while (i == 1); |
@@ -1158,36 +1196,28 @@ error0: | |||
1158 | } | 1196 | } |
1159 | 1197 | ||
1160 | /* | 1198 | /* |
1161 | * Return the location of the inode in bno/off, for mapping it into a buffer. | 1199 | * Return the location of the inode in imap, for mapping it into a buffer. |
1162 | */ | 1200 | */ |
1163 | /*ARGSUSED*/ | ||
1164 | int | 1201 | int |
1165 | xfs_dilocate( | 1202 | xfs_imap( |
1166 | xfs_mount_t *mp, /* file system mount structure */ | 1203 | xfs_mount_t *mp, /* file system mount structure */ |
1167 | xfs_trans_t *tp, /* transaction pointer */ | 1204 | xfs_trans_t *tp, /* transaction pointer */ |
1168 | xfs_ino_t ino, /* inode to locate */ | 1205 | xfs_ino_t ino, /* inode to locate */ |
1169 | xfs_fsblock_t *bno, /* output: block containing inode */ | 1206 | struct xfs_imap *imap, /* location map structure */ |
1170 | int *len, /* output: num blocks in inode cluster */ | 1207 | uint flags) /* flags for inode btree lookup */ |
1171 | int *off, /* output: index in block of inode */ | ||
1172 | uint flags) /* flags concerning inode lookup */ | ||
1173 | { | 1208 | { |
1174 | xfs_agblock_t agbno; /* block number of inode in the alloc group */ | 1209 | xfs_agblock_t agbno; /* block number of inode in the alloc group */ |
1175 | xfs_buf_t *agbp; /* agi buffer */ | ||
1176 | xfs_agino_t agino; /* inode number within alloc group */ | 1210 | xfs_agino_t agino; /* inode number within alloc group */ |
1177 | xfs_agnumber_t agno; /* allocation group number */ | 1211 | xfs_agnumber_t agno; /* allocation group number */ |
1178 | int blks_per_cluster; /* num blocks per inode cluster */ | 1212 | int blks_per_cluster; /* num blocks per inode cluster */ |
1179 | xfs_agblock_t chunk_agbno; /* first block in inode chunk */ | 1213 | xfs_agblock_t chunk_agbno; /* first block in inode chunk */ |
1180 | xfs_agino_t chunk_agino; /* first agino in inode chunk */ | ||
1181 | __int32_t chunk_cnt; /* count of free inodes in chunk */ | ||
1182 | xfs_inofree_t chunk_free; /* mask of free inodes in chunk */ | ||
1183 | xfs_agblock_t cluster_agbno; /* first block in inode cluster */ | 1214 | xfs_agblock_t cluster_agbno; /* first block in inode cluster */ |
1184 | xfs_btree_cur_t *cur; /* inode btree cursor */ | ||
1185 | int error; /* error code */ | 1215 | int error; /* error code */ |
1186 | int i; /* temp state */ | ||
1187 | int offset; /* index of inode in its buffer */ | 1216 | int offset; /* index of inode in its buffer */ |
1188 | int offset_agbno; /* blks from chunk start to inode */ | 1217 | int offset_agbno; /* blks from chunk start to inode */ |
1189 | 1218 | ||
1190 | ASSERT(ino != NULLFSINO); | 1219 | ASSERT(ino != NULLFSINO); |
1220 | |||
1191 | /* | 1221 | /* |
1192 | * Split up the inode number into its parts. | 1222 | * Split up the inode number into its parts. |
1193 | */ | 1223 | */ |
@@ -1198,24 +1228,24 @@ xfs_dilocate( | |||
1198 | ino != XFS_AGINO_TO_INO(mp, agno, agino)) { | 1228 | ino != XFS_AGINO_TO_INO(mp, agno, agino)) { |
1199 | #ifdef DEBUG | 1229 | #ifdef DEBUG |
1200 | /* no diagnostics for bulkstat, ino comes from userspace */ | 1230 | /* no diagnostics for bulkstat, ino comes from userspace */ |
1201 | if (flags & XFS_IMAP_BULKSTAT) | 1231 | if (flags & XFS_IGET_BULKSTAT) |
1202 | return XFS_ERROR(EINVAL); | 1232 | return XFS_ERROR(EINVAL); |
1203 | if (agno >= mp->m_sb.sb_agcount) { | 1233 | if (agno >= mp->m_sb.sb_agcount) { |
1204 | xfs_fs_cmn_err(CE_ALERT, mp, | 1234 | xfs_fs_cmn_err(CE_ALERT, mp, |
1205 | "xfs_dilocate: agno (%d) >= " | 1235 | "xfs_imap: agno (%d) >= " |
1206 | "mp->m_sb.sb_agcount (%d)", | 1236 | "mp->m_sb.sb_agcount (%d)", |
1207 | agno, mp->m_sb.sb_agcount); | 1237 | agno, mp->m_sb.sb_agcount); |
1208 | } | 1238 | } |
1209 | if (agbno >= mp->m_sb.sb_agblocks) { | 1239 | if (agbno >= mp->m_sb.sb_agblocks) { |
1210 | xfs_fs_cmn_err(CE_ALERT, mp, | 1240 | xfs_fs_cmn_err(CE_ALERT, mp, |
1211 | "xfs_dilocate: agbno (0x%llx) >= " | 1241 | "xfs_imap: agbno (0x%llx) >= " |
1212 | "mp->m_sb.sb_agblocks (0x%lx)", | 1242 | "mp->m_sb.sb_agblocks (0x%lx)", |
1213 | (unsigned long long) agbno, | 1243 | (unsigned long long) agbno, |
1214 | (unsigned long) mp->m_sb.sb_agblocks); | 1244 | (unsigned long) mp->m_sb.sb_agblocks); |
1215 | } | 1245 | } |
1216 | if (ino != XFS_AGINO_TO_INO(mp, agno, agino)) { | 1246 | if (ino != XFS_AGINO_TO_INO(mp, agno, agino)) { |
1217 | xfs_fs_cmn_err(CE_ALERT, mp, | 1247 | xfs_fs_cmn_err(CE_ALERT, mp, |
1218 | "xfs_dilocate: ino (0x%llx) != " | 1248 | "xfs_imap: ino (0x%llx) != " |
1219 | "XFS_AGINO_TO_INO(mp, agno, agino) " | 1249 | "XFS_AGINO_TO_INO(mp, agno, agino) " |
1220 | "(0x%llx)", | 1250 | "(0x%llx)", |
1221 | ino, XFS_AGINO_TO_INO(mp, agno, agino)); | 1251 | ino, XFS_AGINO_TO_INO(mp, agno, agino)); |
@@ -1224,65 +1254,89 @@ xfs_dilocate( | |||
1224 | #endif /* DEBUG */ | 1254 | #endif /* DEBUG */ |
1225 | return XFS_ERROR(EINVAL); | 1255 | return XFS_ERROR(EINVAL); |
1226 | } | 1256 | } |
1227 | if ((mp->m_sb.sb_blocksize >= XFS_INODE_CLUSTER_SIZE(mp)) || | 1257 | |
1228 | !(flags & XFS_IMAP_LOOKUP)) { | 1258 | /* |
1259 | * If the inode cluster size is the same as the blocksize or | ||
1260 | * smaller we get to the buffer by simple arithmetics. | ||
1261 | */ | ||
1262 | if (XFS_INODE_CLUSTER_SIZE(mp) <= mp->m_sb.sb_blocksize) { | ||
1229 | offset = XFS_INO_TO_OFFSET(mp, ino); | 1263 | offset = XFS_INO_TO_OFFSET(mp, ino); |
1230 | ASSERT(offset < mp->m_sb.sb_inopblock); | 1264 | ASSERT(offset < mp->m_sb.sb_inopblock); |
1231 | *bno = XFS_AGB_TO_FSB(mp, agno, agbno); | 1265 | |
1232 | *off = offset; | 1266 | imap->im_blkno = XFS_AGB_TO_DADDR(mp, agno, agbno); |
1233 | *len = 1; | 1267 | imap->im_len = XFS_FSB_TO_BB(mp, 1); |
1268 | imap->im_boffset = (ushort)(offset << mp->m_sb.sb_inodelog); | ||
1234 | return 0; | 1269 | return 0; |
1235 | } | 1270 | } |
1271 | |||
1236 | blks_per_cluster = XFS_INODE_CLUSTER_SIZE(mp) >> mp->m_sb.sb_blocklog; | 1272 | blks_per_cluster = XFS_INODE_CLUSTER_SIZE(mp) >> mp->m_sb.sb_blocklog; |
1237 | if (*bno != NULLFSBLOCK) { | 1273 | |
1274 | /* | ||
1275 | * If we get a block number passed from bulkstat we can use it to | ||
1276 | * find the buffer easily. | ||
1277 | */ | ||
1278 | if (imap->im_blkno) { | ||
1238 | offset = XFS_INO_TO_OFFSET(mp, ino); | 1279 | offset = XFS_INO_TO_OFFSET(mp, ino); |
1239 | ASSERT(offset < mp->m_sb.sb_inopblock); | 1280 | ASSERT(offset < mp->m_sb.sb_inopblock); |
1240 | cluster_agbno = XFS_FSB_TO_AGBNO(mp, *bno); | 1281 | |
1241 | *off = ((agbno - cluster_agbno) * mp->m_sb.sb_inopblock) + | 1282 | cluster_agbno = XFS_DADDR_TO_AGBNO(mp, imap->im_blkno); |
1242 | offset; | 1283 | offset += (agbno - cluster_agbno) * mp->m_sb.sb_inopblock; |
1243 | *len = blks_per_cluster; | 1284 | |
1285 | imap->im_len = XFS_FSB_TO_BB(mp, blks_per_cluster); | ||
1286 | imap->im_boffset = (ushort)(offset << mp->m_sb.sb_inodelog); | ||
1244 | return 0; | 1287 | return 0; |
1245 | } | 1288 | } |
1289 | |||
1290 | /* | ||
1291 | * If the inode chunks are aligned then use simple maths to | ||
1292 | * find the location. Otherwise we have to do a btree | ||
1293 | * lookup to find the location. | ||
1294 | */ | ||
1246 | if (mp->m_inoalign_mask) { | 1295 | if (mp->m_inoalign_mask) { |
1247 | offset_agbno = agbno & mp->m_inoalign_mask; | 1296 | offset_agbno = agbno & mp->m_inoalign_mask; |
1248 | chunk_agbno = agbno - offset_agbno; | 1297 | chunk_agbno = agbno - offset_agbno; |
1249 | } else { | 1298 | } else { |
1299 | xfs_btree_cur_t *cur; /* inode btree cursor */ | ||
1300 | xfs_agino_t chunk_agino; /* first agino in inode chunk */ | ||
1301 | __int32_t chunk_cnt; /* count of free inodes in chunk */ | ||
1302 | xfs_inofree_t chunk_free; /* mask of free inodes in chunk */ | ||
1303 | xfs_buf_t *agbp; /* agi buffer */ | ||
1304 | int i; /* temp state */ | ||
1305 | |||
1250 | down_read(&mp->m_peraglock); | 1306 | down_read(&mp->m_peraglock); |
1251 | error = xfs_ialloc_read_agi(mp, tp, agno, &agbp); | 1307 | error = xfs_ialloc_read_agi(mp, tp, agno, &agbp); |
1252 | up_read(&mp->m_peraglock); | 1308 | up_read(&mp->m_peraglock); |
1253 | if (error) { | 1309 | if (error) { |
1254 | #ifdef DEBUG | 1310 | xfs_fs_cmn_err(CE_ALERT, mp, "xfs_imap: " |
1255 | xfs_fs_cmn_err(CE_ALERT, mp, "xfs_dilocate: " | ||
1256 | "xfs_ialloc_read_agi() returned " | 1311 | "xfs_ialloc_read_agi() returned " |
1257 | "error %d, agno %d", | 1312 | "error %d, agno %d", |
1258 | error, agno); | 1313 | error, agno); |
1259 | #endif /* DEBUG */ | ||
1260 | return error; | 1314 | return error; |
1261 | } | 1315 | } |
1262 | cur = xfs_btree_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_INO, | 1316 | |
1263 | (xfs_inode_t *)0, 0); | 1317 | cur = xfs_inobt_init_cursor(mp, tp, agbp, agno); |
1264 | if ((error = xfs_inobt_lookup_le(cur, agino, 0, 0, &i))) { | 1318 | error = xfs_inobt_lookup_le(cur, agino, 0, 0, &i); |
1265 | #ifdef DEBUG | 1319 | if (error) { |
1266 | xfs_fs_cmn_err(CE_ALERT, mp, "xfs_dilocate: " | 1320 | xfs_fs_cmn_err(CE_ALERT, mp, "xfs_imap: " |
1267 | "xfs_inobt_lookup_le() failed"); | 1321 | "xfs_inobt_lookup_le() failed"); |
1268 | #endif /* DEBUG */ | ||
1269 | goto error0; | 1322 | goto error0; |
1270 | } | 1323 | } |
1271 | if ((error = xfs_inobt_get_rec(cur, &chunk_agino, &chunk_cnt, | 1324 | |
1272 | &chunk_free, &i))) { | 1325 | error = xfs_inobt_get_rec(cur, &chunk_agino, &chunk_cnt, |
1273 | #ifdef DEBUG | 1326 | &chunk_free, &i); |
1274 | xfs_fs_cmn_err(CE_ALERT, mp, "xfs_dilocate: " | 1327 | if (error) { |
1328 | xfs_fs_cmn_err(CE_ALERT, mp, "xfs_imap: " | ||
1275 | "xfs_inobt_get_rec() failed"); | 1329 | "xfs_inobt_get_rec() failed"); |
1276 | #endif /* DEBUG */ | ||
1277 | goto error0; | 1330 | goto error0; |
1278 | } | 1331 | } |
1279 | if (i == 0) { | 1332 | if (i == 0) { |
1280 | #ifdef DEBUG | 1333 | #ifdef DEBUG |
1281 | xfs_fs_cmn_err(CE_ALERT, mp, "xfs_dilocate: " | 1334 | xfs_fs_cmn_err(CE_ALERT, mp, "xfs_imap: " |
1282 | "xfs_inobt_get_rec() failed"); | 1335 | "xfs_inobt_get_rec() failed"); |
1283 | #endif /* DEBUG */ | 1336 | #endif /* DEBUG */ |
1284 | error = XFS_ERROR(EINVAL); | 1337 | error = XFS_ERROR(EINVAL); |
1285 | } | 1338 | } |
1339 | error0: | ||
1286 | xfs_trans_brelse(tp, agbp); | 1340 | xfs_trans_brelse(tp, agbp); |
1287 | xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); | 1341 | xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); |
1288 | if (error) | 1342 | if (error) |
@@ -1290,19 +1344,35 @@ xfs_dilocate( | |||
1290 | chunk_agbno = XFS_AGINO_TO_AGBNO(mp, chunk_agino); | 1344 | chunk_agbno = XFS_AGINO_TO_AGBNO(mp, chunk_agino); |
1291 | offset_agbno = agbno - chunk_agbno; | 1345 | offset_agbno = agbno - chunk_agbno; |
1292 | } | 1346 | } |
1347 | |||
1293 | ASSERT(agbno >= chunk_agbno); | 1348 | ASSERT(agbno >= chunk_agbno); |
1294 | cluster_agbno = chunk_agbno + | 1349 | cluster_agbno = chunk_agbno + |
1295 | ((offset_agbno / blks_per_cluster) * blks_per_cluster); | 1350 | ((offset_agbno / blks_per_cluster) * blks_per_cluster); |
1296 | offset = ((agbno - cluster_agbno) * mp->m_sb.sb_inopblock) + | 1351 | offset = ((agbno - cluster_agbno) * mp->m_sb.sb_inopblock) + |
1297 | XFS_INO_TO_OFFSET(mp, ino); | 1352 | XFS_INO_TO_OFFSET(mp, ino); |
1298 | *bno = XFS_AGB_TO_FSB(mp, agno, cluster_agbno); | 1353 | |
1299 | *off = offset; | 1354 | imap->im_blkno = XFS_AGB_TO_DADDR(mp, agno, cluster_agbno); |
1300 | *len = blks_per_cluster; | 1355 | imap->im_len = XFS_FSB_TO_BB(mp, blks_per_cluster); |
1356 | imap->im_boffset = (ushort)(offset << mp->m_sb.sb_inodelog); | ||
1357 | |||
1358 | /* | ||
1359 | * If the inode number maps to a block outside the bounds | ||
1360 | * of the file system then return NULL rather than calling | ||
1361 | * read_buf and panicing when we get an error from the | ||
1362 | * driver. | ||
1363 | */ | ||
1364 | if ((imap->im_blkno + imap->im_len) > | ||
1365 | XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks)) { | ||
1366 | xfs_fs_cmn_err(CE_ALERT, mp, "xfs_imap: " | ||
1367 | "(imap->im_blkno (0x%llx) + imap->im_len (0x%llx)) > " | ||
1368 | " XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks) (0x%llx)", | ||
1369 | (unsigned long long) imap->im_blkno, | ||
1370 | (unsigned long long) imap->im_len, | ||
1371 | XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks)); | ||
1372 | return XFS_ERROR(EINVAL); | ||
1373 | } | ||
1374 | |||
1301 | return 0; | 1375 | return 0; |
1302 | error0: | ||
1303 | xfs_trans_brelse(tp, agbp); | ||
1304 | xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); | ||
1305 | return error; | ||
1306 | } | 1376 | } |
1307 | 1377 | ||
1308 | /* | 1378 | /* |
@@ -1370,70 +1440,95 @@ xfs_ialloc_log_agi( | |||
1370 | xfs_trans_log_buf(tp, bp, first, last); | 1440 | xfs_trans_log_buf(tp, bp, first, last); |
1371 | } | 1441 | } |
1372 | 1442 | ||
1443 | #ifdef DEBUG | ||
1444 | STATIC void | ||
1445 | xfs_check_agi_unlinked( | ||
1446 | struct xfs_agi *agi) | ||
1447 | { | ||
1448 | int i; | ||
1449 | |||
1450 | for (i = 0; i < XFS_AGI_UNLINKED_BUCKETS; i++) | ||
1451 | ASSERT(agi->agi_unlinked[i]); | ||
1452 | } | ||
1453 | #else | ||
1454 | #define xfs_check_agi_unlinked(agi) | ||
1455 | #endif | ||
1456 | |||
1373 | /* | 1457 | /* |
1374 | * Read in the allocation group header (inode allocation section) | 1458 | * Read in the allocation group header (inode allocation section) |
1375 | */ | 1459 | */ |
1376 | int | 1460 | int |
1377 | xfs_ialloc_read_agi( | 1461 | xfs_read_agi( |
1378 | xfs_mount_t *mp, /* file system mount structure */ | 1462 | struct xfs_mount *mp, /* file system mount structure */ |
1379 | xfs_trans_t *tp, /* transaction pointer */ | 1463 | struct xfs_trans *tp, /* transaction pointer */ |
1380 | xfs_agnumber_t agno, /* allocation group number */ | 1464 | xfs_agnumber_t agno, /* allocation group number */ |
1381 | xfs_buf_t **bpp) /* allocation group hdr buf */ | 1465 | struct xfs_buf **bpp) /* allocation group hdr buf */ |
1382 | { | 1466 | { |
1383 | xfs_agi_t *agi; /* allocation group header */ | 1467 | struct xfs_agi *agi; /* allocation group header */ |
1384 | int agi_ok; /* agi is consistent */ | 1468 | int agi_ok; /* agi is consistent */ |
1385 | xfs_buf_t *bp; /* allocation group hdr buf */ | 1469 | int error; |
1386 | xfs_perag_t *pag; /* per allocation group data */ | ||
1387 | int error; | ||
1388 | 1470 | ||
1389 | ASSERT(agno != NULLAGNUMBER); | 1471 | ASSERT(agno != NULLAGNUMBER); |
1390 | error = xfs_trans_read_buf( | 1472 | |
1391 | mp, tp, mp->m_ddev_targp, | 1473 | error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, |
1392 | XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR(mp)), | 1474 | XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR(mp)), |
1393 | XFS_FSS_TO_BB(mp, 1), 0, &bp); | 1475 | XFS_FSS_TO_BB(mp, 1), 0, bpp); |
1394 | if (error) | 1476 | if (error) |
1395 | return error; | 1477 | return error; |
1396 | ASSERT(bp && !XFS_BUF_GETERROR(bp)); | 1478 | |
1479 | ASSERT(*bpp && !XFS_BUF_GETERROR(*bpp)); | ||
1480 | agi = XFS_BUF_TO_AGI(*bpp); | ||
1397 | 1481 | ||
1398 | /* | 1482 | /* |
1399 | * Validate the magic number of the agi block. | 1483 | * Validate the magic number of the agi block. |
1400 | */ | 1484 | */ |
1401 | agi = XFS_BUF_TO_AGI(bp); | 1485 | agi_ok = be32_to_cpu(agi->agi_magicnum) == XFS_AGI_MAGIC && |
1402 | agi_ok = | 1486 | XFS_AGI_GOOD_VERSION(be32_to_cpu(agi->agi_versionnum)) && |
1403 | be32_to_cpu(agi->agi_magicnum) == XFS_AGI_MAGIC && | 1487 | be32_to_cpu(agi->agi_seqno) == agno; |
1404 | XFS_AGI_GOOD_VERSION(be32_to_cpu(agi->agi_versionnum)); | ||
1405 | if (unlikely(XFS_TEST_ERROR(!agi_ok, mp, XFS_ERRTAG_IALLOC_READ_AGI, | 1488 | if (unlikely(XFS_TEST_ERROR(!agi_ok, mp, XFS_ERRTAG_IALLOC_READ_AGI, |
1406 | XFS_RANDOM_IALLOC_READ_AGI))) { | 1489 | XFS_RANDOM_IALLOC_READ_AGI))) { |
1407 | XFS_CORRUPTION_ERROR("xfs_ialloc_read_agi", XFS_ERRLEVEL_LOW, | 1490 | XFS_CORRUPTION_ERROR("xfs_read_agi", XFS_ERRLEVEL_LOW, |
1408 | mp, agi); | 1491 | mp, agi); |
1409 | xfs_trans_brelse(tp, bp); | 1492 | xfs_trans_brelse(tp, *bpp); |
1410 | return XFS_ERROR(EFSCORRUPTED); | 1493 | return XFS_ERROR(EFSCORRUPTED); |
1411 | } | 1494 | } |
1495 | |||
1496 | XFS_BUF_SET_VTYPE_REF(*bpp, B_FS_AGI, XFS_AGI_REF); | ||
1497 | |||
1498 | xfs_check_agi_unlinked(agi); | ||
1499 | return 0; | ||
1500 | } | ||
1501 | |||
1502 | int | ||
1503 | xfs_ialloc_read_agi( | ||
1504 | struct xfs_mount *mp, /* file system mount structure */ | ||
1505 | struct xfs_trans *tp, /* transaction pointer */ | ||
1506 | xfs_agnumber_t agno, /* allocation group number */ | ||
1507 | struct xfs_buf **bpp) /* allocation group hdr buf */ | ||
1508 | { | ||
1509 | struct xfs_agi *agi; /* allocation group header */ | ||
1510 | struct xfs_perag *pag; /* per allocation group data */ | ||
1511 | int error; | ||
1512 | |||
1513 | error = xfs_read_agi(mp, tp, agno, bpp); | ||
1514 | if (error) | ||
1515 | return error; | ||
1516 | |||
1517 | agi = XFS_BUF_TO_AGI(*bpp); | ||
1412 | pag = &mp->m_perag[agno]; | 1518 | pag = &mp->m_perag[agno]; |
1519 | |||
1413 | if (!pag->pagi_init) { | 1520 | if (!pag->pagi_init) { |
1414 | pag->pagi_freecount = be32_to_cpu(agi->agi_freecount); | 1521 | pag->pagi_freecount = be32_to_cpu(agi->agi_freecount); |
1415 | pag->pagi_count = be32_to_cpu(agi->agi_count); | 1522 | pag->pagi_count = be32_to_cpu(agi->agi_count); |
1416 | pag->pagi_init = 1; | 1523 | pag->pagi_init = 1; |
1417 | } else { | ||
1418 | /* | ||
1419 | * It's possible for these to be out of sync if | ||
1420 | * we are in the middle of a forced shutdown. | ||
1421 | */ | ||
1422 | ASSERT(pag->pagi_freecount == be32_to_cpu(agi->agi_freecount) || | ||
1423 | XFS_FORCED_SHUTDOWN(mp)); | ||
1424 | } | 1524 | } |
1425 | 1525 | ||
1426 | #ifdef DEBUG | 1526 | /* |
1427 | { | 1527 | * It's possible for these to be out of sync if |
1428 | int i; | 1528 | * we are in the middle of a forced shutdown. |
1429 | 1529 | */ | |
1430 | for (i = 0; i < XFS_AGI_UNLINKED_BUCKETS; i++) | 1530 | ASSERT(pag->pagi_freecount == be32_to_cpu(agi->agi_freecount) || |
1431 | ASSERT(agi->agi_unlinked[i]); | 1531 | XFS_FORCED_SHUTDOWN(mp)); |
1432 | } | ||
1433 | #endif | ||
1434 | |||
1435 | XFS_BUF_SET_VTYPE_REF(bp, B_FS_AGI, XFS_AGI_REF); | ||
1436 | *bpp = bp; | ||
1437 | return 0; | 1532 | return 0; |
1438 | } | 1533 | } |
1439 | 1534 | ||