Root/
1 | /* |
2 | * Copyright (c) 2000-2003,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_types.h" |
21 | #include "xfs_bit.h" |
22 | #include "xfs_log.h" |
23 | #include "xfs_inum.h" |
24 | #include "xfs_trans.h" |
25 | #include "xfs_sb.h" |
26 | #include "xfs_ag.h" |
27 | #include "xfs_dir2.h" |
28 | #include "xfs_dmapi.h" |
29 | #include "xfs_mount.h" |
30 | #include "xfs_bmap_btree.h" |
31 | #include "xfs_alloc_btree.h" |
32 | #include "xfs_ialloc_btree.h" |
33 | #include "xfs_dir2_sf.h" |
34 | #include "xfs_attr_sf.h" |
35 | #include "xfs_dinode.h" |
36 | #include "xfs_inode.h" |
37 | #include "xfs_inode_item.h" |
38 | #include "xfs_alloc.h" |
39 | #include "xfs_btree.h" |
40 | #include "xfs_btree_trace.h" |
41 | #include "xfs_ialloc.h" |
42 | #include "xfs_itable.h" |
43 | #include "xfs_bmap.h" |
44 | #include "xfs_error.h" |
45 | #include "xfs_quota.h" |
46 | |
47 | /* |
48 | * Determine the extent state. |
49 | */ |
50 | /* ARGSUSED */ |
51 | STATIC xfs_exntst_t |
52 | xfs_extent_state( |
53 | xfs_filblks_t blks, |
54 | int extent_flag) |
55 | { |
56 | if (extent_flag) { |
57 | ASSERT(blks != 0); /* saved for DMIG */ |
58 | return XFS_EXT_UNWRITTEN; |
59 | } |
60 | return XFS_EXT_NORM; |
61 | } |
62 | |
63 | /* |
64 | * Convert on-disk form of btree root to in-memory form. |
65 | */ |
66 | void |
67 | xfs_bmdr_to_bmbt( |
68 | struct xfs_mount *mp, |
69 | xfs_bmdr_block_t *dblock, |
70 | int dblocklen, |
71 | struct xfs_btree_block *rblock, |
72 | int rblocklen) |
73 | { |
74 | int dmxr; |
75 | xfs_bmbt_key_t *fkp; |
76 | __be64 *fpp; |
77 | xfs_bmbt_key_t *tkp; |
78 | __be64 *tpp; |
79 | |
80 | rblock->bb_magic = cpu_to_be32(XFS_BMAP_MAGIC); |
81 | rblock->bb_level = dblock->bb_level; |
82 | ASSERT(be16_to_cpu(rblock->bb_level) > 0); |
83 | rblock->bb_numrecs = dblock->bb_numrecs; |
84 | rblock->bb_u.l.bb_leftsib = cpu_to_be64(NULLDFSBNO); |
85 | rblock->bb_u.l.bb_rightsib = cpu_to_be64(NULLDFSBNO); |
86 | dmxr = xfs_bmdr_maxrecs(mp, dblocklen, 0); |
87 | fkp = XFS_BMDR_KEY_ADDR(dblock, 1); |
88 | tkp = XFS_BMBT_KEY_ADDR(mp, rblock, 1); |
89 | fpp = XFS_BMDR_PTR_ADDR(dblock, 1, dmxr); |
90 | tpp = XFS_BMAP_BROOT_PTR_ADDR(mp, rblock, 1, rblocklen); |
91 | dmxr = be16_to_cpu(dblock->bb_numrecs); |
92 | memcpy(tkp, fkp, sizeof(*fkp) * dmxr); |
93 | memcpy(tpp, fpp, sizeof(*fpp) * dmxr); |
94 | } |
95 | |
96 | /* |
97 | * Convert a compressed bmap extent record to an uncompressed form. |
98 | * This code must be in sync with the routines xfs_bmbt_get_startoff, |
99 | * xfs_bmbt_get_startblock, xfs_bmbt_get_blockcount and xfs_bmbt_get_state. |
100 | */ |
101 | |
102 | STATIC_INLINE void |
103 | __xfs_bmbt_get_all( |
104 | __uint64_t l0, |
105 | __uint64_t l1, |
106 | xfs_bmbt_irec_t *s) |
107 | { |
108 | int ext_flag; |
109 | xfs_exntst_t st; |
110 | |
111 | ext_flag = (int)(l0 >> (64 - BMBT_EXNTFLAG_BITLEN)); |
112 | s->br_startoff = ((xfs_fileoff_t)l0 & |
113 | xfs_mask64lo(64 - BMBT_EXNTFLAG_BITLEN)) >> 9; |
114 | #if XFS_BIG_BLKNOS |
115 | s->br_startblock = (((xfs_fsblock_t)l0 & xfs_mask64lo(9)) << 43) | |
116 | (((xfs_fsblock_t)l1) >> 21); |
117 | #else |
118 | #ifdef DEBUG |
119 | { |
120 | xfs_dfsbno_t b; |
121 | |
122 | b = (((xfs_dfsbno_t)l0 & xfs_mask64lo(9)) << 43) | |
123 | (((xfs_dfsbno_t)l1) >> 21); |
124 | ASSERT((b >> 32) == 0 || isnulldstartblock(b)); |
125 | s->br_startblock = (xfs_fsblock_t)b; |
126 | } |
127 | #else /* !DEBUG */ |
128 | s->br_startblock = (xfs_fsblock_t)(((xfs_dfsbno_t)l1) >> 21); |
129 | #endif /* DEBUG */ |
130 | #endif /* XFS_BIG_BLKNOS */ |
131 | s->br_blockcount = (xfs_filblks_t)(l1 & xfs_mask64lo(21)); |
132 | /* This is xfs_extent_state() in-line */ |
133 | if (ext_flag) { |
134 | ASSERT(s->br_blockcount != 0); /* saved for DMIG */ |
135 | st = XFS_EXT_UNWRITTEN; |
136 | } else |
137 | st = XFS_EXT_NORM; |
138 | s->br_state = st; |
139 | } |
140 | |
141 | void |
142 | xfs_bmbt_get_all( |
143 | xfs_bmbt_rec_host_t *r, |
144 | xfs_bmbt_irec_t *s) |
145 | { |
146 | __xfs_bmbt_get_all(r->l0, r->l1, s); |
147 | } |
148 | |
149 | /* |
150 | * Extract the blockcount field from an in memory bmap extent record. |
151 | */ |
152 | xfs_filblks_t |
153 | xfs_bmbt_get_blockcount( |
154 | xfs_bmbt_rec_host_t *r) |
155 | { |
156 | return (xfs_filblks_t)(r->l1 & xfs_mask64lo(21)); |
157 | } |
158 | |
159 | /* |
160 | * Extract the startblock field from an in memory bmap extent record. |
161 | */ |
162 | xfs_fsblock_t |
163 | xfs_bmbt_get_startblock( |
164 | xfs_bmbt_rec_host_t *r) |
165 | { |
166 | #if XFS_BIG_BLKNOS |
167 | return (((xfs_fsblock_t)r->l0 & xfs_mask64lo(9)) << 43) | |
168 | (((xfs_fsblock_t)r->l1) >> 21); |
169 | #else |
170 | #ifdef DEBUG |
171 | xfs_dfsbno_t b; |
172 | |
173 | b = (((xfs_dfsbno_t)r->l0 & xfs_mask64lo(9)) << 43) | |
174 | (((xfs_dfsbno_t)r->l1) >> 21); |
175 | ASSERT((b >> 32) == 0 || isnulldstartblock(b)); |
176 | return (xfs_fsblock_t)b; |
177 | #else /* !DEBUG */ |
178 | return (xfs_fsblock_t)(((xfs_dfsbno_t)r->l1) >> 21); |
179 | #endif /* DEBUG */ |
180 | #endif /* XFS_BIG_BLKNOS */ |
181 | } |
182 | |
183 | /* |
184 | * Extract the startoff field from an in memory bmap extent record. |
185 | */ |
186 | xfs_fileoff_t |
187 | xfs_bmbt_get_startoff( |
188 | xfs_bmbt_rec_host_t *r) |
189 | { |
190 | return ((xfs_fileoff_t)r->l0 & |
191 | xfs_mask64lo(64 - BMBT_EXNTFLAG_BITLEN)) >> 9; |
192 | } |
193 | |
194 | xfs_exntst_t |
195 | xfs_bmbt_get_state( |
196 | xfs_bmbt_rec_host_t *r) |
197 | { |
198 | int ext_flag; |
199 | |
200 | ext_flag = (int)((r->l0) >> (64 - BMBT_EXNTFLAG_BITLEN)); |
201 | return xfs_extent_state(xfs_bmbt_get_blockcount(r), |
202 | ext_flag); |
203 | } |
204 | |
205 | /* Endian flipping versions of the bmbt extraction functions */ |
206 | void |
207 | xfs_bmbt_disk_get_all( |
208 | xfs_bmbt_rec_t *r, |
209 | xfs_bmbt_irec_t *s) |
210 | { |
211 | __xfs_bmbt_get_all(get_unaligned_be64(&r->l0), |
212 | get_unaligned_be64(&r->l1), s); |
213 | } |
214 | |
215 | /* |
216 | * Extract the blockcount field from an on disk bmap extent record. |
217 | */ |
218 | xfs_filblks_t |
219 | xfs_bmbt_disk_get_blockcount( |
220 | xfs_bmbt_rec_t *r) |
221 | { |
222 | return (xfs_filblks_t)(be64_to_cpu(r->l1) & xfs_mask64lo(21)); |
223 | } |
224 | |
225 | /* |
226 | * Extract the startoff field from a disk format bmap extent record. |
227 | */ |
228 | xfs_fileoff_t |
229 | xfs_bmbt_disk_get_startoff( |
230 | xfs_bmbt_rec_t *r) |
231 | { |
232 | return ((xfs_fileoff_t)be64_to_cpu(r->l0) & |
233 | xfs_mask64lo(64 - BMBT_EXNTFLAG_BITLEN)) >> 9; |
234 | } |
235 | |
236 | |
237 | /* |
238 | * Set all the fields in a bmap extent record from the arguments. |
239 | */ |
240 | void |
241 | xfs_bmbt_set_allf( |
242 | xfs_bmbt_rec_host_t *r, |
243 | xfs_fileoff_t startoff, |
244 | xfs_fsblock_t startblock, |
245 | xfs_filblks_t blockcount, |
246 | xfs_exntst_t state) |
247 | { |
248 | int extent_flag = (state == XFS_EXT_NORM) ? 0 : 1; |
249 | |
250 | ASSERT(state == XFS_EXT_NORM || state == XFS_EXT_UNWRITTEN); |
251 | ASSERT((startoff & xfs_mask64hi(64-BMBT_STARTOFF_BITLEN)) == 0); |
252 | ASSERT((blockcount & xfs_mask64hi(64-BMBT_BLOCKCOUNT_BITLEN)) == 0); |
253 | |
254 | #if XFS_BIG_BLKNOS |
255 | ASSERT((startblock & xfs_mask64hi(64-BMBT_STARTBLOCK_BITLEN)) == 0); |
256 | |
257 | r->l0 = ((xfs_bmbt_rec_base_t)extent_flag << 63) | |
258 | ((xfs_bmbt_rec_base_t)startoff << 9) | |
259 | ((xfs_bmbt_rec_base_t)startblock >> 43); |
260 | r->l1 = ((xfs_bmbt_rec_base_t)startblock << 21) | |
261 | ((xfs_bmbt_rec_base_t)blockcount & |
262 | (xfs_bmbt_rec_base_t)xfs_mask64lo(21)); |
263 | #else /* !XFS_BIG_BLKNOS */ |
264 | if (isnullstartblock(startblock)) { |
265 | r->l0 = ((xfs_bmbt_rec_base_t)extent_flag << 63) | |
266 | ((xfs_bmbt_rec_base_t)startoff << 9) | |
267 | (xfs_bmbt_rec_base_t)xfs_mask64lo(9); |
268 | r->l1 = xfs_mask64hi(11) | |
269 | ((xfs_bmbt_rec_base_t)startblock << 21) | |
270 | ((xfs_bmbt_rec_base_t)blockcount & |
271 | (xfs_bmbt_rec_base_t)xfs_mask64lo(21)); |
272 | } else { |
273 | r->l0 = ((xfs_bmbt_rec_base_t)extent_flag << 63) | |
274 | ((xfs_bmbt_rec_base_t)startoff << 9); |
275 | r->l1 = ((xfs_bmbt_rec_base_t)startblock << 21) | |
276 | ((xfs_bmbt_rec_base_t)blockcount & |
277 | (xfs_bmbt_rec_base_t)xfs_mask64lo(21)); |
278 | } |
279 | #endif /* XFS_BIG_BLKNOS */ |
280 | } |
281 | |
282 | /* |
283 | * Set all the fields in a bmap extent record from the uncompressed form. |
284 | */ |
285 | void |
286 | xfs_bmbt_set_all( |
287 | xfs_bmbt_rec_host_t *r, |
288 | xfs_bmbt_irec_t *s) |
289 | { |
290 | xfs_bmbt_set_allf(r, s->br_startoff, s->br_startblock, |
291 | s->br_blockcount, s->br_state); |
292 | } |
293 | |
294 | |
295 | /* |
296 | * Set all the fields in a disk format bmap extent record from the arguments. |
297 | */ |
298 | void |
299 | xfs_bmbt_disk_set_allf( |
300 | xfs_bmbt_rec_t *r, |
301 | xfs_fileoff_t startoff, |
302 | xfs_fsblock_t startblock, |
303 | xfs_filblks_t blockcount, |
304 | xfs_exntst_t state) |
305 | { |
306 | int extent_flag = (state == XFS_EXT_NORM) ? 0 : 1; |
307 | |
308 | ASSERT(state == XFS_EXT_NORM || state == XFS_EXT_UNWRITTEN); |
309 | ASSERT((startoff & xfs_mask64hi(64-BMBT_STARTOFF_BITLEN)) == 0); |
310 | ASSERT((blockcount & xfs_mask64hi(64-BMBT_BLOCKCOUNT_BITLEN)) == 0); |
311 | |
312 | #if XFS_BIG_BLKNOS |
313 | ASSERT((startblock & xfs_mask64hi(64-BMBT_STARTBLOCK_BITLEN)) == 0); |
314 | |
315 | r->l0 = cpu_to_be64( |
316 | ((xfs_bmbt_rec_base_t)extent_flag << 63) | |
317 | ((xfs_bmbt_rec_base_t)startoff << 9) | |
318 | ((xfs_bmbt_rec_base_t)startblock >> 43)); |
319 | r->l1 = cpu_to_be64( |
320 | ((xfs_bmbt_rec_base_t)startblock << 21) | |
321 | ((xfs_bmbt_rec_base_t)blockcount & |
322 | (xfs_bmbt_rec_base_t)xfs_mask64lo(21))); |
323 | #else /* !XFS_BIG_BLKNOS */ |
324 | if (isnullstartblock(startblock)) { |
325 | r->l0 = cpu_to_be64( |
326 | ((xfs_bmbt_rec_base_t)extent_flag << 63) | |
327 | ((xfs_bmbt_rec_base_t)startoff << 9) | |
328 | (xfs_bmbt_rec_base_t)xfs_mask64lo(9)); |
329 | r->l1 = cpu_to_be64(xfs_mask64hi(11) | |
330 | ((xfs_bmbt_rec_base_t)startblock << 21) | |
331 | ((xfs_bmbt_rec_base_t)blockcount & |
332 | (xfs_bmbt_rec_base_t)xfs_mask64lo(21))); |
333 | } else { |
334 | r->l0 = cpu_to_be64( |
335 | ((xfs_bmbt_rec_base_t)extent_flag << 63) | |
336 | ((xfs_bmbt_rec_base_t)startoff << 9)); |
337 | r->l1 = cpu_to_be64( |
338 | ((xfs_bmbt_rec_base_t)startblock << 21) | |
339 | ((xfs_bmbt_rec_base_t)blockcount & |
340 | (xfs_bmbt_rec_base_t)xfs_mask64lo(21))); |
341 | } |
342 | #endif /* XFS_BIG_BLKNOS */ |
343 | } |
344 | |
345 | /* |
346 | * Set all the fields in a bmap extent record from the uncompressed form. |
347 | */ |
348 | void |
349 | xfs_bmbt_disk_set_all( |
350 | xfs_bmbt_rec_t *r, |
351 | xfs_bmbt_irec_t *s) |
352 | { |
353 | xfs_bmbt_disk_set_allf(r, s->br_startoff, s->br_startblock, |
354 | s->br_blockcount, s->br_state); |
355 | } |
356 | |
357 | /* |
358 | * Set the blockcount field in a bmap extent record. |
359 | */ |
360 | void |
361 | xfs_bmbt_set_blockcount( |
362 | xfs_bmbt_rec_host_t *r, |
363 | xfs_filblks_t v) |
364 | { |
365 | ASSERT((v & xfs_mask64hi(43)) == 0); |
366 | r->l1 = (r->l1 & (xfs_bmbt_rec_base_t)xfs_mask64hi(43)) | |
367 | (xfs_bmbt_rec_base_t)(v & xfs_mask64lo(21)); |
368 | } |
369 | |
370 | /* |
371 | * Set the startblock field in a bmap extent record. |
372 | */ |
373 | void |
374 | xfs_bmbt_set_startblock( |
375 | xfs_bmbt_rec_host_t *r, |
376 | xfs_fsblock_t v) |
377 | { |
378 | #if XFS_BIG_BLKNOS |
379 | ASSERT((v & xfs_mask64hi(12)) == 0); |
380 | r->l0 = (r->l0 & (xfs_bmbt_rec_base_t)xfs_mask64hi(55)) | |
381 | (xfs_bmbt_rec_base_t)(v >> 43); |
382 | r->l1 = (r->l1 & (xfs_bmbt_rec_base_t)xfs_mask64lo(21)) | |
383 | (xfs_bmbt_rec_base_t)(v << 21); |
384 | #else /* !XFS_BIG_BLKNOS */ |
385 | if (isnullstartblock(v)) { |
386 | r->l0 |= (xfs_bmbt_rec_base_t)xfs_mask64lo(9); |
387 | r->l1 = (xfs_bmbt_rec_base_t)xfs_mask64hi(11) | |
388 | ((xfs_bmbt_rec_base_t)v << 21) | |
389 | (r->l1 & (xfs_bmbt_rec_base_t)xfs_mask64lo(21)); |
390 | } else { |
391 | r->l0 &= ~(xfs_bmbt_rec_base_t)xfs_mask64lo(9); |
392 | r->l1 = ((xfs_bmbt_rec_base_t)v << 21) | |
393 | (r->l1 & (xfs_bmbt_rec_base_t)xfs_mask64lo(21)); |
394 | } |
395 | #endif /* XFS_BIG_BLKNOS */ |
396 | } |
397 | |
398 | /* |
399 | * Set the startoff field in a bmap extent record. |
400 | */ |
401 | void |
402 | xfs_bmbt_set_startoff( |
403 | xfs_bmbt_rec_host_t *r, |
404 | xfs_fileoff_t v) |
405 | { |
406 | ASSERT((v & xfs_mask64hi(9)) == 0); |
407 | r->l0 = (r->l0 & (xfs_bmbt_rec_base_t) xfs_mask64hi(1)) | |
408 | ((xfs_bmbt_rec_base_t)v << 9) | |
409 | (r->l0 & (xfs_bmbt_rec_base_t)xfs_mask64lo(9)); |
410 | } |
411 | |
412 | /* |
413 | * Set the extent state field in a bmap extent record. |
414 | */ |
415 | void |
416 | xfs_bmbt_set_state( |
417 | xfs_bmbt_rec_host_t *r, |
418 | xfs_exntst_t v) |
419 | { |
420 | ASSERT(v == XFS_EXT_NORM || v == XFS_EXT_UNWRITTEN); |
421 | if (v == XFS_EXT_NORM) |
422 | r->l0 &= xfs_mask64lo(64 - BMBT_EXNTFLAG_BITLEN); |
423 | else |
424 | r->l0 |= xfs_mask64hi(BMBT_EXNTFLAG_BITLEN); |
425 | } |
426 | |
427 | /* |
428 | * Convert in-memory form of btree root to on-disk form. |
429 | */ |
430 | void |
431 | xfs_bmbt_to_bmdr( |
432 | struct xfs_mount *mp, |
433 | struct xfs_btree_block *rblock, |
434 | int rblocklen, |
435 | xfs_bmdr_block_t *dblock, |
436 | int dblocklen) |
437 | { |
438 | int dmxr; |
439 | xfs_bmbt_key_t *fkp; |
440 | __be64 *fpp; |
441 | xfs_bmbt_key_t *tkp; |
442 | __be64 *tpp; |
443 | |
444 | ASSERT(be32_to_cpu(rblock->bb_magic) == XFS_BMAP_MAGIC); |
445 | ASSERT(be64_to_cpu(rblock->bb_u.l.bb_leftsib) == NULLDFSBNO); |
446 | ASSERT(be64_to_cpu(rblock->bb_u.l.bb_rightsib) == NULLDFSBNO); |
447 | ASSERT(be16_to_cpu(rblock->bb_level) > 0); |
448 | dblock->bb_level = rblock->bb_level; |
449 | dblock->bb_numrecs = rblock->bb_numrecs; |
450 | dmxr = xfs_bmdr_maxrecs(mp, dblocklen, 0); |
451 | fkp = XFS_BMBT_KEY_ADDR(mp, rblock, 1); |
452 | tkp = XFS_BMDR_KEY_ADDR(dblock, 1); |
453 | fpp = XFS_BMAP_BROOT_PTR_ADDR(mp, rblock, 1, rblocklen); |
454 | tpp = XFS_BMDR_PTR_ADDR(dblock, 1, dmxr); |
455 | dmxr = be16_to_cpu(dblock->bb_numrecs); |
456 | memcpy(tkp, fkp, sizeof(*fkp) * dmxr); |
457 | memcpy(tpp, fpp, sizeof(*fpp) * dmxr); |
458 | } |
459 | |
460 | /* |
461 | * Check extent records, which have just been read, for |
462 | * any bit in the extent flag field. ASSERT on debug |
463 | * kernels, as this condition should not occur. |
464 | * Return an error condition (1) if any flags found, |
465 | * otherwise return 0. |
466 | */ |
467 | |
468 | int |
469 | xfs_check_nostate_extents( |
470 | xfs_ifork_t *ifp, |
471 | xfs_extnum_t idx, |
472 | xfs_extnum_t num) |
473 | { |
474 | for (; num > 0; num--, idx++) { |
475 | xfs_bmbt_rec_host_t *ep = xfs_iext_get_ext(ifp, idx); |
476 | if ((ep->l0 >> |
477 | (64 - BMBT_EXNTFLAG_BITLEN)) != 0) { |
478 | ASSERT(0); |
479 | return 1; |
480 | } |
481 | } |
482 | return 0; |
483 | } |
484 | |
485 | |
486 | STATIC struct xfs_btree_cur * |
487 | xfs_bmbt_dup_cursor( |
488 | struct xfs_btree_cur *cur) |
489 | { |
490 | struct xfs_btree_cur *new; |
491 | |
492 | new = xfs_bmbt_init_cursor(cur->bc_mp, cur->bc_tp, |
493 | cur->bc_private.b.ip, cur->bc_private.b.whichfork); |
494 | |
495 | /* |
496 | * Copy the firstblock, flist, and flags values, |
497 | * since init cursor doesn't get them. |
498 | */ |
499 | new->bc_private.b.firstblock = cur->bc_private.b.firstblock; |
500 | new->bc_private.b.flist = cur->bc_private.b.flist; |
501 | new->bc_private.b.flags = cur->bc_private.b.flags; |
502 | |
503 | return new; |
504 | } |
505 | |
506 | STATIC void |
507 | xfs_bmbt_update_cursor( |
508 | struct xfs_btree_cur *src, |
509 | struct xfs_btree_cur *dst) |
510 | { |
511 | ASSERT((dst->bc_private.b.firstblock != NULLFSBLOCK) || |
512 | (dst->bc_private.b.ip->i_d.di_flags & XFS_DIFLAG_REALTIME)); |
513 | ASSERT(dst->bc_private.b.flist == src->bc_private.b.flist); |
514 | |
515 | dst->bc_private.b.allocated += src->bc_private.b.allocated; |
516 | dst->bc_private.b.firstblock = src->bc_private.b.firstblock; |
517 | |
518 | src->bc_private.b.allocated = 0; |
519 | } |
520 | |
521 | STATIC int |
522 | xfs_bmbt_alloc_block( |
523 | struct xfs_btree_cur *cur, |
524 | union xfs_btree_ptr *start, |
525 | union xfs_btree_ptr *new, |
526 | int length, |
527 | int *stat) |
528 | { |
529 | xfs_alloc_arg_t args; /* block allocation args */ |
530 | int error; /* error return value */ |
531 | |
532 | memset(&args, 0, sizeof(args)); |
533 | args.tp = cur->bc_tp; |
534 | args.mp = cur->bc_mp; |
535 | args.fsbno = cur->bc_private.b.firstblock; |
536 | args.firstblock = args.fsbno; |
537 | |
538 | if (args.fsbno == NULLFSBLOCK) { |
539 | args.fsbno = be64_to_cpu(start->l); |
540 | args.type = XFS_ALLOCTYPE_START_BNO; |
541 | /* |
542 | * Make sure there is sufficient room left in the AG to |
543 | * complete a full tree split for an extent insert. If |
544 | * we are converting the middle part of an extent then |
545 | * we may need space for two tree splits. |
546 | * |
547 | * We are relying on the caller to make the correct block |
548 | * reservation for this operation to succeed. If the |
549 | * reservation amount is insufficient then we may fail a |
550 | * block allocation here and corrupt the filesystem. |
551 | */ |
552 | args.minleft = xfs_trans_get_block_res(args.tp); |
553 | } else if (cur->bc_private.b.flist->xbf_low) { |
554 | args.type = XFS_ALLOCTYPE_START_BNO; |
555 | } else { |
556 | args.type = XFS_ALLOCTYPE_NEAR_BNO; |
557 | } |
558 | |
559 | args.minlen = args.maxlen = args.prod = 1; |
560 | args.wasdel = cur->bc_private.b.flags & XFS_BTCUR_BPRV_WASDEL; |
561 | if (!args.wasdel && xfs_trans_get_block_res(args.tp) == 0) { |
562 | error = XFS_ERROR(ENOSPC); |
563 | goto error0; |
564 | } |
565 | error = xfs_alloc_vextent(&args); |
566 | if (error) |
567 | goto error0; |
568 | |
569 | if (args.fsbno == NULLFSBLOCK && args.minleft) { |
570 | /* |
571 | * Could not find an AG with enough free space to satisfy |
572 | * a full btree split. Try again without minleft and if |
573 | * successful activate the lowspace algorithm. |
574 | */ |
575 | args.fsbno = 0; |
576 | args.type = XFS_ALLOCTYPE_FIRST_AG; |
577 | args.minleft = 0; |
578 | error = xfs_alloc_vextent(&args); |
579 | if (error) |
580 | goto error0; |
581 | cur->bc_private.b.flist->xbf_low = 1; |
582 | } |
583 | if (args.fsbno == NULLFSBLOCK) { |
584 | XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); |
585 | *stat = 0; |
586 | return 0; |
587 | } |
588 | ASSERT(args.len == 1); |
589 | cur->bc_private.b.firstblock = args.fsbno; |
590 | cur->bc_private.b.allocated++; |
591 | cur->bc_private.b.ip->i_d.di_nblocks++; |
592 | xfs_trans_log_inode(args.tp, cur->bc_private.b.ip, XFS_ILOG_CORE); |
593 | xfs_trans_mod_dquot_byino(args.tp, cur->bc_private.b.ip, |
594 | XFS_TRANS_DQ_BCOUNT, 1L); |
595 | |
596 | new->l = cpu_to_be64(args.fsbno); |
597 | |
598 | XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); |
599 | *stat = 1; |
600 | return 0; |
601 | |
602 | error0: |
603 | XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR); |
604 | return error; |
605 | } |
606 | |
607 | STATIC int |
608 | xfs_bmbt_free_block( |
609 | struct xfs_btree_cur *cur, |
610 | struct xfs_buf *bp) |
611 | { |
612 | struct xfs_mount *mp = cur->bc_mp; |
613 | struct xfs_inode *ip = cur->bc_private.b.ip; |
614 | struct xfs_trans *tp = cur->bc_tp; |
615 | xfs_fsblock_t fsbno = XFS_DADDR_TO_FSB(mp, XFS_BUF_ADDR(bp)); |
616 | |
617 | xfs_bmap_add_free(fsbno, 1, cur->bc_private.b.flist, mp); |
618 | ip->i_d.di_nblocks--; |
619 | |
620 | xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); |
621 | xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_BCOUNT, -1L); |
622 | xfs_trans_binval(tp, bp); |
623 | return 0; |
624 | } |
625 | |
626 | STATIC int |
627 | xfs_bmbt_get_minrecs( |
628 | struct xfs_btree_cur *cur, |
629 | int level) |
630 | { |
631 | if (level == cur->bc_nlevels - 1) { |
632 | struct xfs_ifork *ifp; |
633 | |
634 | ifp = XFS_IFORK_PTR(cur->bc_private.b.ip, |
635 | cur->bc_private.b.whichfork); |
636 | |
637 | return xfs_bmbt_maxrecs(cur->bc_mp, |
638 | ifp->if_broot_bytes, level == 0) / 2; |
639 | } |
640 | |
641 | return cur->bc_mp->m_bmap_dmnr[level != 0]; |
642 | } |
643 | |
644 | int |
645 | xfs_bmbt_get_maxrecs( |
646 | struct xfs_btree_cur *cur, |
647 | int level) |
648 | { |
649 | if (level == cur->bc_nlevels - 1) { |
650 | struct xfs_ifork *ifp; |
651 | |
652 | ifp = XFS_IFORK_PTR(cur->bc_private.b.ip, |
653 | cur->bc_private.b.whichfork); |
654 | |
655 | return xfs_bmbt_maxrecs(cur->bc_mp, |
656 | ifp->if_broot_bytes, level == 0); |
657 | } |
658 | |
659 | return cur->bc_mp->m_bmap_dmxr[level != 0]; |
660 | |
661 | } |
662 | |
663 | /* |
664 | * Get the maximum records we could store in the on-disk format. |
665 | * |
666 | * For non-root nodes this is equivalent to xfs_bmbt_get_maxrecs, but |
667 | * for the root node this checks the available space in the dinode fork |
668 | * so that we can resize the in-memory buffer to match it. After a |
669 | * resize to the maximum size this function returns the same value |
670 | * as xfs_bmbt_get_maxrecs for the root node, too. |
671 | */ |
672 | STATIC int |
673 | xfs_bmbt_get_dmaxrecs( |
674 | struct xfs_btree_cur *cur, |
675 | int level) |
676 | { |
677 | if (level != cur->bc_nlevels - 1) |
678 | return cur->bc_mp->m_bmap_dmxr[level != 0]; |
679 | return xfs_bmdr_maxrecs(cur->bc_mp, cur->bc_private.b.forksize, |
680 | level == 0); |
681 | } |
682 | |
683 | STATIC void |
684 | xfs_bmbt_init_key_from_rec( |
685 | union xfs_btree_key *key, |
686 | union xfs_btree_rec *rec) |
687 | { |
688 | key->bmbt.br_startoff = |
689 | cpu_to_be64(xfs_bmbt_disk_get_startoff(&rec->bmbt)); |
690 | } |
691 | |
692 | STATIC void |
693 | xfs_bmbt_init_rec_from_key( |
694 | union xfs_btree_key *key, |
695 | union xfs_btree_rec *rec) |
696 | { |
697 | ASSERT(key->bmbt.br_startoff != 0); |
698 | |
699 | xfs_bmbt_disk_set_allf(&rec->bmbt, be64_to_cpu(key->bmbt.br_startoff), |
700 | 0, 0, XFS_EXT_NORM); |
701 | } |
702 | |
703 | STATIC void |
704 | xfs_bmbt_init_rec_from_cur( |
705 | struct xfs_btree_cur *cur, |
706 | union xfs_btree_rec *rec) |
707 | { |
708 | xfs_bmbt_disk_set_all(&rec->bmbt, &cur->bc_rec.b); |
709 | } |
710 | |
711 | STATIC void |
712 | xfs_bmbt_init_ptr_from_cur( |
713 | struct xfs_btree_cur *cur, |
714 | union xfs_btree_ptr *ptr) |
715 | { |
716 | ptr->l = 0; |
717 | } |
718 | |
719 | STATIC __int64_t |
720 | xfs_bmbt_key_diff( |
721 | struct xfs_btree_cur *cur, |
722 | union xfs_btree_key *key) |
723 | { |
724 | return (__int64_t)be64_to_cpu(key->bmbt.br_startoff) - |
725 | cur->bc_rec.b.br_startoff; |
726 | } |
727 | |
728 | #ifdef DEBUG |
729 | STATIC int |
730 | xfs_bmbt_keys_inorder( |
731 | struct xfs_btree_cur *cur, |
732 | union xfs_btree_key *k1, |
733 | union xfs_btree_key *k2) |
734 | { |
735 | return be64_to_cpu(k1->bmbt.br_startoff) < |
736 | be64_to_cpu(k2->bmbt.br_startoff); |
737 | } |
738 | |
739 | STATIC int |
740 | xfs_bmbt_recs_inorder( |
741 | struct xfs_btree_cur *cur, |
742 | union xfs_btree_rec *r1, |
743 | union xfs_btree_rec *r2) |
744 | { |
745 | return xfs_bmbt_disk_get_startoff(&r1->bmbt) + |
746 | xfs_bmbt_disk_get_blockcount(&r1->bmbt) <= |
747 | xfs_bmbt_disk_get_startoff(&r2->bmbt); |
748 | } |
749 | #endif /* DEBUG */ |
750 | |
751 | #ifdef XFS_BTREE_TRACE |
752 | ktrace_t *xfs_bmbt_trace_buf; |
753 | |
754 | STATIC void |
755 | xfs_bmbt_trace_enter( |
756 | struct xfs_btree_cur *cur, |
757 | const char *func, |
758 | char *s, |
759 | int type, |
760 | int line, |
761 | __psunsigned_t a0, |
762 | __psunsigned_t a1, |
763 | __psunsigned_t a2, |
764 | __psunsigned_t a3, |
765 | __psunsigned_t a4, |
766 | __psunsigned_t a5, |
767 | __psunsigned_t a6, |
768 | __psunsigned_t a7, |
769 | __psunsigned_t a8, |
770 | __psunsigned_t a9, |
771 | __psunsigned_t a10) |
772 | { |
773 | struct xfs_inode *ip = cur->bc_private.b.ip; |
774 | int whichfork = cur->bc_private.b.whichfork; |
775 | |
776 | ktrace_enter(xfs_bmbt_trace_buf, |
777 | (void *)((__psint_t)type | (whichfork << 8) | (line << 16)), |
778 | (void *)func, (void *)s, (void *)ip, (void *)cur, |
779 | (void *)a0, (void *)a1, (void *)a2, (void *)a3, |
780 | (void *)a4, (void *)a5, (void *)a6, (void *)a7, |
781 | (void *)a8, (void *)a9, (void *)a10); |
782 | ktrace_enter(ip->i_btrace, |
783 | (void *)((__psint_t)type | (whichfork << 8) | (line << 16)), |
784 | (void *)func, (void *)s, (void *)ip, (void *)cur, |
785 | (void *)a0, (void *)a1, (void *)a2, (void *)a3, |
786 | (void *)a4, (void *)a5, (void *)a6, (void *)a7, |
787 | (void *)a8, (void *)a9, (void *)a10); |
788 | } |
789 | |
790 | STATIC void |
791 | xfs_bmbt_trace_cursor( |
792 | struct xfs_btree_cur *cur, |
793 | __uint32_t *s0, |
794 | __uint64_t *l0, |
795 | __uint64_t *l1) |
796 | { |
797 | struct xfs_bmbt_rec_host r; |
798 | |
799 | xfs_bmbt_set_all(&r, &cur->bc_rec.b); |
800 | |
801 | *s0 = (cur->bc_nlevels << 24) | |
802 | (cur->bc_private.b.flags << 16) | |
803 | cur->bc_private.b.allocated; |
804 | *l0 = r.l0; |
805 | *l1 = r.l1; |
806 | } |
807 | |
808 | STATIC void |
809 | xfs_bmbt_trace_key( |
810 | struct xfs_btree_cur *cur, |
811 | union xfs_btree_key *key, |
812 | __uint64_t *l0, |
813 | __uint64_t *l1) |
814 | { |
815 | *l0 = be64_to_cpu(key->bmbt.br_startoff); |
816 | *l1 = 0; |
817 | } |
818 | |
819 | STATIC void |
820 | xfs_bmbt_trace_record( |
821 | struct xfs_btree_cur *cur, |
822 | union xfs_btree_rec *rec, |
823 | __uint64_t *l0, |
824 | __uint64_t *l1, |
825 | __uint64_t *l2) |
826 | { |
827 | struct xfs_bmbt_irec irec; |
828 | |
829 | xfs_bmbt_disk_get_all(&rec->bmbt, &irec); |
830 | *l0 = irec.br_startoff; |
831 | *l1 = irec.br_startblock; |
832 | *l2 = irec.br_blockcount; |
833 | } |
834 | #endif /* XFS_BTREE_TRACE */ |
835 | |
836 | static const struct xfs_btree_ops xfs_bmbt_ops = { |
837 | .rec_len = sizeof(xfs_bmbt_rec_t), |
838 | .key_len = sizeof(xfs_bmbt_key_t), |
839 | |
840 | .dup_cursor = xfs_bmbt_dup_cursor, |
841 | .update_cursor = xfs_bmbt_update_cursor, |
842 | .alloc_block = xfs_bmbt_alloc_block, |
843 | .free_block = xfs_bmbt_free_block, |
844 | .get_maxrecs = xfs_bmbt_get_maxrecs, |
845 | .get_minrecs = xfs_bmbt_get_minrecs, |
846 | .get_dmaxrecs = xfs_bmbt_get_dmaxrecs, |
847 | .init_key_from_rec = xfs_bmbt_init_key_from_rec, |
848 | .init_rec_from_key = xfs_bmbt_init_rec_from_key, |
849 | .init_rec_from_cur = xfs_bmbt_init_rec_from_cur, |
850 | .init_ptr_from_cur = xfs_bmbt_init_ptr_from_cur, |
851 | .key_diff = xfs_bmbt_key_diff, |
852 | |
853 | #ifdef DEBUG |
854 | .keys_inorder = xfs_bmbt_keys_inorder, |
855 | .recs_inorder = xfs_bmbt_recs_inorder, |
856 | #endif |
857 | |
858 | #ifdef XFS_BTREE_TRACE |
859 | .trace_enter = xfs_bmbt_trace_enter, |
860 | .trace_cursor = xfs_bmbt_trace_cursor, |
861 | .trace_key = xfs_bmbt_trace_key, |
862 | .trace_record = xfs_bmbt_trace_record, |
863 | #endif |
864 | }; |
865 | |
866 | /* |
867 | * Allocate a new bmap btree cursor. |
868 | */ |
869 | struct xfs_btree_cur * /* new bmap btree cursor */ |
870 | xfs_bmbt_init_cursor( |
871 | struct xfs_mount *mp, /* file system mount point */ |
872 | struct xfs_trans *tp, /* transaction pointer */ |
873 | struct xfs_inode *ip, /* inode owning the btree */ |
874 | int whichfork) /* data or attr fork */ |
875 | { |
876 | struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, whichfork); |
877 | struct xfs_btree_cur *cur; |
878 | |
879 | cur = kmem_zone_zalloc(xfs_btree_cur_zone, KM_SLEEP); |
880 | |
881 | cur->bc_tp = tp; |
882 | cur->bc_mp = mp; |
883 | cur->bc_nlevels = be16_to_cpu(ifp->if_broot->bb_level) + 1; |
884 | cur->bc_btnum = XFS_BTNUM_BMAP; |
885 | cur->bc_blocklog = mp->m_sb.sb_blocklog; |
886 | |
887 | cur->bc_ops = &xfs_bmbt_ops; |
888 | cur->bc_flags = XFS_BTREE_LONG_PTRS | XFS_BTREE_ROOT_IN_INODE; |
889 | |
890 | cur->bc_private.b.forksize = XFS_IFORK_SIZE(ip, whichfork); |
891 | cur->bc_private.b.ip = ip; |
892 | cur->bc_private.b.firstblock = NULLFSBLOCK; |
893 | cur->bc_private.b.flist = NULL; |
894 | cur->bc_private.b.allocated = 0; |
895 | cur->bc_private.b.flags = 0; |
896 | cur->bc_private.b.whichfork = whichfork; |
897 | |
898 | return cur; |
899 | } |
900 | |
901 | /* |
902 | * Calculate number of records in a bmap btree block. |
903 | */ |
904 | int |
905 | xfs_bmbt_maxrecs( |
906 | struct xfs_mount *mp, |
907 | int blocklen, |
908 | int leaf) |
909 | { |
910 | blocklen -= XFS_BMBT_BLOCK_LEN(mp); |
911 | |
912 | if (leaf) |
913 | return blocklen / sizeof(xfs_bmbt_rec_t); |
914 | return blocklen / (sizeof(xfs_bmbt_key_t) + sizeof(xfs_bmbt_ptr_t)); |
915 | } |
916 | |
917 | /* |
918 | * Calculate number of records in a bmap btree inode root. |
919 | */ |
920 | int |
921 | xfs_bmdr_maxrecs( |
922 | struct xfs_mount *mp, |
923 | int blocklen, |
924 | int leaf) |
925 | { |
926 | blocklen -= sizeof(xfs_bmdr_block_t); |
927 | |
928 | if (leaf) |
929 | return blocklen / sizeof(xfs_bmdr_rec_t); |
930 | return blocklen / (sizeof(xfs_bmdr_key_t) + sizeof(xfs_bmdr_ptr_t)); |
931 | } |
932 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9