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