]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - libxfs/util.c
fix various typos
[thirdparty/xfsprogs-dev.git] / libxfs / util.c
CommitLineData
2bd0ea18 1/*
da23017d
NS
2 * Copyright (c) 2000-2005 Silicon Graphics, Inc.
3 * All Rights Reserved.
2bd0ea18 4 *
da23017d
NS
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
2bd0ea18
NS
7 * published by the Free Software Foundation.
8 *
da23017d
NS
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.
2bd0ea18 13 *
da23017d
NS
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
2bd0ea18
NS
17 */
18
19#include <xfs.h>
20#include <time.h>
1552a820
NS
21#include <stdio.h>
22#include <stdarg.h>
2bd0ea18 23
2bd0ea18
NS
24/*
25 * Change the requested timestamp in the given inode.
5000d01d 26 *
2bd0ea18 27 * This was once shared with the kernel, but has diverged to the point
ff1f79a7 28 * where it's no longer worth the hassle of maintaining common code.
2bd0ea18
NS
29 */
30void
31libxfs_ichgtime(xfs_inode_t *ip, int flags)
32{
5000d01d 33 struct timespec tv;
2bd0ea18
NS
34 struct timeval stv;
35
36 gettimeofday(&stv, (struct timezone *)0);
37 tv.tv_sec = stv.tv_sec;
38 tv.tv_nsec = stv.tv_usec * 1000;
39 if (flags & XFS_ICHGTIME_MOD) {
40 ip->i_d.di_mtime.t_sec = (__int32_t)tv.tv_sec;
41 ip->i_d.di_mtime.t_nsec = (__int32_t)tv.tv_nsec;
42 }
2bd0ea18
NS
43 if (flags & XFS_ICHGTIME_CHG) {
44 ip->i_d.di_ctime.t_sec = (__int32_t)tv.tv_sec;
45 ip->i_d.di_ctime.t_nsec = (__int32_t)tv.tv_nsec;
46 }
47}
48
f1b058f9
NS
49/*
50 * Given a mount structure and an inode number, return a pointer
51 * to a newly allocated in-core inode coresponding to the given
52 * inode number.
53 *
54 * Initialize the inode's attributes and extent pointers if it
55 * already has them (it will not if the inode has no links).
5e656dbb
BN
56 *
57 * NOTE: this has slightly different behaviour to the kernel in
58 * that this version requires the already allocated *ip being
59 * passed in while the kernel version does the allocation and
60 * returns it in **ip.
f1b058f9
NS
61 */
62int
63libxfs_iread(
64 xfs_mount_t *mp,
65 xfs_trans_t *tp,
66 xfs_ino_t ino,
67 xfs_inode_t *ip,
68 xfs_daddr_t bno)
69{
70 xfs_buf_t *bp;
71 xfs_dinode_t *dip;
72 int error;
73
74 ip->i_ino = ino;
75 ip->i_mount = mp;
5e656dbb
BN
76
77 /*
78 * Get pointer's to the on-disk inode and the buffer containing it.
79 * If the inode number refers to a block outside the file system
80 * then xfs_itobp() will return NULL. In this case we should
81 * return NULL as well. Set i_blkno to 0 so that xfs_itobp() will
82 * know that this is a new incore inode.
83 */
84 error = xfs_itobp(mp, tp, ip, &dip, &bp, bno, 0, XFS_BUF_LOCK);
85 if (error)
f1b058f9 86 return error;
5e656dbb
BN
87
88 /*
89 * If we got something that isn't an inode it means someone
90 * (nfs or dmi) has a stale handle.
91 */
92 if (be16_to_cpu(dip->di_core.di_magic) != XFS_DINODE_MAGIC) {
f1b058f9
NS
93 xfs_trans_brelse(tp, bp);
94 return EINVAL;
95 }
5e656dbb
BN
96
97 /*
98 * If the on-disk inode is already linked to a directory
99 * entry, copy all of the inode into the in-core inode.
100 * xfs_iformat() handles copying in the inode format
101 * specific information.
102 * Otherwise, just get the truly permanent information.
103 */
f1b058f9 104 if (dip->di_core.di_mode) {
5e656dbb
BN
105 xfs_dinode_from_disk(&ip->i_d, &dip->di_core);
106 error = xfs_iformat(ip, dip);
107 if (error) {
f1b058f9
NS
108 xfs_trans_brelse(tp, bp);
109 return error;
110 }
111 } else {
5e656dbb
BN
112 ip->i_d.di_magic = be16_to_cpu(dip->di_core.di_magic);
113 ip->i_d.di_version = dip->di_core.di_version;
114 ip->i_d.di_gen = be32_to_cpu(dip->di_core.di_gen);
115 ip->i_d.di_flushiter = be16_to_cpu(dip->di_core.di_flushiter);
116 /*
117 * Make sure to pull in the mode here as well in
118 * case the inode is released without being used.
119 * This ensures that xfs_inactive() will see that
120 * the inode is already free and not try to mess
121 * with the uninitialized part of it.
122 */
f1b058f9 123 ip->i_d.di_mode = 0;
5e656dbb
BN
124 /*
125 * Initialize the per-fork minima and maxima for a new
126 * inode here. xfs_iformat will do it for old inodes.
127 */
f1b058f9
NS
128 ip->i_df.if_ext_max =
129 XFS_IFORK_DSIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t);
130 }
5e656dbb
BN
131
132 /*
133 * The inode format changed when we moved the link count and
134 * made it 32 bits long. If this is an old format inode,
135 * convert it in memory to look like a new one. If it gets
136 * flushed to disk we will convert back before flushing or
137 * logging it. We zero out the new projid field and the old link
138 * count field. We'll handle clearing the pad field (the remains
139 * of the old uuid field) when we actually convert the inode to
140 * the new format. We don't change the version number so that we
141 * can distinguish this from a real new format inode.
142 */
f1b058f9
NS
143 if (ip->i_d.di_version == XFS_DINODE_VERSION_1) {
144 ip->i_d.di_nlink = ip->i_d.di_onlink;
145 ip->i_d.di_onlink = 0;
146 ip->i_d.di_projid = 0;
147 }
5e656dbb 148
f1b058f9 149 ip->i_delayed_blks = 0;
5e656dbb
BN
150 ip->i_size = ip->i_d.di_size;
151
152 /*
153 * Use xfs_trans_brelse() to release the buffer containing the
154 * on-disk inode, because it was acquired with xfs_trans_read_buf()
155 * in xfs_itobp() above. If tp is NULL, this is just a normal
156 * brelse(). If we're within a transaction, then xfs_trans_brelse()
157 * will only release the buffer if it is not dirty within the
158 * transaction. It will be OK to release the buffer in this case,
159 * because inodes on disk are never destroyed and we will be
160 * locking the new in-core inode before putting it in the hash
161 * table where other processes can find it. Thus we don't have
162 * to worry about the inode being changed just because we released
163 * the buffer.
164 */
f1b058f9
NS
165 xfs_trans_brelse(tp, bp);
166 return 0;
167}
168
2bd0ea18 169/*
ff1f79a7 170 * Allocate an inode on disk and return a copy of its in-core version.
2bd0ea18
NS
171 * Set mode, nlink, and rdev appropriately within the inode.
172 * The uid and gid for the inode are set according to the contents of
173 * the given cred structure.
174 *
175 * This was once shared with the kernel, but has diverged to the point
ff1f79a7 176 * where it's no longer worth the hassle of maintaining common code.
2bd0ea18 177 */
5e656dbb 178int
2bd0ea18
NS
179libxfs_ialloc(
180 xfs_trans_t *tp,
181 xfs_inode_t *pip,
182 mode_t mode,
183 nlink_t nlink,
63899e27 184 xfs_dev_t rdev,
9f064b7e
NS
185 struct cred *cr,
186 struct fsxattr *fsx,
2bd0ea18
NS
187 int okalloc,
188 xfs_buf_t **ialloc_context,
189 boolean_t *call_again,
190 xfs_inode_t **ipp)
191{
192 xfs_ino_t ino;
193 xfs_inode_t *ip;
194 uint flags;
195 int error;
196
197 /*
198 * Call the space management code to pick
199 * the on-disk inode to be allocated.
200 */
201 error = xfs_dialloc(tp, pip ? pip->i_ino : 0, mode, okalloc,
202 ialloc_context, call_again, &ino);
203 if (error != 0)
204 return error;
205 if (*call_again || ino == NULLFSINO) {
206 *ipp = NULL;
207 return 0;
208 }
209 ASSERT(*ialloc_context == NULL);
210
46eca962 211 error = xfs_trans_iget(tp->t_mountp, tp, ino, 0, 0, &ip);
2bd0ea18
NS
212 if (error != 0)
213 return error;
214 ASSERT(ip != NULL);
215
216 ip->i_d.di_mode = (__uint16_t)mode;
217 ip->i_d.di_onlink = 0;
218 ip->i_d.di_nlink = nlink;
219 ASSERT(ip->i_d.di_nlink == nlink);
220 ip->i_d.di_uid = cr->cr_uid;
221 ip->i_d.di_gid = cr->cr_gid;
9f064b7e 222 ip->i_d.di_projid = pip ? 0 : fsx->fsx_projid;
32181a02 223 memset(&(ip->i_d.di_pad[0]), 0, sizeof(ip->i_d.di_pad));
2bd0ea18
NS
224
225 /*
226 * If the superblock version is up to where we support new format
227 * inodes and this is currently an old format inode, then change
228 * the inode version number now. This way we only do the conversion
229 * here rather than here and in the flush/logging code.
230 */
5e656dbb 231 if (xfs_sb_version_hasnlink(&tp->t_mountp->m_sb) &&
2bd0ea18
NS
232 ip->i_d.di_version == XFS_DINODE_VERSION_1) {
233 ip->i_d.di_version = XFS_DINODE_VERSION_2;
234 /* old link count, projid field, pad field already zeroed */
5000d01d 235 }
2bd0ea18 236
9f064b7e
NS
237 if (pip && (pip->i_d.di_mode & S_ISGID)) {
238 ip->i_d.di_gid = pip->i_d.di_gid;
239 if ((pip->i_d.di_mode & S_ISGID) && (mode & S_IFMT) == S_IFDIR)
240 ip->i_d.di_mode |= S_ISGID;
241 }
242
2bd0ea18
NS
243 ip->i_d.di_size = 0;
244 ip->i_d.di_nextents = 0;
245 ASSERT(ip->i_d.di_nblocks == 0);
5e656dbb 246 xfs_ichgtime(ip, XFS_ICHGTIME_CHG|XFS_ICHGTIME_MOD);
2bd0ea18
NS
247 /*
248 * di_gen will have been taken care of in xfs_iread.
249 */
9f064b7e 250 ip->i_d.di_extsize = pip ? 0 : fsx->fsx_extsize;
2bd0ea18
NS
251 ip->i_d.di_dmevmask = 0;
252 ip->i_d.di_dmstate = 0;
9f064b7e 253 ip->i_d.di_flags = pip ? 0 : fsx->fsx_xflags;
2bd0ea18 254 flags = XFS_ILOG_CORE;
322f2a29
SL
255 switch (mode & S_IFMT) {
256 case S_IFIFO:
63899e27
NS
257 case S_IFSOCK:
258 /* doesn't make sense to set an rdev for these */
259 rdev = 0;
322f2a29
SL
260 case S_IFCHR:
261 case S_IFBLK:
2bd0ea18 262 ip->i_d.di_format = XFS_DINODE_FMT_DEV;
63899e27 263 ip->i_df.if_u2.if_rdev = rdev;
2bd0ea18
NS
264 flags |= XFS_ILOG_DEV;
265 break;
322f2a29
SL
266 case S_IFREG:
267 case S_IFDIR:
9f064b7e
NS
268 if (pip && (pip->i_d.di_flags & XFS_DIFLAG_ANY)) {
269 uint di_flags = 0;
270
271 if ((mode & S_IFMT) == S_IFDIR) {
272 if (pip->i_d.di_flags & XFS_DIFLAG_RTINHERIT)
273 di_flags |= XFS_DIFLAG_RTINHERIT;
274 if (pip->i_d.di_flags & XFS_DIFLAG_EXTSZINHERIT) {
275 di_flags |= XFS_DIFLAG_EXTSZINHERIT;
276 ip->i_d.di_extsize = pip->i_d.di_extsize;
277 }
278 } else {
279 if (pip->i_d.di_flags & XFS_DIFLAG_RTINHERIT) {
280 di_flags |= XFS_DIFLAG_REALTIME;
281 }
282 if (pip->i_d.di_flags & XFS_DIFLAG_EXTSZINHERIT) {
283 di_flags |= XFS_DIFLAG_EXTSIZE;
284 ip->i_d.di_extsize = pip->i_d.di_extsize;
285 }
286 }
287 if (pip->i_d.di_flags & XFS_DIFLAG_PROJINHERIT)
288 di_flags |= XFS_DIFLAG_PROJINHERIT;
289 ip->i_d.di_flags |= di_flags;
290 }
291 /* FALLTHROUGH */
322f2a29 292 case S_IFLNK:
2bd0ea18
NS
293 ip->i_d.di_format = XFS_DINODE_FMT_EXTENTS;
294 ip->i_df.if_flags = XFS_IFEXTENTS;
295 ip->i_df.if_bytes = ip->i_df.if_real_bytes = 0;
296 ip->i_df.if_u1.if_extents = NULL;
297 break;
298 default:
299 ASSERT(0);
300 }
301 /* Attribute fork settings for new inode. */
302 ip->i_d.di_aformat = XFS_DINODE_FMT_EXTENTS;
303 ip->i_d.di_anextents = 0;
304
305 /*
306 * Log the new values stuffed into the inode.
307 */
308 xfs_trans_log_inode(tp, ip, flags);
309 *ipp = ip;
310 return 0;
311}
312
313void
5e656dbb
BN
314libxfs_iprint(
315 xfs_inode_t *ip)
2bd0ea18 316{
5e656dbb
BN
317 xfs_icdinode_t *dip;
318 xfs_bmbt_rec_host_t *ep;
db15fab1
NS
319 xfs_extnum_t i;
320 xfs_extnum_t nextents;
2bd0ea18 321
5b64e00a 322 printf("Inode %lx\n", (unsigned long)ip);
5b64e00a 323 printf(" i_ino %llx\n", (unsigned long long)ip->i_ino);
2bd0ea18
NS
324
325 if (ip->i_df.if_flags & XFS_IFEXTENTS)
326 printf("EXTENTS ");
327 printf("\n");
328 printf(" i_df.if_bytes %d\n", ip->i_df.if_bytes);
5b64e00a
NS
329 printf(" i_df.if_u1.if_extents/if_data %lx\n",
330 (unsigned long)ip->i_df.if_u1.if_extents);
2bd0ea18
NS
331 if (ip->i_df.if_flags & XFS_IFEXTENTS) {
332 nextents = ip->i_df.if_bytes / (uint)sizeof(*ep);
5e656dbb
BN
333 for (ep = ip->i_df.if_u1.if_extents, i = 0; i < nextents;
334 i++, ep++) {
5000d01d 335 xfs_bmbt_irec_t rec;
2bd0ea18
NS
336
337 xfs_bmbt_get_all(ep, &rec);
5b64e00a
NS
338 printf("\t%d: startoff %llu, startblock 0x%llx,"
339 " blockcount %llu, state %d\n",
340 i, (unsigned long long)rec.br_startoff,
341 (unsigned long long)rec.br_startblock,
342 (unsigned long long)rec.br_blockcount,
2bd0ea18
NS
343 (int)rec.br_state);
344 }
345 }
5b64e00a 346 printf(" i_df.if_broot %lx\n", (unsigned long)ip->i_df.if_broot);
2bd0ea18
NS
347 printf(" i_df.if_broot_bytes %x\n", ip->i_df.if_broot_bytes);
348
5e656dbb 349 dip = &ip->i_d;
2bd0ea18
NS
350 printf("\nOn disk portion\n");
351 printf(" di_magic %x\n", dip->di_magic);
352 printf(" di_mode %o\n", dip->di_mode);
353 printf(" di_version %x\n", (uint)dip->di_version);
354 switch (ip->i_d.di_format) {
355 case XFS_DINODE_FMT_LOCAL:
356 printf(" Inline inode\n");
357 break;
358 case XFS_DINODE_FMT_EXTENTS:
359 printf(" Extents inode\n");
360 break;
361 case XFS_DINODE_FMT_BTREE:
362 printf(" B-tree inode\n");
363 break;
364 default:
365 printf(" Other inode\n");
366 break;
367 }
368 printf(" di_nlink %x\n", dip->di_nlink);
369 printf(" di_uid %d\n", dip->di_uid);
370 printf(" di_gid %d\n", dip->di_gid);
371 printf(" di_nextents %d\n", dip->di_nextents);
5b64e00a 372 printf(" di_size %llu\n", (unsigned long long)dip->di_size);
2bd0ea18
NS
373 printf(" di_gen %x\n", dip->di_gen);
374 printf(" di_extsize %d\n", dip->di_extsize);
375 printf(" di_flags %x\n", dip->di_flags);
5b64e00a 376 printf(" di_nblocks %llu\n", (unsigned long long)dip->di_nblocks);
2bd0ea18
NS
377}
378
379/*
380 * Writes a modified inode's changes out to the inode's on disk home.
381 * Originally based on xfs_iflush_int() from xfs_inode.c in the kernel.
382 */
383int
384libxfs_iflush_int(xfs_inode_t *ip, xfs_buf_t *bp)
385{
386 xfs_inode_log_item_t *iip;
387 xfs_dinode_t *dip;
388 xfs_mount_t *mp;
389
390 ASSERT(XFS_BUF_FSPRIVATE(bp, void *) != NULL);
391 ASSERT(ip->i_d.di_format != XFS_DINODE_FMT_BTREE ||
392 ip->i_d.di_nextents > ip->i_df.if_ext_max);
393
394 iip = ip->i_itemp;
395 mp = ip->i_mount;
396
397 /* set *dip = inode's place in the buffer */
398 dip = (xfs_dinode_t *)xfs_buf_offset(bp, ip->i_boffset);
399
2bd0ea18 400 ASSERT(ip->i_d.di_magic == XFS_DINODE_MAGIC);
322f2a29 401 if ((ip->i_d.di_mode & S_IFMT) == S_IFREG) {
2bd0ea18
NS
402 ASSERT( (ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS) ||
403 (ip->i_d.di_format == XFS_DINODE_FMT_BTREE) );
404 }
322f2a29 405 else if ((ip->i_d.di_mode & S_IFMT) == S_IFDIR) {
2bd0ea18
NS
406 ASSERT( (ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS) ||
407 (ip->i_d.di_format == XFS_DINODE_FMT_BTREE) ||
408 (ip->i_d.di_format == XFS_DINODE_FMT_LOCAL) );
409 }
410 ASSERT(ip->i_d.di_nextents+ip->i_d.di_anextents <= ip->i_d.di_nblocks);
411 ASSERT(ip->i_d.di_forkoff <= mp->m_sb.sb_inodesize);
2bd0ea18
NS
412
413 /*
414 * Copy the dirty parts of the inode into the on-disk
415 * inode. We always copy out the core of the inode,
416 * because if the inode is dirty at all the core must
417 * be.
418 */
5e656dbb 419 xfs_dinode_to_disk(&dip->di_core, &ip->i_d);
46eca962 420
2bd0ea18
NS
421 /*
422 * If this is really an old format inode and the superblock version
423 * has not been updated to support only new format inodes, then
424 * convert back to the old inode format. If the superblock version
425 * has been updated, then make the conversion permanent.
426 */
427 ASSERT(ip->i_d.di_version == XFS_DINODE_VERSION_1 ||
5e656dbb 428 xfs_sb_version_hasnlink(&mp->m_sb));
2bd0ea18 429 if (ip->i_d.di_version == XFS_DINODE_VERSION_1) {
5e656dbb 430 if (!xfs_sb_version_hasnlink(&mp->m_sb)) {
2bd0ea18
NS
431 /*
432 * Convert it back.
433 */
434 ASSERT(ip->i_d.di_nlink <= XFS_MAXLINK_1);
5e656dbb 435 dip->di_core.di_onlink = cpu_to_be16(ip->i_d.di_nlink);
2bd0ea18
NS
436 } else {
437 /*
438 * The superblock version has already been bumped,
439 * so just make the conversion to the new inode
440 * format permanent.
441 */
442 ip->i_d.di_version = XFS_DINODE_VERSION_2;
5e656dbb 443 dip->di_core.di_version = XFS_DINODE_VERSION_2;
2bd0ea18 444 ip->i_d.di_onlink = 0;
46eca962 445 dip->di_core.di_onlink = 0;
32181a02
NS
446 memset(&(ip->i_d.di_pad[0]), 0, sizeof(ip->i_d.di_pad));
447 memset(&(dip->di_core.di_pad[0]), 0,
5e656dbb 448 sizeof(dip->di_core.di_pad));
2bd0ea18
NS
449 ASSERT(ip->i_d.di_projid == 0);
450 }
451 }
452
5e656dbb
BN
453 xfs_iflush_fork(ip, dip, iip, XFS_DATA_FORK, bp);
454 if (XFS_IFORK_Q(ip))
2bd0ea18 455 xfs_iflush_fork(ip, dip, iip, XFS_ATTR_FORK, bp);
2bd0ea18
NS
456
457 return 0;
458}
459
2bd0ea18
NS
460/*
461 * Utility routine common used to apply a delta to a field in the
462 * in-core superblock.
463 * Switch on the field indicated and apply the delta to that field.
464 * Fields are not allowed to dip below zero, so if the delta would
465 * do this do not apply it and return EINVAL.
466 *
5e656dbb 467 * Originally derived from xfs_mod_incore_sb_unlocked().
2bd0ea18
NS
468 */
469int
5e656dbb
BN
470libxfs_mod_incore_sb(
471 xfs_mount_t *mp,
472 xfs_sb_field_t field,
473 int64_t delta,
474 int rsvd)
2bd0ea18
NS
475{
476 long long lcounter; /* long counter for 64 bit fields */
477
478 switch (field) {
479 case XFS_SBS_FDBLOCKS:
480 lcounter = (long long)mp->m_sb.sb_fdblocks;
481 lcounter += delta;
482 if (lcounter < 0)
5e656dbb 483 return XFS_ERROR(ENOSPC);
2bd0ea18 484 mp->m_sb.sb_fdblocks = lcounter;
5e656dbb 485 return 0;
2bd0ea18
NS
486 default:
487 ASSERT(0);
5e656dbb 488 return XFS_ERROR(EINVAL);
2bd0ea18 489 }
2bd0ea18
NS
490}
491
492int
493libxfs_bmap_finish(
494 xfs_trans_t **tp,
5000d01d 495 xfs_bmap_free_t *flist,
2bd0ea18
NS
496 int *committed)
497{
498 xfs_bmap_free_item_t *free; /* free extent list item */
499 xfs_bmap_free_item_t *next; /* next item on free list */
500 int error;
2bd0ea18
NS
501
502 if (flist->xbf_count == 0) {
503 *committed = 0;
504 return 0;
505 }
506
507 for (free = flist->xbf_first; free != NULL; free = next) {
508 next = free->xbfi_next;
0e266570
NS
509 if ((error = xfs_free_extent(*tp, free->xbfi_startblock,
510 free->xbfi_blockcount)))
2bd0ea18
NS
511 return error;
512 xfs_bmap_del_free(flist, NULL, free);
513 }
57c9fccb 514 *committed = 0;
2bd0ea18
NS
515 return 0;
516}
517
518/*
519 * This routine allocates disk space for the given file.
520 * Originally derived from xfs_alloc_file_space().
521 */
522int
523libxfs_alloc_file_space(
524 xfs_inode_t *ip,
525 xfs_off_t offset,
526 xfs_off_t len,
527 int alloc_type,
528 int attr_flags)
529{
530 xfs_mount_t *mp;
531 xfs_off_t count;
532 xfs_filblks_t datablocks;
533 xfs_filblks_t allocated_fsb;
534 xfs_filblks_t allocatesize_fsb;
535 xfs_fsblock_t firstfsb;
5000d01d
SL
536 xfs_bmap_free_t free_list;
537 xfs_bmbt_irec_t *imapp;
538 xfs_bmbt_irec_t imaps[1];
2bd0ea18
NS
539 int reccount;
540 uint resblks;
541 xfs_fileoff_t startoffset_fsb;
542 xfs_trans_t *tp;
543 int xfs_bmapi_flags;
544 int committed;
545 int error;
546
547 if (len <= 0)
548 return EINVAL;
549
550 count = len;
551 error = 0;
552 imapp = &imaps[0];
553 reccount = 1;
554 xfs_bmapi_flags = XFS_BMAPI_WRITE | (alloc_type ? XFS_BMAPI_PREALLOC : 0);
555 mp = ip->i_mount;
556 startoffset_fsb = XFS_B_TO_FSBT(mp, offset);
557 allocatesize_fsb = XFS_B_TO_FSB(mp, count);
558
559 /* allocate file space until done or until there is an error */
560 while (allocatesize_fsb && !error) {
561 datablocks = allocatesize_fsb;
562
563 tp = xfs_trans_alloc(mp, XFS_TRANS_DIOSTRAT);
564 resblks = (uint)XFS_DIOSTRAT_SPACE_RES(mp, datablocks);
565 error = xfs_trans_reserve(tp, resblks, 0, 0, 0, 0);
566 if (error)
567 break;
568 xfs_trans_ijoin(tp, ip, 0);
569 xfs_trans_ihold(tp, ip);
570
571 XFS_BMAP_INIT(&free_list, &firstfsb);
572 error = xfs_bmapi(tp, ip, startoffset_fsb, allocatesize_fsb,
573 xfs_bmapi_flags, &firstfsb, 0, imapp,
5e656dbb 574 &reccount, &free_list, NULL);
2bd0ea18
NS
575 if (error)
576 break;
577
578 /* complete the transaction */
5e656dbb 579 error = xfs_bmap_finish(&tp, &free_list, &committed);
2bd0ea18
NS
580 if (error)
581 break;
582
5e656dbb 583 error = xfs_trans_commit(tp, 0);
2bd0ea18
NS
584 if (error)
585 break;
586
587 allocated_fsb = imapp->br_blockcount;
588 if (reccount == 0)
589 return ENOSPC;
590
591 startoffset_fsb += allocated_fsb;
592 allocatesize_fsb -= allocated_fsb;
593 }
594 return error;
595}
596
597unsigned int
598libxfs_log2_roundup(unsigned int i)
599{
600 unsigned int rval;
601
602 for (rval = 0; rval < NBBY * sizeof(i); rval++) {
603 if ((1 << rval) >= i)
604 break;
605 }
606 return rval;
607}
608
609/*
610 * Get a buffer for the dir/attr block, fill in the contents.
611 * Don't check magic number, the caller will (it's xfs_repair).
5000d01d 612 *
2bd0ea18
NS
613 * Originally from xfs_da_btree.c in the kernel, but only used
614 * in userspace so it now resides here.
615 */
616int
617libxfs_da_read_bufr(
618 xfs_trans_t *trans,
619 xfs_inode_t *dp,
620 xfs_dablk_t bno,
a981f202 621 xfs_daddr_t mappedbno,
2bd0ea18
NS
622 xfs_dabuf_t **bpp,
623 int whichfork)
624{
5e656dbb 625 return xfs_da_do_buf(trans, dp, bno, &mappedbno, bpp, whichfork, 2,
2bd0ea18
NS
626 (inst_t *)__return_address);
627}
628
629/*
630 * Hold dabuf at transaction commit.
5000d01d 631 *
2bd0ea18
NS
632 * Originally from xfs_da_btree.c in the kernel, but only used
633 * in userspace so it now resides here.
634 */
635void
636libxfs_da_bhold(xfs_trans_t *tp, xfs_dabuf_t *dabuf)
637{
638 int i;
639
640 for (i = 0; i < dabuf->nbuf; i++)
641 xfs_trans_bhold(tp, dabuf->bps[i]);
642}
643
644/*
645 * Join dabuf to transaction.
5000d01d 646 *
2bd0ea18
NS
647 * Originally from xfs_da_btree.c in the kernel, but only used
648 * in userspace so it now resides here.
649 */
650void
651libxfs_da_bjoin(xfs_trans_t *tp, xfs_dabuf_t *dabuf)
652{
653 int i;
654
655 for (i = 0; i < dabuf->nbuf; i++)
656 xfs_trans_bjoin(tp, dabuf->bps[i]);
657}
9f064b7e
NS
658
659/*
660 * Wrapper around call to libxfs_ialloc. Takes care of committing and
661 * allocating a new transaction as needed.
662 *
663 * Originally there were two copies of this code - one in mkfs, the
664 * other in repair - now there is just the one.
665 */
666int
667libxfs_inode_alloc(
668 xfs_trans_t **tp,
669 xfs_inode_t *pip,
670 mode_t mode,
671 nlink_t nlink,
672 xfs_dev_t rdev,
673 struct cred *cr,
674 struct fsxattr *fsx,
675 xfs_inode_t **ipp)
676{
677 boolean_t call_again;
678 int i;
679 xfs_buf_t *ialloc_context;
680 xfs_inode_t *ip;
681 xfs_trans_t *ntp;
682 int error;
683
684 call_again = B_FALSE;
685 ialloc_context = (xfs_buf_t *)0;
686 error = libxfs_ialloc(*tp, pip, mode, nlink, rdev, cr, fsx,
687 1, &ialloc_context, &call_again, &ip);
688 if (error)
689 return error;
690
691 if (call_again) {
692 xfs_trans_bhold(*tp, ialloc_context);
693 ntp = xfs_trans_dup(*tp);
5e656dbb 694 xfs_trans_commit(*tp, 0);
9f064b7e
NS
695 *tp = ntp;
696 if ((i = xfs_trans_reserve(*tp, 0, 0, 0, 0, 0))) {
697 fprintf(stderr, _("%s: cannot reserve space: %s\n"),
1552a820 698 progname, strerror(i));
9f064b7e
NS
699 exit(1);
700 }
701 xfs_trans_bjoin(*tp, ialloc_context);
702 error = libxfs_ialloc(*tp, pip, mode, nlink, rdev, cr,
703 fsx, 1, &ialloc_context,
704 &call_again, &ip);
705 if (!ip)
706 error = ENOSPC;
707 if (error)
708 return error;
709 }
710 if (!ip)
711 error = ENOSPC;
712
713 *ipp = ip;
714 return error;
715}
1552a820
NS
716
717/*
718 * Userspace versions of common diagnostic routines (varargs fun).
719 */
720void
5e656dbb 721libxfs_fs_repair_cmn_err(int level, xfs_mount_t *mp, char *fmt, ...)
1552a820
NS
722{
723 va_list ap;
724
725 va_start(ap, fmt);
726 vfprintf(stderr, fmt, ap);
727 fprintf(stderr, " This is a bug.\n");
6c39a3cb
BN
728 fprintf(stderr, "Please capture the filesystem metadata with "
729 "xfs_metadump and\nreport it to xfs@oss.sgi.com.\n");
1552a820
NS
730 va_end(ap);
731}
732
733void
5e656dbb 734libxfs_fs_cmn_err(int level, xfs_mount_t *mp, char *fmt, ...)
1552a820
NS
735{
736 va_list ap;
737
738 va_start(ap, fmt);
739 vfprintf(stderr, fmt, ap);
740 fputs("\n", stderr);
741 va_end(ap);
742}
743
744void
745cmn_err(int level, char *fmt, ...)
746{
747 va_list ap;
748
749 va_start(ap, fmt);
750 vfprintf(stderr, fmt, ap);
751 fputs("\n", stderr);
752 va_end(ap);
753}