2 * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
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.
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.
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.
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.
23 * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
24 * Mountain View, CA 94043, or:
28 * For further information regarding this notice, see:
30 * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
37 * Wrapper around call to libxfs_ialloc. Takes care of committing and
38 * allocating a new transaction as needed.
40 * Originally there were two copies of this code - one in mkfs, the
41 * other in repair - now there is just the one.
55 xfs_buf_t
*ialloc_context
;
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
);
68 xfs_trans_bhold(*tp
, ialloc_context
);
69 ntp
= xfs_trans_dup(*tp
);
70 xfs_trans_commit(*tp
, 0, NULL
);
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
));
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
,
91 * Change the requested timestamp in the given inode.
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.
97 libxfs_ichgtime(xfs_inode_t
*ip
, int flags
)
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
;
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
;
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
;
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.
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.
138 xfs_buf_t
**ialloc_context
,
139 boolean_t
*call_again
,
148 * Call the space management code to pick
149 * the on-disk inode to be allocated.
151 error
= xfs_dialloc(tp
, pip
? pip
->i_ino
: 0, mode
, okalloc
,
152 ialloc_context
, call_again
, &ino
);
155 if (*call_again
|| ino
== NULLFSINO
) {
159 ASSERT(*ialloc_context
== NULL
);
161 error
= xfs_trans_iget(tp
->t_mountp
, tp
, ino
, 0, &ip
);
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
));
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.
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 */
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
);
192 * di_gen will have been taken care of in xfs_iread.
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
) {
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
;
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
;
219 /* Attribute fork settings for new inode. */
220 ip
->i_d
.di_aformat
= XFS_DINODE_FMT_EXTENTS
;
221 ip
->i_d
.di_anextents
= 0;
224 * Log the new values stuffed into the inode.
226 xfs_trans_log_inode(tp
, ip
, flags
);
232 libxfs_iprint(xfs_inode_t
*ip
)
234 xfs_dinode_core_t
*dip
;
237 xfs_extnum_t nextents
;
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
);
243 if (ip
->i_df
.if_flags
& XFS_IFEXTENTS
)
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
++) {
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
,
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
);
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");
274 case XFS_DINODE_FMT_EXTENTS
:
275 printf(" Extents inode\n");
277 case XFS_DINODE_FMT_BTREE
:
278 printf(" B-tree inode\n");
281 printf(" Other inode\n");
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
);
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.
300 libxfs_iflush_int(xfs_inode_t
*ip
, xfs_buf_t
*bp
)
302 xfs_inode_log_item_t
*iip
;
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
);
313 /* set *dip = inode's place in the buffer */
314 dip
= (xfs_dinode_t
*)xfs_buf_offset(bp
, ip
->i_boffset
);
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
) );
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
) );
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
);
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
337 xfs_xlate_dinode_core((xfs_caddr_t
)&(dip
->di_core
), &(ip
->i_d
), -1,
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.
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
)) {
352 ASSERT(ip
->i_d
.di_nlink
<= XFS_MAXLINK_1
);
353 INT_SET(dip
->di_core
.di_onlink
, ARCH_CONVERT
,
357 * The superblock version has already been bumped,
358 * so just make the conversion to the new inode
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);
373 if (xfs_iflush_fork(ip
, dip
, iip
, XFS_DATA_FORK
, bp
) == 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
);
384 * Given a block number in a fork, return the next valid block number
386 * If this is the last block number then NULLFILEOFF is returned.
388 * This was originally in the kernel, but only used in xfs_repair.
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 */
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 */
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
) {
413 ifp
= XFS_IFORK_PTR(ip
, whichfork
);
414 if (!(ifp
->if_flags
& XFS_IFEXTENTS
) &&
415 (error
= xfs_iread_extents(tp
, ip
, whichfork
)))
418 xfs_bmap_search_extents(ip
, bno
, whichfork
, &eof
, &lastx
, &got
, &prev
);
422 *bnop
= got
.br_startoff
< bno
? bno
: got
.br_startoff
;
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).
431 * This was originally in the kernel, but only used in xfs_repair.
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
)
439 int count
, totallen
, newsize
, retval
;
441 ASSERT((dp
->i_d
.di_mode
& IFMT
) == IFDIR
);
442 if (namelen
>= MAXNAMELEN
) {
447 * Fill in the arg structure for this request.
450 args
.namelen
= namelen
;
451 args
.hashval
= hashval
;
454 args
.firstblock
= firstblock
;
457 args
.whichfork
= XFS_DATA_FORK
;
459 args
.justcheck
= args
.addname
= 0;
463 * Decide on what work routines to call based on the inode size.
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
);
470 newsize
= XFS_DIR_SF_ALLFIT(count
, totallen
);
471 if (newsize
<= XFS_IFORK_DSIZE(dp
)) {
472 retval
= xfs_dir_leaf_to_shortform(&args
);
476 retval
= xfs_dir_node_removename(&args
);
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).
486 * This was originally in the kernel, but only used in xfs_repair.
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 */
499 xfs_da_args_t args
; /* operation arguments */
500 int rval
; /* return value */
501 int v
; /* type-checking value */
503 ASSERT((dp
->i_d
.di_mode
& IFMT
) == IFDIR
);
504 if (namelen
>= MAXNAMELEN
)
508 * Fill in the arg structure for this request.
511 args
.namelen
= namelen
;
515 args
.firstblock
= first
;
518 args
.whichfork
= XFS_DATA_FORK
;
520 args
.justcheck
= args
.addname
= 0;
524 * Decide on what work routines to call based on the inode size.
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
))
531 rval
= xfs_dir2_block_removename(&args
);
532 else if (rval
= xfs_dir2_isleaf(tp
, dp
, &v
))
535 rval
= xfs_dir2_leaf_removename(&args
);
537 rval
= xfs_dir2_node_removename(&args
);
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.
548 * Originally derived from xfs_mod_incore_sb().
551 libxfs_mod_incore_sb(xfs_mount_t
*mp
, xfs_sb_field_t field
, int delta
, int rsvd
)
553 long long lcounter
; /* long counter for 64 bit fields */
556 case XFS_SBS_FDBLOCKS
:
557 lcounter
= (long long)mp
->m_sb
.sb_fdblocks
;
560 return (XFS_ERROR(ENOSPC
));
561 mp
->m_sb
.sb_fdblocks
= lcounter
;
572 xfs_bmap_free_t
*flist
,
573 xfs_fsblock_t firstblock
,
576 xfs_bmap_free_item_t
*free
; /* free extent list item */
577 xfs_bmap_free_item_t
*next
; /* next item on free list */
581 if (flist
->xbf_count
== 0) {
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
))
591 xfs_bmap_del_free(flist
, NULL
, free
);
597 * This routine allocates disk space for the given file.
598 * Originally derived from xfs_alloc_file_space().
601 libxfs_alloc_file_space(
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];
619 xfs_fileoff_t startoffset_fsb
;
632 xfs_bmapi_flags
= XFS_BMAPI_WRITE
| (alloc_type
? XFS_BMAPI_PREALLOC
: 0);
634 startoffset_fsb
= XFS_B_TO_FSBT(mp
, offset
);
635 allocatesize_fsb
= XFS_B_TO_FSB(mp
, count
);
637 /* allocate file space until done or until there is an error */
638 while (allocatesize_fsb
&& !error
) {
639 datablocks
= allocatesize_fsb
;
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);
646 xfs_trans_ijoin(tp
, ip
, 0);
647 xfs_trans_ihold(tp
, ip
);
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
);
656 /* complete the transaction */
657 error
= xfs_bmap_finish(&tp
, &free_list
, firstfsb
, &committed
);
661 error
= xfs_trans_commit(tp
, 0, NULL
);
665 allocated_fsb
= imapp
->br_blockcount
;
669 startoffset_fsb
+= allocated_fsb
;
670 allocatesize_fsb
-= allocated_fsb
;
676 libxfs_log2_roundup(unsigned int i
)
680 for (rval
= 0; rval
< NBBY
* sizeof(i
); rval
++) {
681 if ((1 << rval
) >= i
)
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).
691 * Originally from xfs_da_btree.c in the kernel, but only used
692 * in userspace so it now resides here.
699 xfs_daddr_t mappedbno
,
703 return libxfs_da_do_buf(trans
, dp
, bno
, &mappedbno
, bpp
, whichfork
, 2,
704 (inst_t
*)__return_address
);
708 * Hold dabuf at transaction commit.
710 * Originally from xfs_da_btree.c in the kernel, but only used
711 * in userspace so it now resides here.
714 libxfs_da_bhold(xfs_trans_t
*tp
, xfs_dabuf_t
*dabuf
)
718 for (i
= 0; i
< dabuf
->nbuf
; i
++)
719 xfs_trans_bhold(tp
, dabuf
->bps
[i
]);
723 * Join dabuf to transaction.
725 * Originally from xfs_da_btree.c in the kernel, but only used
726 * in userspace so it now resides here.
729 libxfs_da_bjoin(xfs_trans_t
*tp
, xfs_dabuf_t
*dabuf
)
733 for (i
= 0; i
< dabuf
->nbuf
; i
++)
734 xfs_trans_bjoin(tp
, dabuf
->bps
[i
]);