]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - libxfs/util.c
63b5f677a5c50c6806912d33846d4f4b73da2ac0
[thirdparty/xfsprogs-dev.git] / libxfs / util.c
1 /*
2 * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of version 2 of the GNU General Public License as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it would be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11 *
12 * Further, this software is distributed without any warranty that it is
13 * free of the rightful claim of any third person regarding infringement
14 * or the like. Any license provided herein, whether implied or
15 * otherwise, applies only to this software file. Patent licenses, if
16 * any, provided herein do not apply to combinations of this program with
17 * other software, or any other product whatsoever.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write the Free Software Foundation, Inc., 59
21 * Temple Place - Suite 330, Boston MA 02111-1307, USA.
22 *
23 * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
24 * Mountain View, CA 94043, or:
25 *
26 * http://www.sgi.com
27 *
28 * For further information regarding this notice, see:
29 *
30 * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
31 */
32
33 #include <xfs.h>
34 #include <time.h>
35
36 /*
37 * Wrapper around call to libxfs_ialloc. Takes care of committing and
38 * allocating a new transaction as needed.
39 *
40 * Originally there were two copies of this code - one in mkfs, the
41 * other in repair - now there is just the one.
42 */
43 int
44 libxfs_inode_alloc(
45 xfs_trans_t **tp,
46 xfs_inode_t *pip,
47 mode_t mode,
48 ushort nlink,
49 dev_t rdev,
50 cred_t *cr,
51 xfs_inode_t **ipp)
52 {
53 boolean_t call_again;
54 int i;
55 xfs_buf_t *ialloc_context;
56 xfs_inode_t *ip;
57 xfs_trans_t *ntp;
58 int error;
59
60 call_again = B_FALSE;
61 ialloc_context = (xfs_buf_t *)0;
62 error = libxfs_ialloc(*tp, pip, mode, nlink, rdev, cr, (xfs_prid_t) 0,
63 1, &ialloc_context, &call_again, &ip);
64 if (error)
65 return error;
66
67 if (call_again) {
68 xfs_trans_bhold(*tp, ialloc_context);
69 ntp = xfs_trans_dup(*tp);
70 xfs_trans_commit(*tp, 0, NULL);
71 *tp = ntp;
72 if ((i = xfs_trans_reserve(*tp, 0, 0, 0, 0, 0))) {
73 fprintf(stderr, "%s: cannot reserve space: %s\n",
74 progname, strerror(errno));
75 exit(1);
76 }
77 xfs_trans_bjoin(*tp, ialloc_context);
78 error = libxfs_ialloc(*tp, pip, mode, nlink, rdev, cr,
79 (xfs_prid_t) 0, 1, &ialloc_context,
80 &call_again, &ip);
81 if (!ip)
82 error = ENOSPC;
83 if (error)
84 return error;
85 }
86 if (!ip)
87 error = ENOSPC;
88
89 *ipp = ip;
90 return error;
91 }
92
93 /*
94 * Change the requested timestamp in the given inode.
95 *
96 * This was once shared with the kernel, but has diverged to the point
97 * where its no longer worth the hassle of maintaining common code.
98 */
99 void
100 libxfs_ichgtime(xfs_inode_t *ip, int flags)
101 {
102 struct timespec tv;
103 struct timeval stv;
104
105 gettimeofday(&stv, (struct timezone *)0);
106 tv.tv_sec = stv.tv_sec;
107 tv.tv_nsec = stv.tv_usec * 1000;
108 if (flags & XFS_ICHGTIME_MOD) {
109 ip->i_d.di_mtime.t_sec = (__int32_t)tv.tv_sec;
110 ip->i_d.di_mtime.t_nsec = (__int32_t)tv.tv_nsec;
111 }
112 if (flags & XFS_ICHGTIME_ACC) {
113 ip->i_d.di_atime.t_sec = (__int32_t)tv.tv_sec;
114 ip->i_d.di_atime.t_nsec = (__int32_t)tv.tv_nsec;
115 }
116 if (flags & XFS_ICHGTIME_CHG) {
117 ip->i_d.di_ctime.t_sec = (__int32_t)tv.tv_sec;
118 ip->i_d.di_ctime.t_nsec = (__int32_t)tv.tv_nsec;
119 }
120 }
121
122 /*
123 * Allocate an inode on disk and return a copy of it's in-core version.
124 * Set mode, nlink, and rdev appropriately within the inode.
125 * The uid and gid for the inode are set according to the contents of
126 * the given cred structure.
127 *
128 * This was once shared with the kernel, but has diverged to the point
129 * where its no longer worth the hassle of maintaining common code.
130 */
131 int
132 libxfs_ialloc(
133 xfs_trans_t *tp,
134 xfs_inode_t *pip,
135 mode_t mode,
136 nlink_t nlink,
137 dev_t rdev,
138 cred_t *cr,
139 xfs_prid_t prid,
140 int okalloc,
141 xfs_buf_t **ialloc_context,
142 boolean_t *call_again,
143 xfs_inode_t **ipp)
144 {
145 xfs_ino_t ino;
146 xfs_inode_t *ip;
147 uint flags;
148 int error;
149
150 /*
151 * Call the space management code to pick
152 * the on-disk inode to be allocated.
153 */
154 error = xfs_dialloc(tp, pip ? pip->i_ino : 0, mode, okalloc,
155 ialloc_context, call_again, &ino);
156 if (error != 0)
157 return error;
158 if (*call_again || ino == NULLFSINO) {
159 *ipp = NULL;
160 return 0;
161 }
162 ASSERT(*ialloc_context == NULL);
163
164 error = xfs_trans_iget(tp->t_mountp, tp, ino, 0, &ip);
165 if (error != 0)
166 return error;
167 ASSERT(ip != NULL);
168
169 ip->i_d.di_mode = (__uint16_t)mode;
170 ip->i_d.di_onlink = 0;
171 ip->i_d.di_nlink = nlink;
172 ASSERT(ip->i_d.di_nlink == nlink);
173 ip->i_d.di_uid = cr->cr_uid;
174 ip->i_d.di_gid = cr->cr_gid;
175 ip->i_d.di_projid = prid;
176 bzero(&(ip->i_d.di_pad[0]), sizeof(ip->i_d.di_pad));
177
178 /*
179 * If the superblock version is up to where we support new format
180 * inodes and this is currently an old format inode, then change
181 * the inode version number now. This way we only do the conversion
182 * here rather than here and in the flush/logging code.
183 */
184 if (XFS_SB_VERSION_HASNLINK(&tp->t_mountp->m_sb) &&
185 ip->i_d.di_version == XFS_DINODE_VERSION_1) {
186 ip->i_d.di_version = XFS_DINODE_VERSION_2;
187 /* old link count, projid field, pad field already zeroed */
188 }
189
190 ip->i_d.di_size = 0;
191 ip->i_d.di_nextents = 0;
192 ASSERT(ip->i_d.di_nblocks == 0);
193 xfs_ichgtime(ip, XFS_ICHGTIME_CHG|XFS_ICHGTIME_ACC|XFS_ICHGTIME_MOD);
194 /*
195 * di_gen will have been taken care of in xfs_iread.
196 */
197 ip->i_d.di_extsize = 0;
198 ip->i_d.di_dmevmask = 0;
199 ip->i_d.di_dmstate = 0;
200 ip->i_d.di_flags = 0;
201 flags = XFS_ILOG_CORE;
202 switch (mode & IFMT) {
203 case IFIFO:
204 case IFCHR:
205 case IFBLK:
206 case IFSOCK:
207 ip->i_d.di_format = XFS_DINODE_FMT_DEV;
208 ip->i_df.if_u2.if_rdev = makedev(major(rdev), minor(rdev)); ip->i_df.if_flags = 0;
209 flags |= XFS_ILOG_DEV;
210 break;
211 case IFREG:
212 case IFDIR:
213 case IFLNK:
214 ip->i_d.di_format = XFS_DINODE_FMT_EXTENTS;
215 ip->i_df.if_flags = XFS_IFEXTENTS;
216 ip->i_df.if_bytes = ip->i_df.if_real_bytes = 0;
217 ip->i_df.if_u1.if_extents = NULL;
218 break;
219 default:
220 ASSERT(0);
221 }
222 /* Attribute fork settings for new inode. */
223 ip->i_d.di_aformat = XFS_DINODE_FMT_EXTENTS;
224 ip->i_d.di_anextents = 0;
225
226 /*
227 * Log the new values stuffed into the inode.
228 */
229 xfs_trans_log_inode(tp, ip, flags);
230 *ipp = ip;
231 return 0;
232 }
233
234 void
235 libxfs_iprint(xfs_inode_t *ip)
236 {
237 xfs_dinode_core_t *dip;
238 xfs_bmbt_rec_t *ep;
239 xfs_extnum_t i;
240 xfs_extnum_t nextents;
241
242 printf("Inode %lx\n", (unsigned long)ip);
243 printf(" i_ino %llx\n", (unsigned long long)ip->i_ino);
244
245 if (ip->i_df.if_flags & XFS_IFEXTENTS)
246 printf("EXTENTS ");
247 printf("\n");
248 printf(" i_df.if_bytes %d\n", ip->i_df.if_bytes);
249 printf(" i_df.if_u1.if_extents/if_data %lx\n",
250 (unsigned long)ip->i_df.if_u1.if_extents);
251 if (ip->i_df.if_flags & XFS_IFEXTENTS) {
252 nextents = ip->i_df.if_bytes / (uint)sizeof(*ep);
253 for (ep = ip->i_df.if_u1.if_extents, i = 0; i < nextents; i++, ep++) {
254 xfs_bmbt_irec_t rec;
255
256 xfs_bmbt_get_all(ep, &rec);
257 printf("\t%d: startoff %llu, startblock 0x%llx,"
258 " blockcount %llu, state %d\n",
259 i, (unsigned long long)rec.br_startoff,
260 (unsigned long long)rec.br_startblock,
261 (unsigned long long)rec.br_blockcount,
262 (int)rec.br_state);
263 }
264 }
265 printf(" i_df.if_broot %lx\n", (unsigned long)ip->i_df.if_broot);
266 printf(" i_df.if_broot_bytes %x\n", ip->i_df.if_broot_bytes);
267
268 dip = &(ip->i_d);
269 printf("\nOn disk portion\n");
270 printf(" di_magic %x\n", dip->di_magic);
271 printf(" di_mode %o\n", dip->di_mode);
272 printf(" di_version %x\n", (uint)dip->di_version);
273 switch (ip->i_d.di_format) {
274 case XFS_DINODE_FMT_LOCAL:
275 printf(" Inline inode\n");
276 break;
277 case XFS_DINODE_FMT_EXTENTS:
278 printf(" Extents inode\n");
279 break;
280 case XFS_DINODE_FMT_BTREE:
281 printf(" B-tree inode\n");
282 break;
283 default:
284 printf(" Other inode\n");
285 break;
286 }
287 printf(" di_nlink %x\n", dip->di_nlink);
288 printf(" di_uid %d\n", dip->di_uid);
289 printf(" di_gid %d\n", dip->di_gid);
290 printf(" di_nextents %d\n", dip->di_nextents);
291 printf(" di_size %llu\n", (unsigned long long)dip->di_size);
292 printf(" di_gen %x\n", dip->di_gen);
293 printf(" di_extsize %d\n", dip->di_extsize);
294 printf(" di_flags %x\n", dip->di_flags);
295 printf(" di_nblocks %llu\n", (unsigned long long)dip->di_nblocks);
296 }
297
298 /*
299 * Writes a modified inode's changes out to the inode's on disk home.
300 * Originally based on xfs_iflush_int() from xfs_inode.c in the kernel.
301 */
302 int
303 libxfs_iflush_int(xfs_inode_t *ip, xfs_buf_t *bp)
304 {
305 xfs_inode_log_item_t *iip;
306 xfs_dinode_t *dip;
307 xfs_mount_t *mp;
308
309 ASSERT(XFS_BUF_FSPRIVATE(bp, void *) != NULL);
310 ASSERT(ip->i_d.di_format != XFS_DINODE_FMT_BTREE ||
311 ip->i_d.di_nextents > ip->i_df.if_ext_max);
312
313 iip = ip->i_itemp;
314 mp = ip->i_mount;
315
316 /* set *dip = inode's place in the buffer */
317 dip = (xfs_dinode_t *)xfs_buf_offset(bp, ip->i_boffset);
318
319 #ifdef DEBUG
320 ASSERT(ip->i_d.di_magic == XFS_DINODE_MAGIC);
321 if ((ip->i_d.di_mode & IFMT) == IFREG) {
322 ASSERT( (ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS) ||
323 (ip->i_d.di_format == XFS_DINODE_FMT_BTREE) );
324 }
325 else if ((ip->i_d.di_mode & IFMT) == IFDIR) {
326 ASSERT( (ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS) ||
327 (ip->i_d.di_format == XFS_DINODE_FMT_BTREE) ||
328 (ip->i_d.di_format == XFS_DINODE_FMT_LOCAL) );
329 }
330 ASSERT(ip->i_d.di_nextents+ip->i_d.di_anextents <= ip->i_d.di_nblocks);
331 ASSERT(ip->i_d.di_forkoff <= mp->m_sb.sb_inodesize);
332 #endif
333
334 /*
335 * Copy the dirty parts of the inode into the on-disk
336 * inode. We always copy out the core of the inode,
337 * because if the inode is dirty at all the core must
338 * be.
339 */
340 xfs_xlate_dinode_core((xfs_caddr_t)&(dip->di_core), &(ip->i_d), -1,
341 ARCH_CONVERT);
342 /*
343 * If this is really an old format inode and the superblock version
344 * has not been updated to support only new format inodes, then
345 * convert back to the old inode format. If the superblock version
346 * has been updated, then make the conversion permanent.
347 */
348 ASSERT(ip->i_d.di_version == XFS_DINODE_VERSION_1 ||
349 XFS_SB_VERSION_HASNLINK(&mp->m_sb));
350 if (ip->i_d.di_version == XFS_DINODE_VERSION_1) {
351 if (!XFS_SB_VERSION_HASNLINK(&mp->m_sb)) {
352 /*
353 * Convert it back.
354 */
355 ASSERT(ip->i_d.di_nlink <= XFS_MAXLINK_1);
356 INT_SET(dip->di_core.di_onlink, ARCH_CONVERT,
357 ip->i_d.di_nlink);
358 } else {
359 /*
360 * The superblock version has already been bumped,
361 * so just make the conversion to the new inode
362 * format permanent.
363 */
364 ip->i_d.di_version = XFS_DINODE_VERSION_2;
365 INT_SET(dip->di_core.di_version, ARCH_CONVERT,
366 XFS_DINODE_VERSION_2);
367 ip->i_d.di_onlink = 0;
368 INT_ZERO(dip->di_core.di_onlink, ARCH_CONVERT);
369 bzero(&(ip->i_d.di_pad[0]), sizeof(ip->i_d.di_pad));
370 bzero(&(dip->di_core.di_pad[0]),
371 sizeof(dip->di_core.di_pad));
372 ASSERT(ip->i_d.di_projid == 0);
373 }
374 }
375
376 if (xfs_iflush_fork(ip, dip, iip, XFS_DATA_FORK, bp) == EFSCORRUPTED)
377 return EFSCORRUPTED;
378 if (XFS_IFORK_Q(ip)) {
379 /* The only error from xfs_iflush_fork is on the data fork. */
380 xfs_iflush_fork(ip, dip, iip, XFS_ATTR_FORK, bp);
381 }
382
383 return 0;
384 }
385
386 /*
387 * Given a block number in a fork, return the next valid block number
388 * (not a hole).
389 * If this is the last block number then NULLFILEOFF is returned.
390 *
391 * This was originally in the kernel, but only used in xfs_repair.
392 */
393 int
394 libxfs_bmap_next_offset(
395 xfs_trans_t *tp, /* transaction pointer */
396 xfs_inode_t *ip, /* incore inode */
397 xfs_fileoff_t *bnop, /* current block */
398 int whichfork) /* data or attr fork */
399 {
400 xfs_fileoff_t bno; /* current block */
401 int eof; /* hit end of file */
402 int error; /* error return value */
403 xfs_bmbt_irec_t got; /* current extent value */
404 xfs_ifork_t *ifp; /* inode fork pointer */
405 xfs_extnum_t lastx; /* last extent used */
406 xfs_bmbt_irec_t prev; /* previous extent value */
407
408 if (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE &&
409 XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS &&
410 XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_LOCAL)
411 return XFS_ERROR(EIO);
412 if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL) {
413 *bnop = NULLFILEOFF;
414 return 0;
415 }
416 ifp = XFS_IFORK_PTR(ip, whichfork);
417 if (!(ifp->if_flags & XFS_IFEXTENTS) &&
418 (error = xfs_iread_extents(tp, ip, whichfork)))
419 return error;
420 bno = *bnop + 1;
421 xfs_bmap_search_extents(ip, bno, whichfork, &eof, &lastx, &got, &prev);
422 if (eof)
423 *bnop = NULLFILEOFF;
424 else
425 *bnop = got.br_startoff < bno ? bno : got.br_startoff;
426 return 0;
427 }
428
429 /*
430 * Like xfs_dir_removename, but only for removing entries with
431 * (name, hashvalue) pairs that may not be consistent (hashvalue
432 * may not be correctly set for the name).
433 *
434 * This was originally in the kernel, but only used in xfs_repair.
435 */
436 int
437 xfs_dir_bogus_removename(xfs_trans_t *trans, xfs_inode_t *dp, char *name,
438 xfs_fsblock_t *firstblock, xfs_bmap_free_t *flist,
439 xfs_extlen_t total, xfs_dahash_t hashval, int namelen)
440 {
441 xfs_da_args_t args;
442 int count, totallen, newsize, retval;
443
444 ASSERT((dp->i_d.di_mode & IFMT) == IFDIR);
445 if (namelen >= MAXNAMELEN) {
446 return EINVAL;
447 }
448
449 /*
450 * Fill in the arg structure for this request.
451 */
452 args.name = name;
453 args.namelen = namelen;
454 args.hashval = hashval;
455 args.inumber = 0;
456 args.dp = dp;
457 args.firstblock = firstblock;
458 args.flist = flist;
459 args.total = total;
460 args.whichfork = XFS_DATA_FORK;
461 args.trans = trans;
462 args.justcheck = args.addname = 0;
463 args.oknoent = 1;
464
465 /*
466 * Decide on what work routines to call based on the inode size.
467 */
468 if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) {
469 retval = xfs_dir_shortform_removename(&args);
470 } else if (xfs_bmap_one_block(dp, XFS_DATA_FORK)) {
471 retval = xfs_dir_leaf_removename(&args, &count, &totallen);
472 if (retval == 0) {
473 newsize = XFS_DIR_SF_ALLFIT(count, totallen);
474 if (newsize <= XFS_IFORK_DSIZE(dp)) {
475 retval = xfs_dir_leaf_to_shortform(&args);
476 }
477 }
478 } else {
479 retval = xfs_dir_node_removename(&args);
480 }
481 return(retval);
482 }
483
484 /*
485 * Like xfs_dir_removename, but only for removing entries with
486 * (name, hashvalue) pairs that may not be consistent (hashvalue
487 * may not be correctly set for the name).
488 *
489 * This was originally in the kernel, but only used in xfs_repair.
490 */
491 int
492 xfs_dir2_bogus_removename(
493 xfs_trans_t *tp, /* transaction pointer */
494 xfs_inode_t *dp, /* incore directory inode */
495 char *name, /* name of entry to remove */
496 xfs_fsblock_t *first, /* bmap's firstblock */
497 xfs_bmap_free_t *flist, /* bmap's freeblock list */
498 xfs_extlen_t total, /* bmap's total block count */
499 xfs_dahash_t hash, /* name's real hash value */
500 int namelen) /* entry's name length */
501 {
502 xfs_da_args_t args; /* operation arguments */
503 int rval; /* return value */
504 int v; /* type-checking value */
505
506 ASSERT((dp->i_d.di_mode & IFMT) == IFDIR);
507 if (namelen >= MAXNAMELEN)
508 return EINVAL;
509
510 /*
511 * Fill in the arg structure for this request.
512 */
513 args.name = name;
514 args.namelen = namelen;
515 args.hashval = hash;
516 args.inumber = 0;
517 args.dp = dp;
518 args.firstblock = first;
519 args.flist = flist;
520 args.total = total;
521 args.whichfork = XFS_DATA_FORK;
522 args.trans = tp;
523 args.justcheck = args.addname = 0;
524 args.oknoent = 1;
525
526 /*
527 * Decide on what work routines to call based on the inode size.
528 */
529 if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL)
530 rval = xfs_dir2_sf_removename(&args);
531 else if ((rval = xfs_dir2_isblock(tp, dp, &v)))
532 return rval;
533 else if (v)
534 rval = xfs_dir2_block_removename(&args);
535 else if ((rval = xfs_dir2_isleaf(tp, dp, &v)))
536 return rval;
537 else if (v)
538 rval = xfs_dir2_leaf_removename(&args);
539 else
540 rval = xfs_dir2_node_removename(&args);
541 return rval;
542 }
543
544 /*
545 * Utility routine common used to apply a delta to a field in the
546 * in-core superblock.
547 * Switch on the field indicated and apply the delta to that field.
548 * Fields are not allowed to dip below zero, so if the delta would
549 * do this do not apply it and return EINVAL.
550 *
551 * Originally derived from xfs_mod_incore_sb().
552 */
553 int
554 libxfs_mod_incore_sb(xfs_mount_t *mp, xfs_sb_field_t field, int delta, int rsvd)
555 {
556 long long lcounter; /* long counter for 64 bit fields */
557
558 switch (field) {
559 case XFS_SBS_FDBLOCKS:
560 lcounter = (long long)mp->m_sb.sb_fdblocks;
561 lcounter += delta;
562 if (lcounter < 0)
563 return (XFS_ERROR(ENOSPC));
564 mp->m_sb.sb_fdblocks = lcounter;
565 break;
566 default:
567 ASSERT(0);
568 }
569 return 0;
570 }
571
572 int
573 libxfs_bmap_finish(
574 xfs_trans_t **tp,
575 xfs_bmap_free_t *flist,
576 xfs_fsblock_t firstblock,
577 int *committed)
578 {
579 xfs_bmap_free_item_t *free; /* free extent list item */
580 xfs_bmap_free_item_t *next; /* next item on free list */
581 int error;
582
583 if (flist->xbf_count == 0) {
584 *committed = 0;
585 return 0;
586 }
587
588 for (free = flist->xbf_first; free != NULL; free = next) {
589 next = free->xbfi_next;
590 if ((error = xfs_free_extent(*tp, free->xbfi_startblock,
591 free->xbfi_blockcount)))
592 return error;
593 xfs_bmap_del_free(flist, NULL, free);
594 }
595 return 0;
596 }
597
598 /*
599 * This routine allocates disk space for the given file.
600 * Originally derived from xfs_alloc_file_space().
601 */
602 int
603 libxfs_alloc_file_space(
604 xfs_inode_t *ip,
605 xfs_off_t offset,
606 xfs_off_t len,
607 int alloc_type,
608 int attr_flags)
609 {
610 xfs_mount_t *mp;
611 xfs_off_t count;
612 xfs_filblks_t datablocks;
613 xfs_filblks_t allocated_fsb;
614 xfs_filblks_t allocatesize_fsb;
615 xfs_fsblock_t firstfsb;
616 xfs_bmap_free_t free_list;
617 xfs_bmbt_irec_t *imapp;
618 xfs_bmbt_irec_t imaps[1];
619 int reccount;
620 uint resblks;
621 xfs_fileoff_t startoffset_fsb;
622 xfs_trans_t *tp;
623 int xfs_bmapi_flags;
624 int committed;
625 int error;
626
627 if (len <= 0)
628 return EINVAL;
629
630 count = len;
631 error = 0;
632 imapp = &imaps[0];
633 reccount = 1;
634 xfs_bmapi_flags = XFS_BMAPI_WRITE | (alloc_type ? XFS_BMAPI_PREALLOC : 0);
635 mp = ip->i_mount;
636 startoffset_fsb = XFS_B_TO_FSBT(mp, offset);
637 allocatesize_fsb = XFS_B_TO_FSB(mp, count);
638
639 /* allocate file space until done or until there is an error */
640 while (allocatesize_fsb && !error) {
641 datablocks = allocatesize_fsb;
642
643 tp = xfs_trans_alloc(mp, XFS_TRANS_DIOSTRAT);
644 resblks = (uint)XFS_DIOSTRAT_SPACE_RES(mp, datablocks);
645 error = xfs_trans_reserve(tp, resblks, 0, 0, 0, 0);
646 if (error)
647 break;
648 xfs_trans_ijoin(tp, ip, 0);
649 xfs_trans_ihold(tp, ip);
650
651 XFS_BMAP_INIT(&free_list, &firstfsb);
652 error = xfs_bmapi(tp, ip, startoffset_fsb, allocatesize_fsb,
653 xfs_bmapi_flags, &firstfsb, 0, imapp,
654 &reccount, &free_list);
655 if (error)
656 break;
657
658 /* complete the transaction */
659 error = xfs_bmap_finish(&tp, &free_list, firstfsb, &committed);
660 if (error)
661 break;
662
663 error = xfs_trans_commit(tp, 0, NULL);
664 if (error)
665 break;
666
667 allocated_fsb = imapp->br_blockcount;
668 if (reccount == 0)
669 return ENOSPC;
670
671 startoffset_fsb += allocated_fsb;
672 allocatesize_fsb -= allocated_fsb;
673 }
674 return error;
675 }
676
677 unsigned int
678 libxfs_log2_roundup(unsigned int i)
679 {
680 unsigned int rval;
681
682 for (rval = 0; rval < NBBY * sizeof(i); rval++) {
683 if ((1 << rval) >= i)
684 break;
685 }
686 return rval;
687 }
688
689 /*
690 * Get a buffer for the dir/attr block, fill in the contents.
691 * Don't check magic number, the caller will (it's xfs_repair).
692 *
693 * Originally from xfs_da_btree.c in the kernel, but only used
694 * in userspace so it now resides here.
695 */
696 int
697 libxfs_da_read_bufr(
698 xfs_trans_t *trans,
699 xfs_inode_t *dp,
700 xfs_dablk_t bno,
701 xfs_daddr_t mappedbno,
702 xfs_dabuf_t **bpp,
703 int whichfork)
704 {
705 return libxfs_da_do_buf(trans, dp, bno, &mappedbno, bpp, whichfork, 2,
706 (inst_t *)__return_address);
707 }
708
709 /*
710 * Hold dabuf at transaction commit.
711 *
712 * Originally from xfs_da_btree.c in the kernel, but only used
713 * in userspace so it now resides here.
714 */
715 void
716 libxfs_da_bhold(xfs_trans_t *tp, xfs_dabuf_t *dabuf)
717 {
718 int i;
719
720 for (i = 0; i < dabuf->nbuf; i++)
721 xfs_trans_bhold(tp, dabuf->bps[i]);
722 }
723
724 /*
725 * Join dabuf to transaction.
726 *
727 * Originally from xfs_da_btree.c in the kernel, but only used
728 * in userspace so it now resides here.
729 */
730 void
731 libxfs_da_bjoin(xfs_trans_t *tp, xfs_dabuf_t *dabuf)
732 {
733 int i;
734
735 for (i = 0; i < dabuf->nbuf; i++)
736 xfs_trans_bjoin(tp, dabuf->bps[i]);
737 }