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
,
94 * Change the requested timestamp in the given inode.
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.
100 libxfs_ichgtime(xfs_inode_t
*ip
, int flags
)
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
;
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
;
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
;
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.
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.
141 xfs_buf_t
**ialloc_context
,
142 boolean_t
*call_again
,
151 * Call the space management code to pick
152 * the on-disk inode to be allocated.
154 error
= xfs_dialloc(tp
, pip
? pip
->i_ino
: 0, mode
, okalloc
,
155 ialloc_context
, call_again
, &ino
);
158 if (*call_again
|| ino
== NULLFSINO
) {
162 ASSERT(*ialloc_context
== NULL
);
164 error
= xfs_trans_iget(tp
->t_mountp
, tp
, ino
, 0, &ip
);
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
));
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.
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 */
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
);
195 * di_gen will have been taken care of in xfs_iread.
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
) {
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
;
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
;
222 /* Attribute fork settings for new inode. */
223 ip
->i_d
.di_aformat
= XFS_DINODE_FMT_EXTENTS
;
224 ip
->i_d
.di_anextents
= 0;
227 * Log the new values stuffed into the inode.
229 xfs_trans_log_inode(tp
, ip
, flags
);
235 libxfs_iprint(xfs_inode_t
*ip
)
237 xfs_dinode_core_t
*dip
;
240 xfs_extnum_t nextents
;
242 printf("Inode %lx\n", (unsigned long)ip
);
243 printf(" i_ino %llx\n", (unsigned long long)ip
->i_ino
);
245 if (ip
->i_df
.if_flags
& XFS_IFEXTENTS
)
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
++) {
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
,
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
);
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");
277 case XFS_DINODE_FMT_EXTENTS
:
278 printf(" Extents inode\n");
280 case XFS_DINODE_FMT_BTREE
:
281 printf(" B-tree inode\n");
284 printf(" Other inode\n");
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
);
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.
303 libxfs_iflush_int(xfs_inode_t
*ip
, xfs_buf_t
*bp
)
305 xfs_inode_log_item_t
*iip
;
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
);
316 /* set *dip = inode's place in the buffer */
317 dip
= (xfs_dinode_t
*)xfs_buf_offset(bp
, ip
->i_boffset
);
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
) );
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
) );
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
);
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
340 xfs_xlate_dinode_core((xfs_caddr_t
)&(dip
->di_core
), &(ip
->i_d
), -1,
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.
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
)) {
355 ASSERT(ip
->i_d
.di_nlink
<= XFS_MAXLINK_1
);
356 INT_SET(dip
->di_core
.di_onlink
, ARCH_CONVERT
,
360 * The superblock version has already been bumped,
361 * so just make the conversion to the new inode
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);
376 if (xfs_iflush_fork(ip
, dip
, iip
, XFS_DATA_FORK
, bp
) == 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
);
387 * Given a block number in a fork, return the next valid block number
389 * If this is the last block number then NULLFILEOFF is returned.
391 * This was originally in the kernel, but only used in xfs_repair.
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 */
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 */
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
) {
416 ifp
= XFS_IFORK_PTR(ip
, whichfork
);
417 if (!(ifp
->if_flags
& XFS_IFEXTENTS
) &&
418 (error
= xfs_iread_extents(tp
, ip
, whichfork
)))
421 xfs_bmap_search_extents(ip
, bno
, whichfork
, &eof
, &lastx
, &got
, &prev
);
425 *bnop
= got
.br_startoff
< bno
? bno
: got
.br_startoff
;
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).
434 * This was originally in the kernel, but only used in xfs_repair.
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
)
442 int count
, totallen
, newsize
, retval
;
444 ASSERT((dp
->i_d
.di_mode
& IFMT
) == IFDIR
);
445 if (namelen
>= MAXNAMELEN
) {
450 * Fill in the arg structure for this request.
453 args
.namelen
= namelen
;
454 args
.hashval
= hashval
;
457 args
.firstblock
= firstblock
;
460 args
.whichfork
= XFS_DATA_FORK
;
462 args
.justcheck
= args
.addname
= 0;
466 * Decide on what work routines to call based on the inode size.
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
);
473 newsize
= XFS_DIR_SF_ALLFIT(count
, totallen
);
474 if (newsize
<= XFS_IFORK_DSIZE(dp
)) {
475 retval
= xfs_dir_leaf_to_shortform(&args
);
479 retval
= xfs_dir_node_removename(&args
);
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).
489 * This was originally in the kernel, but only used in xfs_repair.
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 */
502 xfs_da_args_t args
; /* operation arguments */
503 int rval
; /* return value */
504 int v
; /* type-checking value */
506 ASSERT((dp
->i_d
.di_mode
& IFMT
) == IFDIR
);
507 if (namelen
>= MAXNAMELEN
)
511 * Fill in the arg structure for this request.
514 args
.namelen
= namelen
;
518 args
.firstblock
= first
;
521 args
.whichfork
= XFS_DATA_FORK
;
523 args
.justcheck
= args
.addname
= 0;
527 * Decide on what work routines to call based on the inode size.
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
)))
534 rval
= xfs_dir2_block_removename(&args
);
535 else if ((rval
= xfs_dir2_isleaf(tp
, dp
, &v
)))
538 rval
= xfs_dir2_leaf_removename(&args
);
540 rval
= xfs_dir2_node_removename(&args
);
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.
551 * Originally derived from xfs_mod_incore_sb().
554 libxfs_mod_incore_sb(xfs_mount_t
*mp
, xfs_sb_field_t field
, int delta
, int rsvd
)
556 long long lcounter
; /* long counter for 64 bit fields */
559 case XFS_SBS_FDBLOCKS
:
560 lcounter
= (long long)mp
->m_sb
.sb_fdblocks
;
563 return (XFS_ERROR(ENOSPC
));
564 mp
->m_sb
.sb_fdblocks
= lcounter
;
575 xfs_bmap_free_t
*flist
,
576 xfs_fsblock_t firstblock
,
579 xfs_bmap_free_item_t
*free
; /* free extent list item */
580 xfs_bmap_free_item_t
*next
; /* next item on free list */
583 if (flist
->xbf_count
== 0) {
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
)))
593 xfs_bmap_del_free(flist
, NULL
, free
);
599 * This routine allocates disk space for the given file.
600 * Originally derived from xfs_alloc_file_space().
603 libxfs_alloc_file_space(
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];
621 xfs_fileoff_t startoffset_fsb
;
634 xfs_bmapi_flags
= XFS_BMAPI_WRITE
| (alloc_type
? XFS_BMAPI_PREALLOC
: 0);
636 startoffset_fsb
= XFS_B_TO_FSBT(mp
, offset
);
637 allocatesize_fsb
= XFS_B_TO_FSB(mp
, count
);
639 /* allocate file space until done or until there is an error */
640 while (allocatesize_fsb
&& !error
) {
641 datablocks
= allocatesize_fsb
;
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);
648 xfs_trans_ijoin(tp
, ip
, 0);
649 xfs_trans_ihold(tp
, ip
);
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
);
658 /* complete the transaction */
659 error
= xfs_bmap_finish(&tp
, &free_list
, firstfsb
, &committed
);
663 error
= xfs_trans_commit(tp
, 0, NULL
);
667 allocated_fsb
= imapp
->br_blockcount
;
671 startoffset_fsb
+= allocated_fsb
;
672 allocatesize_fsb
-= allocated_fsb
;
678 libxfs_log2_roundup(unsigned int i
)
682 for (rval
= 0; rval
< NBBY
* sizeof(i
); rval
++) {
683 if ((1 << rval
) >= i
)
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).
693 * Originally from xfs_da_btree.c in the kernel, but only used
694 * in userspace so it now resides here.
701 xfs_daddr_t mappedbno
,
705 return libxfs_da_do_buf(trans
, dp
, bno
, &mappedbno
, bpp
, whichfork
, 2,
706 (inst_t
*)__return_address
);
710 * Hold dabuf at transaction commit.
712 * Originally from xfs_da_btree.c in the kernel, but only used
713 * in userspace so it now resides here.
716 libxfs_da_bhold(xfs_trans_t
*tp
, xfs_dabuf_t
*dabuf
)
720 for (i
= 0; i
< dabuf
->nbuf
; i
++)
721 xfs_trans_bhold(tp
, dabuf
->bps
[i
]);
725 * Join dabuf to transaction.
727 * Originally from xfs_da_btree.c in the kernel, but only used
728 * in userspace so it now resides here.
731 libxfs_da_bjoin(xfs_trans_t
*tp
, xfs_dabuf_t
*dabuf
)
735 for (i
= 0; i
< dabuf
->nbuf
; i
++)
736 xfs_trans_bjoin(tp
, dabuf
->bps
[i
]);