blob: 6c0a07d1fed37dca66d0f395162791dd849f3359 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Nathan Scott7b718762005-11-02 14:58:39 +11002 * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc.
3 * All Rights Reserved.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004 *
Nathan Scott7b718762005-11-02 14:58:39 +11005 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 * published by the Free Software Foundation.
8 *
Nathan Scott7b718762005-11-02 14:58:39 +11009 * 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.
Linus Torvalds1da177e2005-04-16 15:20:36 -070013 *
Nathan Scott7b718762005-11-02 14:58:39 +110014 * 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
Linus Torvalds1da177e2005-04-16 15:20:36 -070017 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070018#include "xfs.h"
Nathan Scotta844f452005-11-02 14:38:42 +110019#include "xfs_fs.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070020#include "xfs_types.h"
Nathan Scotta844f452005-11-02 14:38:42 +110021#include "xfs_bit.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070022#include "xfs_log.h"
Nathan Scotta844f452005-11-02 14:38:42 +110023#include "xfs_inum.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070024#include "xfs_trans.h"
25#include "xfs_sb.h"
26#include "xfs_ag.h"
Nathan Scotta844f452005-11-02 14:38:42 +110027#include "xfs_dir2.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070028#include "xfs_dmapi.h"
29#include "xfs_mount.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070030#include "xfs_bmap_btree.h"
Nathan Scotta844f452005-11-02 14:38:42 +110031#include "xfs_alloc_btree.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#include "xfs_ialloc_btree.h"
Nathan Scotta844f452005-11-02 14:38:42 +110033#include "xfs_dir2_sf.h"
34#include "xfs_attr_sf.h"
35#include "xfs_dinode.h"
36#include "xfs_inode.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070037#include "xfs_btree.h"
Christoph Hellwigf5eb8e72008-10-30 16:57:03 +110038#include "xfs_btree_trace.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070039#include "xfs_ialloc.h"
40#include "xfs_alloc.h"
41#include "xfs_error.h"
42
Linus Torvalds1da177e2005-04-16 15:20:36 -070043
44/*
45 * Get the data from the pointed-to record.
46 */
47int /* error */
48xfs_inobt_get_rec(
49 xfs_btree_cur_t *cur, /* btree cursor */
50 xfs_agino_t *ino, /* output: starting inode of chunk */
51 __int32_t *fcnt, /* output: number of free inodes */
52 xfs_inofree_t *free, /* output: free inode mask */
53 int *stat) /* output: success/failure */
54{
55 xfs_inobt_block_t *block; /* btree block */
56 xfs_buf_t *bp; /* buffer containing btree block */
57#ifdef DEBUG
58 int error; /* error return value */
59#endif
60 int ptr; /* record number */
61 xfs_inobt_rec_t *rec; /* record data */
62
63 bp = cur->bc_bufs[0];
64 ptr = cur->bc_ptrs[0];
65 block = XFS_BUF_TO_INOBT_BLOCK(bp);
66#ifdef DEBUG
67 if ((error = xfs_btree_check_sblock(cur, block, 0, bp)))
68 return error;
69#endif
70 /*
71 * Off the right end or left end, return failure.
72 */
Christoph Hellwig16259e72005-11-02 15:11:25 +110073 if (ptr > be16_to_cpu(block->bb_numrecs) || ptr <= 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070074 *stat = 0;
75 return 0;
76 }
77 /*
78 * Point to the record and extract its data.
79 */
80 rec = XFS_INOBT_REC_ADDR(block, ptr, cur);
Christoph Hellwig61a25842006-09-28 10:57:04 +100081 *ino = be32_to_cpu(rec->ir_startino);
82 *fcnt = be32_to_cpu(rec->ir_freecount);
83 *free = be64_to_cpu(rec->ir_free);
Linus Torvalds1da177e2005-04-16 15:20:36 -070084 *stat = 1;
85 return 0;
86}
87
Christoph Hellwig91cca5d2008-10-30 16:58:01 +110088STATIC int
89xfs_inobt_get_minrecs(
90 struct xfs_btree_cur *cur,
91 int level)
92{
93 return cur->bc_mp->m_inobt_mnr[level != 0];
94}
Linus Torvalds1da177e2005-04-16 15:20:36 -070095
Christoph Hellwig561f7d12008-10-30 16:53:59 +110096STATIC struct xfs_btree_cur *
97xfs_inobt_dup_cursor(
98 struct xfs_btree_cur *cur)
99{
100 return xfs_inobt_init_cursor(cur->bc_mp, cur->bc_tp,
101 cur->bc_private.a.agbp, cur->bc_private.a.agno);
102}
103
Christoph Hellwig344207c2008-10-30 16:57:16 +1100104STATIC void
105xfs_inobt_set_root(
106 struct xfs_btree_cur *cur,
107 union xfs_btree_ptr *nptr,
108 int inc) /* level change */
109{
110 struct xfs_buf *agbp = cur->bc_private.a.agbp;
111 struct xfs_agi *agi = XFS_BUF_TO_AGI(agbp);
112
113 agi->agi_root = nptr->s;
114 be32_add_cpu(&agi->agi_level, inc);
115 xfs_ialloc_log_agi(cur->bc_tp, agbp, XFS_AGI_ROOT | XFS_AGI_LEVEL);
116}
117
Christoph Hellwigce5e42d2008-10-30 16:55:23 +1100118STATIC int
Christoph Hellwigf5eb8e72008-10-30 16:57:03 +1100119xfs_inobt_alloc_block(
120 struct xfs_btree_cur *cur,
121 union xfs_btree_ptr *start,
122 union xfs_btree_ptr *new,
123 int length,
124 int *stat)
125{
126 xfs_alloc_arg_t args; /* block allocation args */
127 int error; /* error return value */
128 xfs_agblock_t sbno = be32_to_cpu(start->s);
129
130 XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY);
131
132 memset(&args, 0, sizeof(args));
133 args.tp = cur->bc_tp;
134 args.mp = cur->bc_mp;
135 args.fsbno = XFS_AGB_TO_FSB(args.mp, cur->bc_private.a.agno, sbno);
136 args.minlen = 1;
137 args.maxlen = 1;
138 args.prod = 1;
139 args.type = XFS_ALLOCTYPE_NEAR_BNO;
140
141 error = xfs_alloc_vextent(&args);
142 if (error) {
143 XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR);
144 return error;
145 }
146 if (args.fsbno == NULLFSBLOCK) {
147 XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
148 *stat = 0;
149 return 0;
150 }
151 ASSERT(args.len == 1);
152 XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
153
154 new->s = cpu_to_be32(XFS_FSB_TO_AGBNO(args.mp, args.fsbno));
155 *stat = 1;
156 return 0;
157}
158
Christoph Hellwigd4b3a4b2008-10-30 16:57:51 +1100159STATIC int
160xfs_inobt_free_block(
161 struct xfs_btree_cur *cur,
162 struct xfs_buf *bp)
163{
164 xfs_fsblock_t fsbno;
165 int error;
166
167 fsbno = XFS_DADDR_TO_FSB(cur->bc_mp, XFS_BUF_ADDR(bp));
168 error = xfs_free_extent(cur->bc_tp, fsbno, 1);
169 if (error)
170 return error;
171
172 xfs_trans_binval(cur->bc_tp, bp);
173 return error;
174}
Christoph Hellwigf5eb8e72008-10-30 16:57:03 +1100175
176STATIC int
Christoph Hellwigce5e42d2008-10-30 16:55:23 +1100177xfs_inobt_get_maxrecs(
178 struct xfs_btree_cur *cur,
179 int level)
180{
181 return cur->bc_mp->m_inobt_mxr[level != 0];
182}
183
Christoph Hellwigfe033cc2008-10-30 16:56:09 +1100184STATIC void
185xfs_inobt_init_key_from_rec(
186 union xfs_btree_key *key,
187 union xfs_btree_rec *rec)
188{
189 key->inobt.ir_startino = rec->inobt.ir_startino;
190}
191
Christoph Hellwig4b22a572008-10-30 16:57:40 +1100192STATIC void
193xfs_inobt_init_rec_from_key(
194 union xfs_btree_key *key,
195 union xfs_btree_rec *rec)
196{
197 rec->inobt.ir_startino = key->inobt.ir_startino;
198}
199
200STATIC void
201xfs_inobt_init_rec_from_cur(
202 struct xfs_btree_cur *cur,
203 union xfs_btree_rec *rec)
204{
205 rec->inobt.ir_startino = cpu_to_be32(cur->bc_rec.i.ir_startino);
206 rec->inobt.ir_freecount = cpu_to_be32(cur->bc_rec.i.ir_freecount);
207 rec->inobt.ir_free = cpu_to_be64(cur->bc_rec.i.ir_free);
208}
209
Christoph Hellwigfe033cc2008-10-30 16:56:09 +1100210/*
211 * intial value of ptr for lookup
212 */
213STATIC void
214xfs_inobt_init_ptr_from_cur(
215 struct xfs_btree_cur *cur,
216 union xfs_btree_ptr *ptr)
217{
218 struct xfs_agi *agi = XFS_BUF_TO_AGI(cur->bc_private.a.agbp);
219
220 ASSERT(cur->bc_private.a.agno == be32_to_cpu(agi->agi_seqno));
221
222 ptr->s = agi->agi_root;
223}
224
225STATIC __int64_t
226xfs_inobt_key_diff(
227 struct xfs_btree_cur *cur,
228 union xfs_btree_key *key)
229{
230 return (__int64_t)be32_to_cpu(key->inobt.ir_startino) -
231 cur->bc_rec.i.ir_startino;
232}
233
Christoph Hellwig91cca5d2008-10-30 16:58:01 +1100234STATIC int
235xfs_inobt_kill_root(
236 struct xfs_btree_cur *cur,
237 struct xfs_buf *bp,
238 int level,
239 union xfs_btree_ptr *newroot)
240{
241 int error;
242
243 XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY);
244 XFS_BTREE_STATS_INC(cur, killroot);
245
246 /*
247 * Update the root pointer, decreasing the level by 1 and then
248 * free the old root.
249 */
250 xfs_inobt_set_root(cur, newroot, -1);
251 error = xfs_inobt_free_block(cur, bp);
252 if (error) {
253 XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR);
254 return error;
255 }
256
257 XFS_BTREE_STATS_INC(cur, free);
258
259 cur->bc_bufs[level] = NULL;
260 cur->bc_nlevels--;
261
262 XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
263 return 0;
264}
265
Christoph Hellwig8c4ed632008-10-30 16:55:13 +1100266#ifdef XFS_BTREE_TRACE
267ktrace_t *xfs_inobt_trace_buf;
268
269STATIC void
270xfs_inobt_trace_enter(
271 struct xfs_btree_cur *cur,
272 const char *func,
273 char *s,
274 int type,
275 int line,
276 __psunsigned_t a0,
277 __psunsigned_t a1,
278 __psunsigned_t a2,
279 __psunsigned_t a3,
280 __psunsigned_t a4,
281 __psunsigned_t a5,
282 __psunsigned_t a6,
283 __psunsigned_t a7,
284 __psunsigned_t a8,
285 __psunsigned_t a9,
286 __psunsigned_t a10)
287{
288 ktrace_enter(xfs_inobt_trace_buf, (void *)(__psint_t)type,
289 (void *)func, (void *)s, NULL, (void *)cur,
290 (void *)a0, (void *)a1, (void *)a2, (void *)a3,
291 (void *)a4, (void *)a5, (void *)a6, (void *)a7,
292 (void *)a8, (void *)a9, (void *)a10);
293}
294
295STATIC void
296xfs_inobt_trace_cursor(
297 struct xfs_btree_cur *cur,
298 __uint32_t *s0,
299 __uint64_t *l0,
300 __uint64_t *l1)
301{
302 *s0 = cur->bc_private.a.agno;
303 *l0 = cur->bc_rec.i.ir_startino;
304 *l1 = cur->bc_rec.i.ir_free;
305}
306
307STATIC void
308xfs_inobt_trace_key(
309 struct xfs_btree_cur *cur,
310 union xfs_btree_key *key,
311 __uint64_t *l0,
312 __uint64_t *l1)
313{
314 *l0 = be32_to_cpu(key->inobt.ir_startino);
315 *l1 = 0;
316}
317
318STATIC void
319xfs_inobt_trace_record(
320 struct xfs_btree_cur *cur,
321 union xfs_btree_rec *rec,
322 __uint64_t *l0,
323 __uint64_t *l1,
324 __uint64_t *l2)
325{
326 *l0 = be32_to_cpu(rec->inobt.ir_startino);
327 *l1 = be32_to_cpu(rec->inobt.ir_freecount);
328 *l2 = be64_to_cpu(rec->inobt.ir_free);
329}
330#endif /* XFS_BTREE_TRACE */
331
Christoph Hellwig561f7d12008-10-30 16:53:59 +1100332static const struct xfs_btree_ops xfs_inobt_ops = {
Christoph Hellwig65f1eae2008-10-30 16:55:34 +1100333 .rec_len = sizeof(xfs_inobt_rec_t),
334 .key_len = sizeof(xfs_inobt_key_t),
335
Christoph Hellwig561f7d12008-10-30 16:53:59 +1100336 .dup_cursor = xfs_inobt_dup_cursor,
Christoph Hellwig344207c2008-10-30 16:57:16 +1100337 .set_root = xfs_inobt_set_root,
Christoph Hellwig91cca5d2008-10-30 16:58:01 +1100338 .kill_root = xfs_inobt_kill_root,
Christoph Hellwigf5eb8e72008-10-30 16:57:03 +1100339 .alloc_block = xfs_inobt_alloc_block,
Christoph Hellwigd4b3a4b2008-10-30 16:57:51 +1100340 .free_block = xfs_inobt_free_block,
Christoph Hellwig91cca5d2008-10-30 16:58:01 +1100341 .get_minrecs = xfs_inobt_get_minrecs,
Christoph Hellwigce5e42d2008-10-30 16:55:23 +1100342 .get_maxrecs = xfs_inobt_get_maxrecs,
Christoph Hellwigfe033cc2008-10-30 16:56:09 +1100343 .init_key_from_rec = xfs_inobt_init_key_from_rec,
Christoph Hellwig4b22a572008-10-30 16:57:40 +1100344 .init_rec_from_key = xfs_inobt_init_rec_from_key,
345 .init_rec_from_cur = xfs_inobt_init_rec_from_cur,
Christoph Hellwigfe033cc2008-10-30 16:56:09 +1100346 .init_ptr_from_cur = xfs_inobt_init_ptr_from_cur,
347 .key_diff = xfs_inobt_key_diff,
Christoph Hellwig8c4ed632008-10-30 16:55:13 +1100348
349#ifdef XFS_BTREE_TRACE
350 .trace_enter = xfs_inobt_trace_enter,
351 .trace_cursor = xfs_inobt_trace_cursor,
352 .trace_key = xfs_inobt_trace_key,
353 .trace_record = xfs_inobt_trace_record,
354#endif
Christoph Hellwig561f7d12008-10-30 16:53:59 +1100355};
356
357/*
358 * Allocate a new inode btree cursor.
359 */
360struct xfs_btree_cur * /* new inode btree cursor */
361xfs_inobt_init_cursor(
362 struct xfs_mount *mp, /* file system mount point */
363 struct xfs_trans *tp, /* transaction pointer */
364 struct xfs_buf *agbp, /* buffer for agi structure */
365 xfs_agnumber_t agno) /* allocation group number */
366{
367 struct xfs_agi *agi = XFS_BUF_TO_AGI(agbp);
368 struct xfs_btree_cur *cur;
369
370 cur = kmem_zone_zalloc(xfs_btree_cur_zone, KM_SLEEP);
371
372 cur->bc_tp = tp;
373 cur->bc_mp = mp;
374 cur->bc_nlevels = be32_to_cpu(agi->agi_level);
375 cur->bc_btnum = XFS_BTNUM_INO;
376 cur->bc_blocklog = mp->m_sb.sb_blocklog;
377
378 cur->bc_ops = &xfs_inobt_ops;
379
380 cur->bc_private.a.agbp = agbp;
381 cur->bc_private.a.agno = agno;
382
383 return cur;
384}