1 /* $NetBSD: nilfs_subr.c,v 1.3 2009/07/29 13:23:23 reinoud Exp $ */
4 * Copyright (c) 2008, 2009 Reinoud Zandijk
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #include <sys/cdefs.h>
31 __KERNEL_RCSID(0, "$NetBSD: nilfs_subr.c,v 1.3 2009/07/29 13:23:23 reinoud Exp $");
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/namei.h>
37 #include <sys/resourcevar.h> /* defines plimit structure in proc struct */
38 #include <sys/kernel.h>
39 #include <sys/file.h> /* define FWRITE ... */
43 #include <sys/mount.h>
44 #include <sys/vnode.h>
45 #include <sys/signalvar.h>
46 #include <sys/malloc.h>
47 #include <sys/dirent.h>
48 #include <sys/lockf.h>
49 #include <sys/kauth.h>
50 #include <sys/dirhash.h>
52 #include <miscfs/genfs/genfs.h>
53 #include <uvm/uvm_extern.h>
55 #include <fs/nilfs/nilfs_mount.h>
57 #include "nilfs_subr.h"
58 #include "nilfs_bswap.h"
61 #define VTOI(vnode) ((struct nilfs_node *) (vnode)->v_data)
63 /* basic calculators */
64 uint64_t nilfs_get_segnum_of_block(struct nilfs_device
*nilfsdev
,
67 return blocknr
/ nilfs_rw32(nilfsdev
->super
.s_blocks_per_segment
);
72 nilfs_get_segment_range(struct nilfs_device
*nilfsdev
, uint64_t segnum
,
73 uint64_t *seg_start
, uint64_t *seg_end
)
75 uint64_t blks_per_seg
;
77 blks_per_seg
= nilfs_rw64(nilfsdev
->super
.s_blocks_per_segment
);
78 *seg_start
= blks_per_seg
* segnum
;
79 *seg_end
= *seg_start
+ blks_per_seg
-1;
81 *seg_start
= nilfs_rw64(nilfsdev
->super
.s_first_data_block
);
85 void nilfs_calc_mdt_consts(struct nilfs_device
*nilfsdev
,
86 struct nilfs_mdt
*mdt
, int entry_size
)
88 uint32_t blocksize
= nilfsdev
->blocksize
;
90 mdt
->entries_per_group
= blocksize
* 8; /* bits in sector */
91 mdt
->entries_per_block
= blocksize
/ entry_size
;
93 mdt
->blocks_per_group
=
94 (mdt
->entries_per_group
-1) / mdt
->entries_per_block
+ 1 + 1;
95 mdt
->groups_per_desc_block
=
96 blocksize
/ sizeof(struct nilfs_block_group_desc
);
97 mdt
->blocks_per_desc_block
=
98 mdt
->groups_per_desc_block
* mdt
->blocks_per_group
+ 1;
102 /* from NetBSD's src/sys/net/if_ethersubr.c */
104 crc32_le(uint32_t crc
, const uint8_t *buf
, size_t len
)
106 static const uint32_t crctab
[] = {
107 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
108 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
109 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
110 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
114 for (i
= 0; i
< len
; i
++) {
116 crc
= (crc
>> 4) ^ crctab
[crc
& 0xf];
117 crc
= (crc
>> 4) ^ crctab
[crc
& 0xf];
125 nilfs_calchash(uint64_t ino
)
133 nilfs_dev_bread(struct nilfs_device
*nilfsdev
, uint64_t blocknr
,
134 struct kauth_cred
*cred
, int flags
, struct buf
**bpp
)
136 int blk2dev
= nilfsdev
->blocksize
/ DEV_BSIZE
;
138 return bread(nilfsdev
->devvp
, blocknr
* blk2dev
, nilfsdev
->blocksize
,
145 nilfs_bread(struct nilfs_node
*node
, uint64_t blocknr
,
146 struct kauth_cred
*cred
, int flags
, struct buf
**bpp
)
148 return bread(node
->vnode
, blocknr
, node
->nilfsdev
->blocksize
,
153 /* segment-log reading */
155 nilfs_get_segment_log(struct nilfs_device
*nilfsdev
, uint64_t *blocknr
,
156 uint64_t *offset
, struct buf
**bpp
, int len
, void *blob
)
158 int blocksize
= nilfsdev
->blocksize
;
161 KASSERT(len
<= blocksize
);
163 if (*offset
+ len
> blocksize
) {
164 *blocknr
= *blocknr
+ 1;
169 brelse(*bpp
, BC_AGE
);
171 error
= nilfs_dev_bread(nilfsdev
, *blocknr
, NOCRED
, 0, bpp
);
175 memcpy(blob
, ((uint8_t *) (*bpp
)->b_data
) + *offset
, len
);
181 /* -------------------------------------------------------------------------- */
183 /* btree operations */
186 nilfs_btree_lookup_level(struct nilfs_node
*node
, uint64_t lblocknr
,
187 uint64_t btree_vblknr
, int level
, uint64_t *vblocknr
)
189 struct nilfs_device
*nilfsdev
= node
->nilfsdev
;
190 struct nilfs_btree_node
*btree_hdr
;
192 uint64_t btree_blknr
;
193 uint64_t *dkeys
, *dptrs
, child_btree_blk
;
195 int i
, error
, selected
;
197 DPRINTF(TRANSLATE
, ("nilfs_btree_lookup_level ino %"PRIu64
", "
198 "lblocknr %"PRIu64
", btree_vblknr %"PRIu64
", level %d\n",
199 node
->ino
, lblocknr
, btree_vblknr
, level
));
201 /* translate btree_vblknr */
202 error
= nilfs_nvtop(node
, 1, &btree_vblknr
, &btree_blknr
);
207 error
= nilfs_dev_bread(nilfsdev
, btree_blknr
, NOCRED
, 0, &bp
);
213 btree_hdr
= (struct nilfs_btree_node
*) bp
->b_data
;
214 pos
= (uint8_t *) bp
->b_data
+
215 sizeof(struct nilfs_btree_node
) +
216 NILFS_BTREE_NODE_EXTRA_PAD_SIZE
;
217 dkeys
= (uint64_t *) pos
;
218 dptrs
= dkeys
+ NILFS_BTREE_NODE_NCHILDREN_MAX(nilfsdev
->blocksize
);
220 assert((btree_hdr
->bn_flags
& NILFS_BTREE_NODE_ROOT
) == 0);
222 /* select matching child XXX could use binary search */
224 for (i
= 0; i
< nilfs_rw16(btree_hdr
->bn_nchildren
); i
++) {
225 if (dkeys
[i
] > lblocknr
)
231 /* if found it mapped */
232 if (dkeys
[selected
] == lblocknr
)
233 *vblocknr
= dptrs
[selected
];
238 /* lookup in selected child */
239 assert(dkeys
[selected
] <= lblocknr
);
240 child_btree_blk
= dptrs
[selected
];
243 return nilfs_btree_lookup_level(node
, lblocknr
,
244 child_btree_blk
, btree_hdr
->bn_level
-1, vblocknr
);
248 /* internal function */
250 nilfs_btree_lookup(struct nilfs_node
*node
, uint64_t lblocknr
,
253 struct nilfs_inode
*inode
= &node
->inode
;
254 struct nilfs_btree_node
*btree_hdr
;
255 uint64_t *dkeys
, *dptrs
, *dtrans
;
259 DPRINTF(TRANSLATE
, ("nilfs_btree_lookup ino %"PRIu64
", "
260 "lblocknr %"PRIu64
"\n", node
->ino
, lblocknr
));
262 btree_hdr
= (struct nilfs_btree_node
*) &inode
->i_bmap
[0];
263 dkeys
= &inode
->i_bmap
[1];
264 dptrs
= dkeys
+ NILFS_BTREE_ROOT_NCHILDREN_MAX
;
265 dtrans
= &inode
->i_bmap
[1];
267 /* SMALL, direct lookup */
269 if ((btree_hdr
->bn_flags
& NILFS_BMAP_LARGE
) == 0) {
270 if (lblocknr
< NILFS_DIRECT_NBLOCKS
) {
271 *vblocknr
= dtrans
[lblocknr
];
274 /* not mapped XXX could be considered error here */
278 /* LARGE, select matching child; XXX could use binary search */
282 for (i
= 0; i
< nilfs_rw16(btree_hdr
->bn_nchildren
); i
++) {
283 if (dkeys
[i
] > lblocknr
)
288 /* if selected key > lblocknr, its not mapped */
289 if (dkeys
[selected
] > lblocknr
)
292 /* overshooting? then not mapped */
293 if (selected
== nilfs_rw16(btree_hdr
->bn_nchildren
))
296 /* level should be > 1 or otherwise it should be a direct one */
297 assert(btree_hdr
->bn_level
> 1);
299 /* lookup in selected child */
300 assert(dkeys
[selected
] <= lblocknr
);
301 error
= nilfs_btree_lookup_level(node
, lblocknr
,
302 dptrs
[selected
], btree_hdr
->bn_level
-1, vblocknr
);
308 /* node should be locked on entry to prevent btree changes (unlikely) */
310 nilfs_btree_nlookup(struct nilfs_node
*node
, uint64_t from
, uint64_t blks
,
313 uint64_t lblocknr
, *vblocknr
;
316 /* TODO / OPTI multiple translations in one go possible */
318 for (i
= 0; i
< blks
; i
++) {
320 vblocknr
= l2vmap
+ i
;
321 error
= nilfs_btree_lookup(node
, lblocknr
, vblocknr
);
323 DPRINTF(TRANSLATE
, ("btree_nlookup ino %"PRIu64
", "
324 "lblocknr %"PRIu64
" -> %"PRIu64
"\n",
325 node
->ino
, lblocknr
, *vblocknr
));
333 /* --------------------------------------------------------------------- */
335 /* vtop operations */
337 /* translate index to a file block number and an entry */
339 nilfs_mdt_trans(struct nilfs_mdt
*mdt
, uint64_t index
,
340 uint64_t *blocknr
, uint32_t *entry_in_block
)
343 uint64_t group
, group_offset
, blocknr_in_group
;
344 uint64_t desc_block
, desc_offset
;
346 /* calculate our offset in the file */
347 group
= index
/ mdt
->entries_per_group
;
348 group_offset
= index
% mdt
->entries_per_group
;
349 desc_block
= group
/ mdt
->groups_per_desc_block
;
350 desc_offset
= group
% mdt
->groups_per_desc_block
;
351 blocknr_in_group
= group_offset
/ mdt
->entries_per_block
;
353 /* to descgroup offset */
354 blknr
= 1 + desc_block
* mdt
->blocks_per_desc_block
;
356 /* to group offset */
357 blknr
+= desc_offset
* mdt
->blocks_per_group
;
359 /* to actual file block */
360 blknr
+= 1 + blocknr_in_group
;
363 *entry_in_block
= group_offset
% mdt
->entries_per_block
;
368 nilfs_vtop(struct nilfs_device
*nilfsdev
, uint64_t vblocknr
, uint64_t *pblocknr
)
370 struct nilfs_dat_entry
*entry
;
373 uint32_t entry_in_block
;
376 nilfs_mdt_trans(&nilfsdev
->dat_mdt
, vblocknr
,
377 &ldatblknr
, &entry_in_block
);
379 error
= nilfs_bread(nilfsdev
->dat_node
, ldatblknr
, NOCRED
, 0, &bp
);
381 printf("vtop: can't read in DAT block %"PRIu64
"!\n", ldatblknr
);
386 /* get our translation */
387 entry
= ((struct nilfs_dat_entry
*) bp
->b_data
) + entry_in_block
;
389 printf("\tvblk %4"PRIu64
" -> %"PRIu64
" for "
390 "checkpoint %"PRIu64
" to %"PRIu64
"\n",
392 nilfs_rw64(entry
->de_blocknr
),
393 nilfs_rw64(entry
->de_start
),
394 nilfs_rw64(entry
->de_end
));
397 *pblocknr
= nilfs_rw64(entry
->de_blocknr
);
405 nilfs_nvtop(struct nilfs_node
*node
, uint64_t blks
, uint64_t *l2vmap
,
408 uint64_t vblocknr
, *pblocknr
;
411 /* the DAT inode is the only one not mapped virtual */
412 if (node
->ino
== NILFS_DAT_INO
) {
413 memcpy(v2pmap
, l2vmap
, blks
* sizeof(uint64_t));
417 /* TODO / OPTI more translations in one go */
419 for (i
= 0; i
< blks
; i
++) {
420 vblocknr
= l2vmap
[i
];
421 pblocknr
= v2pmap
+ i
;
424 /* only translate valid vblocknrs */
427 error
= nilfs_vtop(node
->nilfsdev
, vblocknr
, pblocknr
);
435 /* --------------------------------------------------------------------- */
437 struct nilfs_recover_info
{
441 struct nilfs_segment_summary segsum
;
442 struct nilfs_super_root super_root
;
443 STAILQ_ENTRY(nilfs_recover_info
) next
;
448 * Helper functions of nilfs_mount() that actually mounts the disc.
451 nilfs_load_segsum(struct nilfs_device
*nilfsdev
,
452 struct nilfs_recover_info
*ri
)
455 uint64_t blocknr
, offset
;
456 uint32_t segsum_struct_size
;
460 segsum_struct_size
= sizeof(struct nilfs_segment_summary
);
462 /* read in segsum structure */
466 error
= nilfs_get_segment_log(nilfsdev
,
467 &blocknr
, &offset
, &bp
,
468 segsum_struct_size
, (void *) &ri
->segsum
);
473 magic
= nilfs_rw32(ri
->segsum
.ss_magic
);
474 if (magic
!= NILFS_SEGSUM_MAGIC
) {
475 DPRINTF(VOLUMES
, ("nilfs: bad magic in pseg %"PRIu64
"\n",
481 /* TODO check segment summary checksum */
482 /* TODO check data checksum */
484 /* adjust our walking point if we have an odd size */
485 if (segsum_struct_size
!= nilfs_rw32(ri
->segsum
.ss_bytes
)) {
486 printf("nilfs: WARNING encountered segsum_struct size %d in "
488 nilfs_rw32(ri
->segsum
.ss_bytes
), ri
->pseg
);
489 /* XXX report as an error? */
501 nilfs_load_super_root(struct nilfs_device
*nilfsdev
,
502 struct nilfs_recover_info
*ri
)
504 struct nilfs_segment_summary
*segsum
= &ri
->segsum
;
505 struct nilfs_super_root
*super_root
;
507 uint64_t blocknr
, offset
;
508 uint32_t segsum_size
, size
;
509 uint32_t nsumblk
, nfileblk
;
510 uint32_t super_root_crc
, comp_crc
;
513 /* process segment summary */
514 segsum_size
= nilfs_rw32(segsum
->ss_sumbytes
);
515 nsumblk
= (segsum_size
- 1) / nilfsdev
->blocksize
+ 1;
516 nfileblk
= nilfs_rw32(segsum
->ss_nblocks
) - nsumblk
;
518 /* check if there is a superroot */
519 if ((nilfs_rw16(segsum
->ss_flags
) & NILFS_SS_SR
) == 0) {
520 DPRINTF(VOLUMES
, ("nilfs: no super root in pseg %"PRIu64
"\n",
525 /* get our super root, located at the end of the pseg */
526 blocknr
= ri
->pseg
+ nsumblk
+ nfileblk
- 1;
528 size
= sizeof(struct nilfs_super_root
);
530 error
= nilfs_get_segment_log(nilfsdev
,
531 &blocknr
, &offset
, &bp
,
532 size
, (void *) &nilfsdev
->super_root
);
536 printf("read in of superroot failed\n");
540 /* check super root crc */
541 super_root
= &nilfsdev
->super_root
;
542 super_root_crc
= nilfs_rw32(super_root
->sr_sum
);
543 off
= sizeof(super_root
->sr_sum
);
544 comp_crc
= crc32_le(nilfs_rw32(nilfsdev
->super
.s_crc_seed
),
545 (uint8_t *) super_root
+ off
,
546 NILFS_SR_BYTES
- off
);
547 if (super_root_crc
!= comp_crc
) {
548 DPRINTF(VOLUMES
, (" invalid superroot, likely from old format\n"));
552 DPRINTF(VOLUMES
, (" got valid superroot\n"));
558 * Search for the last super root recorded.
561 nilfs_search_super_root(struct nilfs_device
*nilfsdev
)
563 struct nilfs_super_block
*super
;
564 struct nilfs_segment_summary
*segsum
;
565 struct nilfs_recover_info
*ri
, *ori
, *i_ri
;
566 STAILQ_HEAD(,nilfs_recover_info
) ri_list
;
567 uint64_t seg_start
, seg_end
, cno
;
568 uint32_t segsum_size
;
569 uint32_t nsumblk
, nfileblk
;
572 STAILQ_INIT(&ri_list
);
574 /* search for last super root */
575 ri
= malloc(sizeof(struct nilfs_recover_info
), M_NILFSTEMP
, M_WAITOK
);
576 memset(ri
, 0, sizeof(struct nilfs_recover_info
));
578 /* if enabled, start from the specified position */
580 /* start from set start */
581 nilfsdev
->super
.s_last_pseg
= nilfsdev
->super
.s_first_data_block
;
582 nilfsdev
->super
.s_last_cno
= nilfs_rw64(1);
585 ri
->pseg
= nilfs_rw64(nilfsdev
->super
.s_last_pseg
); /* blknr */
586 ri
->segnum
= nilfs_get_segnum_of_block(nilfsdev
, ri
->pseg
);
589 cno
= nilfs_rw64(nilfsdev
->super
.s_last_cno
);
590 DPRINTF(VOLUMES
, ("nilfs: seach_super_root start in pseg %"PRIu64
"\n",
593 DPRINTF(VOLUMES
, (" at pseg %"PRIu64
"\n", ri
->pseg
));
594 error
= nilfs_load_segsum(nilfsdev
, ri
);
598 segsum
= &ri
->segsum
;
600 /* try to load super root */
601 if (nilfs_rw16(segsum
->ss_flags
) & NILFS_SS_SR
) {
602 DPRINTF(VOLUMES
, (" try super root\n"));
603 error
= nilfs_load_super_root(nilfsdev
, ri
);
605 break; /* confused */
606 /* wipe current list of ri */
607 while (!STAILQ_EMPTY(&ri_list
)) {
608 i_ri
= STAILQ_FIRST(&ri_list
);
609 STAILQ_REMOVE_HEAD(&ri_list
, next
);
610 free(i_ri
, M_NILFSTEMP
);
612 super
= &nilfsdev
->super
;
614 super
->s_last_pseg
= nilfs_rw64(ri
->pseg
);
615 super
->s_last_cno
= cno
++;
616 super
->s_last_seq
= segsum
->ss_seq
;
617 super
->s_state
= nilfs_rw16(NILFS_VALID_FS
);
619 STAILQ_INSERT_TAIL(&ri_list
, ri
, next
);
621 ri
= malloc(sizeof(struct nilfs_recover_info
),
622 M_NILFSTEMP
, M_WAITOK
);
623 memset(ri
, 0, sizeof(struct nilfs_recover_info
));
624 ri
->segnum
= ori
->segnum
;
625 ri
->pseg
= ori
->pseg
;
626 /* segsum keeps pointing to the `old' ri */
629 /* continue to the next pseg */
630 segsum_size
= nilfs_rw32(segsum
->ss_sumbytes
);
631 nsumblk
= (segsum_size
- 1) / nilfsdev
->blocksize
+ 1;
632 nfileblk
= nilfs_rw32(segsum
->ss_nblocks
) - nsumblk
;
634 /* calculate next partial segment location */
635 ri
->pseg
+= nsumblk
+ nfileblk
;
637 /* did we reach the end of the segment? if so, go to the next */
638 nilfs_get_segment_range(nilfsdev
, ri
->segnum
, &seg_start
, &seg_end
);
639 if (ri
->pseg
>= seg_end
)
640 ri
->pseg
= nilfs_rw64(segsum
->ss_next
);
641 ri
->segnum
= nilfs_get_segnum_of_block(nilfsdev
, ri
->pseg
);
645 * XXX No roll-forward yet of the remaining partial segments.
648 /* wipe current list of ri */
649 while (!STAILQ_EMPTY(&ri_list
)) {
650 i_ri
= STAILQ_FIRST(&ri_list
);
651 STAILQ_REMOVE_HEAD(&ri_list
, next
);
652 printf("nilfs: ignoring pseg at %"PRIu64
"\n", i_ri
->pseg
);
653 free(i_ri
, M_NILFSTEMP
);
655 free(ri
, M_NILFSTEMP
);
658 /* --------------------------------------------------------------------- */
663 * static const struct genfs_ops nilfs_genfsops = {
664 * .gop_size = genfs_size,
666 * .gop_alloc = nilfs_gop_alloc,
667 * allocate len bytes at offset
668 * .gop_write = genfs_gop_write,
669 * putpages interface code
670 * .gop_markupdate = nilfs_gop_markupdate,
671 * set update/modify flags etc.
676 * Callback from genfs to allocate len bytes at offset off; only called when
677 * filling up gaps in the allocation.
680 nilfs_gop_alloc(struct vnode
*vp
, off_t off
,
681 off_t len
, int flags
, kauth_cred_t cred
)
683 DPRINTF(NOTIMPL
, ("nilfs_gop_alloc not implemented\n"));
684 DPRINTF(ALLOC
, ("nilfs_gop_alloc called for %"PRIu64
" bytes\n", len
));
691 * callback from genfs to update our flags
694 nilfs_gop_markupdate(struct vnode
*vp
, int flags
)
696 struct nilfs_node
*nilfs_node
= VTOI(vp
);
699 if ((flags
& GOP_UPDATE_ACCESSED
) != 0) {
702 if ((flags
& GOP_UPDATE_MODIFIED
) != 0) {
703 if (vp
->v_type
== VREG
) {
704 mask
|= IN_CHANGE
| IN_UPDATE
;
710 nilfs_node
->i_flags
|= mask
;
715 static const struct genfs_ops nilfs_genfsops
= {
716 .gop_size
= genfs_size
,
717 .gop_alloc
= nilfs_gop_alloc
,
718 .gop_write
= genfs_gop_write_rwmap
,
719 .gop_markupdate
= nilfs_gop_markupdate
,
722 /* --------------------------------------------------------------------- */
725 nilfs_register_node(struct nilfs_node
*node
)
727 struct nilfs_mount
*ump
;
728 struct nilfs_node
*chk
;
732 mutex_enter(&ump
->ihash_lock
);
734 /* add to our hash table */
735 hashline
= nilfs_calchash(node
->ino
) & NILFS_INODE_HASHMASK
;
737 LIST_FOREACH(chk
, &ump
->nilfs_nodes
[hashline
], hashchain
) {
739 if (chk
->ino
== node
->ino
)
740 panic("Double node entered\n");
745 LIST_INSERT_HEAD(&ump
->nilfs_nodes
[hashline
], node
, hashchain
);
747 mutex_exit(&ump
->ihash_lock
);
752 nilfs_deregister_node(struct nilfs_node
*node
)
754 struct nilfs_mount
*ump
;
757 mutex_enter(&ump
->ihash_lock
);
759 /* remove from hash list */
760 LIST_REMOVE(node
, hashchain
);
762 mutex_exit(&ump
->ihash_lock
);
766 static struct nilfs_node
*
767 nilfs_hash_lookup(struct nilfs_mount
*ump
, ino_t ino
)
769 struct nilfs_node
*node
;
774 mutex_enter(&ump
->ihash_lock
);
776 /* search our hash table */
777 hashline
= nilfs_calchash(ino
) & NILFS_INODE_HASHMASK
;
778 LIST_FOREACH(node
, &ump
->nilfs_nodes
[hashline
], hashchain
) {
780 if (node
->ino
== ino
) {
783 mutex_enter(&vp
->v_interlock
);
784 mutex_exit(&ump
->ihash_lock
);
785 if (vget(vp
, LK_EXCLUSIVE
| LK_INTERLOCK
))
790 mutex_exit(&ump
->ihash_lock
);
796 /* node action implementators */
797 extern int (**nilfs_vnodeop_p
)(void *);
800 nilfs_get_node_raw(struct nilfs_device
*nilfsdev
, struct nilfs_mount
*ump
,
801 uint64_t ino
, struct nilfs_inode
*inode
, struct nilfs_node
**nodep
)
803 struct nilfs_node
*node
;
806 int (**vnodeops
)(void *);
810 vnodeops
= nilfs_vnodeop_p
;
812 /* associate with mountpoint if present*/
813 mp
= ump
? ump
->vfs_mountp
: NULL
;
814 error
= getnewvnode(VT_NILFS
, mp
, vnodeops
, &nvp
);
819 error
= vn_lock(nvp
, LK_EXCLUSIVE
| LK_RETRY
);
826 node
= pool_get(&nilfs_node_pool
, PR_WAITOK
);
827 memset(node
, 0, sizeof(struct nilfs_node
));
832 node
->nilfsdev
= nilfsdev
;
835 /* initiase nilfs node */
837 node
->inode
= *inode
;
841 mutex_init(&node
->node_mutex
, MUTEX_DEFAULT
, IPL_NONE
);
842 cv_init(&node
->node_lock
, "nilfs_nlk");
844 /* initialise genfs */
845 genfs_node_init(nvp
, &nilfs_genfsops
);
847 /* check if we're fetching the root */
848 if (ino
== NILFS_ROOT_INO
)
849 nvp
->v_vflag
|= VV_ROOT
;
851 /* update vnode's file type XXX is there a function for this? */
853 if (S_ISDIR(inode
->i_mode
))
855 if (S_ISLNK(inode
->i_mode
))
858 if (S_ISCHR(inode
->i_mode
))
860 if (S_ISBLK(inode
->i_mode
))
865 /* fixup inode size for system nodes */
866 if ((ino
< NILFS_USER_INO
) && (ino
!= NILFS_ROOT_INO
)) {
867 DPRINTF(VOLUMES
, ("NEED TO GET my size for inode %"PRIu64
"\n",
869 /* for now set it to maximum, -1 is illegal */
870 inode
->i_size
= nilfs_rw64(((uint64_t) -2));
873 uvm_vnp_setsize(nvp
, nilfs_rw64(inode
->i_size
));
876 nilfs_register_node(node
);
885 nilfs_get_node(struct nilfs_mount
*ump
, uint64_t ino
, struct nilfs_node
**nodep
)
887 struct nilfs_device
*nilfsdev
;
888 struct nilfs_inode inode
, *entry
;
891 uint32_t entry_in_block
;
894 /* lookup node in hash table */
895 *nodep
= nilfs_hash_lookup(ump
, ino
);
899 /* lock to disallow simultanious creation of same udf_node */
900 mutex_enter(&ump
->get_node_lock
);
902 /* relookup since it could be created while waiting for the mutex */
903 *nodep
= nilfs_hash_lookup(ump
, ino
);
905 mutex_exit(&ump
->get_node_lock
);
909 /* create new inode; XXX check could be handier */
910 if ((ino
< NILFS_ATIME_INO
) && (ino
!= NILFS_ROOT_INO
)) {
911 printf("nilfs_get_node: system ino %"PRIu64
" not in mount "
913 mutex_exit(&ump
->get_node_lock
);
917 /* lookup inode in the ifile */
918 DPRINTF(NODE
, ("lookup ino %"PRIu64
"\n", ino
));
920 /* lookup inode structure in mountpoints ifile */
921 nilfsdev
= ump
->nilfsdev
;
922 nilfs_mdt_trans(&nilfsdev
->ifile_mdt
, ino
, &ivblocknr
, &entry_in_block
);
924 error
= nilfs_bread(ump
->ifile_node
, ivblocknr
, NOCRED
, 0, &bp
);
926 mutex_exit(&ump
->get_node_lock
);
930 /* get inode entry */
931 entry
= (struct nilfs_inode
*) bp
->b_data
+ entry_in_block
;
936 error
= nilfs_get_node_raw(ump
->nilfsdev
, ump
, ino
, &inode
, nodep
);
937 mutex_exit(&ump
->get_node_lock
);
944 nilfs_dispose_node(struct nilfs_node
**nodep
)
947 struct nilfs_node
*node
;
949 /* protect against rogue values */
956 /* remove dirhash if present */
957 dirhash_purge(&node
->dir_hash
);
959 /* remove from our hash lookup table */
961 nilfs_deregister_node(node
);
963 /* destroy our locks */
964 mutex_destroy(&node
->node_mutex
);
965 cv_destroy(&node
->node_lock
);
967 /* dissociate from our vnode */
968 genfs_node_destroy(node
->vnode
);
971 /* free our associated memory */
972 pool_put(&nilfs_node_pool
, node
);
979 nilfs_itimes(struct nilfs_node
*node
, struct timespec
*acc
,
980 struct timespec
*mod
, struct timespec
*birth
)
986 nilfs_update(struct vnode
*node
, struct timespec
*acc
,
987 struct timespec
*mod
, struct timespec
*birth
, int updflags
)
994 nilfs_chsize(struct vnode
*vp
, u_quad_t newsize
, kauth_cred_t cred
)
1002 nilfs_grow_node(struct nilfs_node
*node
, uint64_t new_size
)
1009 nilfs_shrink_node(struct nilfs_node
*node
, uint64_t new_size
)
1016 dirhash_fill(struct nilfs_node
*dir_node
)
1018 struct vnode
*dvp
= dir_node
->vnode
;
1019 struct dirhash
*dirh
;
1020 struct nilfs_dir_entry
*ndirent
;
1021 struct dirent dirent
;
1023 uint64_t file_size
, diroffset
, blkoff
;
1025 uint32_t blocksize
= dir_node
->nilfsdev
->blocksize
;
1026 uint8_t *pos
, name_len
;
1029 DPRINTF(CALL
, ("dirhash_fill called\n"));
1031 if (dvp
->v_type
!= VDIR
)
1034 /* make sure we have a dirhash to work on */
1035 dirh
= dir_node
->dir_hash
;
1037 KASSERT(dirh
->refcnt
> 0);
1039 if (dirh
->flags
& DIRH_BROKEN
)
1042 if (dirh
->flags
& DIRH_COMPLETE
)
1045 DPRINTF(DIRHASH
, ("Filling directory hash\n"));
1047 /* make sure we have a clean dirhash to add to */
1048 dirhash_purge_entries(dirh
);
1050 /* get directory filesize */
1051 file_size
= nilfs_rw64(dir_node
->inode
.i_size
);
1053 /* walk the directory */
1057 blocknr
= diroffset
/ blocksize
;
1058 blkoff
= diroffset
% blocksize
;
1059 error
= nilfs_bread(dir_node
, blocknr
, NOCRED
, 0, &bp
);
1061 dirh
->flags
|= DIRH_BROKEN
;
1062 dirhash_purge_entries(dirh
);
1065 while (diroffset
< file_size
) {
1066 DPRINTF(READDIR
, ("filldir : offset = %"PRIu64
"\n",
1068 if (blkoff
>= blocksize
) {
1069 blkoff
= 0; blocknr
++;
1071 error
= nilfs_bread(dir_node
, blocknr
, NOCRED
, 0,
1074 dirh
->flags
|= DIRH_BROKEN
;
1075 dirhash_purge_entries(dirh
);
1080 /* read in one dirent */
1081 pos
= (uint8_t *) bp
->b_data
+ blkoff
;
1082 ndirent
= (struct nilfs_dir_entry
*) pos
;
1083 name_len
= ndirent
->name_len
;
1085 memset(&dirent
, 0, sizeof(struct dirent
));
1086 dirent
.d_fileno
= nilfs_rw64(ndirent
->inode
);
1087 dirent
.d_type
= ndirent
->file_type
; /* 1:1 ? */
1088 dirent
.d_namlen
= name_len
;
1089 strncpy(dirent
.d_name
, ndirent
->name
, name_len
);
1090 dirent
.d_reclen
= _DIRENT_SIZE(&dirent
);
1091 DPRINTF(DIRHASH
, ("copying `%*.*s`\n", name_len
,
1092 name_len
, dirent
.d_name
));
1094 /* XXX is it deleted? extra free space? */
1095 dirhash_enter(dirh
, &dirent
, diroffset
,
1096 nilfs_rw16(ndirent
->rec_len
), 0);
1099 diroffset
+= nilfs_rw16(ndirent
->rec_len
);
1100 blkoff
+= nilfs_rw16(ndirent
->rec_len
);
1104 dirh
->flags
|= DIRH_COMPLETE
;
1111 nilfs_lookup_name_in_dir(struct vnode
*dvp
, const char *name
, int namelen
,
1112 uint64_t *ino
, int *found
)
1114 struct nilfs_node
*dir_node
= VTOI(dvp
);
1115 struct nilfs_dir_entry
*ndirent
;
1116 struct dirhash
*dirh
;
1117 struct dirhash_entry
*dirh_ep
;
1119 uint64_t diroffset
, blkoff
;
1121 uint32_t blocksize
= dir_node
->nilfsdev
->blocksize
;
1125 /* set default return */
1128 /* get our dirhash and make sure its read in */
1129 dirhash_get(&dir_node
->dir_hash
);
1130 error
= dirhash_fill(dir_node
);
1132 dirhash_put(dir_node
->dir_hash
);
1135 dirh
= dir_node
->dir_hash
;
1137 /* allocate temporary space for fid */
1139 DPRINTF(DIRHASH
, ("dirhash_lookup looking for `%*.*s`\n",
1140 namelen
, namelen
, name
));
1142 /* search our dirhash hits */
1146 hit
= dirhash_lookup(dirh
, name
, namelen
, &dirh_ep
);
1147 /* if no hit, abort the search */
1151 /* check this hit */
1152 diroffset
= dirh_ep
->offset
;
1154 blocknr
= diroffset
/ blocksize
;
1155 blkoff
= diroffset
% blocksize
;
1156 error
= nilfs_bread(dir_node
, blocknr
, NOCRED
, 0, &bp
);
1160 /* read in one dirent */
1161 pos
= (uint8_t *) bp
->b_data
+ blkoff
;
1162 ndirent
= (struct nilfs_dir_entry
*) pos
;
1164 DPRINTF(DIRHASH
, ("dirhash_lookup\tchecking `%*.*s`\n",
1165 ndirent
->name_len
, ndirent
->name_len
, ndirent
->name
));
1167 /* see if its our entry */
1168 KASSERT(ndirent
->name_len
== namelen
);
1169 if (strncmp(ndirent
->name
, name
, namelen
) == 0) {
1171 *ino
= nilfs_rw64(ndirent
->inode
);
1178 dirhash_put(dir_node
->dir_hash
);
1185 nilfs_dir_detach(struct nilfs_mount
*ump
, struct nilfs_node
*dir_node
, struct nilfs_node
*node
, struct componentname
*cnp
)
1192 nilfs_dir_attach(struct nilfs_mount
*ump
, struct nilfs_node
*dir_node
, struct nilfs_node
*node
, struct vattr
*vap
, struct componentname
*cnp
)
1198 /* XXX return vnode? */
1200 nilfs_create_node(struct vnode
*dvp
, struct vnode
**vpp
, struct vattr
*vap
, struct componentname
*cnp
)
1207 nilfs_delete_node(struct nilfs_node
*node
)