1 /* $NetBSD: bfs.c,v 1.11 2008/04/28 20:24:02 martin Exp $ */
4 * Copyright (c) 2004 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 #include <sys/cdefs.h>
34 __KERNEL_RCSID(0, "$NetBSD: bfs.c,v 1.11 2008/04/28 20:24:02 martin Exp $");
37 #include <sys/param.h>
38 #include <sys/kernel.h>
39 #include <sys/types.h>
40 #include <sys/systm.h>
41 #include <sys/errno.h>
42 #include <sys/malloc.h>
46 MALLOC_JUSTDEFINE(M_BFS
, "sysvbfs core", "sysvbfs internal structures");
47 #define __MALLOC(s, t, f) malloc(s, t, f)
48 #define __FREE(a, s, t) free(a, t)
49 #elif defined _STANDALONE
50 #include <lib/libsa/stand.h>
51 #include <lib/libkern/libkern.h>
52 #define __MALLOC(s, t, f) alloc(s)
53 #define __FREE(a, s, t) dealloc(a, s)
56 #define __MALLOC(s, t, f) malloc(s)
57 #define __FREE(a, s, t) free(a)
59 #include <fs/sysvbfs/bfs.h>
62 #define DPRINTF(on, fmt, args...) if (on) printf(fmt, ##args)
64 #define DPRINTF(arg...) ((void)0)
67 #define ROUND_SECTOR(x) (((x) + 511) & ~511)
68 #define TRUNC_SECTOR(x) ((x) & ~511)
72 STATIC
int bfs_init_superblock(struct bfs
*, int, size_t *);
73 STATIC
int bfs_init_inode(struct bfs
*, uint8_t *, size_t *);
74 STATIC
int bfs_init_dirent(struct bfs
*, uint8_t *);
76 /* super block ops. */
77 STATIC
bool bfs_superblock_valid(const struct bfs_super_block
*);
78 STATIC
bool bfs_writeback_dirent(const struct bfs
*, struct bfs_dirent
*,
80 STATIC
bool bfs_writeback_inode(const struct bfs
*, struct bfs_inode
*);
83 bfs_init2(struct bfs
**bfsp
, int bfs_sector
, struct sector_io_ops
*io
,
92 DPRINTF(debug
, "bfs sector = %d\n", bfs_sector
);
93 if ((bfs
= (void *)__MALLOC(sizeof(struct bfs
), M_BFS
, M_NOWAIT
)) == 0)
95 memset(bfs
, 0, sizeof *bfs
);
100 if ((err
= bfs_init_superblock(bfs
, bfs_sector
, &memsize
)) != 0) {
104 DPRINTF(debug
, "bfs super block + inode area = %zd\n", memsize
);
105 bfs
->super_block_size
= memsize
;
106 if ((p
= (void *)__MALLOC(memsize
, M_BFS
, M_NOWAIT
)) == 0) {
111 if ((err
= bfs_init_inode(bfs
, p
, &memsize
)) != 0) {
115 DPRINTF(debug
, "bfs dirent area = %zd\n", memsize
);
116 bfs
->dirent_size
= memsize
;
117 if ((p
= (void *)__MALLOC(memsize
, M_BFS
, M_NOWAIT
)) == 0) {
122 if ((err
= bfs_init_dirent(bfs
, p
)) != 0) {
136 bfs_fini(struct bfs
*bfs
)
141 if (bfs
->super_block
)
142 __FREE(bfs
->super_block
, bfs
->super_block_size
, M_BFS
);
144 __FREE(bfs
->dirent
, bfs
->dirent_size
, M_BFS
);
145 __FREE(bfs
, sizeof(struct bfs
), M_BFS
);
149 bfs_init_superblock(struct bfs
*bfs
, int bfs_sector
, size_t *required_memory
)
151 struct bfs_super_block super
;
153 bfs
->start_sector
= bfs_sector
;
155 /* Read super block */
156 if (!bfs
->io
->read(bfs
->io
, (uint8_t *)&super
, bfs_sector
))
159 if (!bfs_superblock_valid(&super
))
162 /* i-node table size */
163 bfs
->data_start
= super
.header
.data_start_byte
;
164 bfs
->data_end
= super
.header
.data_end_byte
;
166 bfs
->max_inode
= (bfs
->data_start
- sizeof(struct bfs_super_block
)) /
167 sizeof(struct bfs_inode
);
169 *required_memory
= ROUND_SECTOR(bfs
->data_start
);
175 bfs_init_inode(struct bfs
*bfs
, uint8_t *p
, size_t *required_memory
)
177 struct bfs_inode
*inode
, *root_inode
;
180 if (!bfs
->io
->read_n(bfs
->io
, p
, bfs
->start_sector
,
181 bfs
->data_start
>> DEV_BSHIFT
))
184 bfs
->super_block
= (struct bfs_super_block
*)p
;
185 bfs
->inode
= (struct bfs_inode
*)(p
+ sizeof(struct bfs_super_block
));
186 p
+= bfs
->data_start
;
191 for (i
= 0; i
< bfs
->max_inode
; i
++, inode
++) {
192 if (inode
->number
!= 0) {
194 if (inode
->number
== BFS_ROOT_INODE
)
198 DPRINTF(bfs
->debug
, "inode: %d/%d\n", bfs
->n_inode
, bfs
->max_inode
);
200 if (root_inode
== 0) {
201 DPRINTF(bfs
->debug
, "no root directory.\n");
204 /* dirent table size */
205 DPRINTF(bfs
->debug
, "root inode: %d-%d\n", root_inode
->start_sector
,
206 root_inode
->end_sector
);
207 bfs
->root_inode
= root_inode
;
209 *required_memory
= (root_inode
->end_sector
-
210 root_inode
->start_sector
+ 1) << DEV_BSHIFT
;
216 bfs_init_dirent(struct bfs
*bfs
, uint8_t *p
)
218 struct bfs_dirent
*file
;
219 struct bfs_inode
*inode
= bfs
->root_inode
;
222 n
= inode
->end_sector
- inode
->start_sector
+ 1;
224 if (!bfs
->io
->read_n(bfs
->io
, p
,
225 bfs
->start_sector
+ inode
->start_sector
, n
))
228 bfs
->dirent
= (struct bfs_dirent
*)p
;
229 bfs
->max_dirent
= (n
<< DEV_BSHIFT
) / sizeof(struct bfs_dirent
);
233 for (i
= 0; i
< bfs
->max_dirent
; i
++, file
++)
234 if (file
->inode
!= 0)
237 DPRINTF(bfs
->debug
, "dirent: %d/%d\n", bfs
->n_dirent
, bfs
->max_dirent
);
243 bfs_file_read(const struct bfs
*bfs
, const char *fname
, void *buf
, size_t bufsz
,
248 uint8_t tmpbuf
[DEV_BSIZE
];
251 if (!bfs_file_lookup(bfs
, fname
, &start
, &end
, &sz
))
259 if (!bfs
->io
->read_n(bfs
->io
, p
, start
, n
))
263 if (!bfs
->io
->read(bfs
->io
, tmpbuf
, end
))
265 memcpy(p
+ n
, tmpbuf
, sz
- n
);
274 bfs_file_write(struct bfs
*bfs
, const char *fname
, void *buf
,
277 struct bfs_fileattr attr
;
278 struct bfs_dirent
*dirent
;
279 char name
[BFS_FILENAME_MAXLEN
];
282 strncpy(name
, fname
, BFS_FILENAME_MAXLEN
);
284 if (bfs_dirent_lookup_by_name(bfs
, name
, &dirent
)) {
285 struct bfs_inode
*inode
;
286 if (!bfs_inode_lookup(bfs
, dirent
->inode
, &inode
)) {
287 DPRINTF(bfs
->debug
, "%s: dirent found, but inode "
288 "not found. inconsistent filesystem.\n",
292 attr
= inode
->attr
; /* copy old attribute */
293 bfs_file_delete(bfs
, name
);
294 if ((err
= bfs_file_create(bfs
, name
, buf
, bufsz
, &attr
)) != 0)
297 memset(&attr
, 0xff, sizeof attr
); /* Set VNOVAL all */
299 attr
.atime
= time_second
;
300 attr
.ctime
= time_second
;
301 attr
.mtime
= time_second
;
303 if ((err
= bfs_file_create(bfs
, name
, buf
, bufsz
, &attr
)) != 0)
311 bfs_file_delete(struct bfs
*bfs
, const char *fname
)
313 struct bfs_inode
*inode
;
314 struct bfs_dirent
*dirent
;
316 if (!bfs_dirent_lookup_by_name(bfs
, fname
, &dirent
))
319 if (!bfs_inode_lookup(bfs
, dirent
->inode
, &inode
))
322 memset(dirent
, 0, sizeof *dirent
);
323 memset(inode
, 0, sizeof *inode
);
327 bfs_writeback_dirent(bfs
, dirent
, false);
328 bfs_writeback_inode(bfs
, inode
);
329 DPRINTF(bfs
->debug
, "%s: \"%s\" deleted.\n", __func__
, fname
);
335 bfs_file_rename(struct bfs
*bfs
, const char *from_name
, const char *to_name
)
337 struct bfs_dirent
*dirent
;
340 if (strlen(to_name
) > BFS_FILENAME_MAXLEN
) {
344 if (!bfs_dirent_lookup_by_name(bfs
, from_name
, &dirent
)) {
349 bfs_file_delete(bfs
, to_name
);
350 strncpy(dirent
->name
, to_name
, BFS_FILENAME_MAXLEN
);
351 bfs_writeback_dirent(bfs
, dirent
, false);
354 DPRINTF(bfs
->debug
, "%s: \"%s\" -> \"%s\" error=%d.\n", __func__
,
355 from_name
, to_name
, err
);
361 bfs_file_create(struct bfs
*bfs
, const char *fname
, void *buf
, size_t bufsz
,
362 const struct bfs_fileattr
*attr
)
364 struct bfs_inode
*inode
;
365 struct bfs_dirent
*file
;
367 uint8_t *p
, tmpbuf
[DEV_BSIZE
];
370 /* Find free i-node and data block */
371 if ((err
= bfs_inode_alloc(bfs
, &inode
, &j
, &start
)) != 0)
374 /* File size (unit block) */
375 n
= (ROUND_SECTOR(bufsz
) >> DEV_BSHIFT
) - 1;
376 if (n
< 0) /* bufsz == 0 */
379 if ((start
+ n
) * DEV_BSIZE
>= bfs
->data_end
) {
380 DPRINTF(bfs
->debug
, "disk full.\n");
384 /* Find free dirent */
385 for (file
= bfs
->dirent
, i
= 0; i
< bfs
->max_dirent
; i
++, file
++)
386 if (file
->inode
== 0)
388 if (i
== bfs
->max_dirent
) {
389 DPRINTF(bfs
->debug
, "dirent full.\n");
394 memset(inode
, 0, sizeof *inode
);
396 inode
->start_sector
= start
;
397 inode
->end_sector
= start
+ n
;
398 inode
->eof_offset_byte
= start
* DEV_BSIZE
+ bufsz
- 1;
399 /* i-node attribute */
400 inode
->attr
.type
= 1;
401 inode
->attr
.mode
= 0;
402 inode
->attr
.nlink
= 1;
403 bfs_inode_set_attr(bfs
, inode
, attr
);
406 memset(file
, 0, sizeof *file
);
407 file
->inode
= inode
->number
;
408 strncpy(file
->name
, fname
, BFS_FILENAME_MAXLEN
);
410 DPRINTF(bfs
->debug
, "%s: start %d end %d\n", __func__
,
411 inode
->start_sector
, inode
->end_sector
);
417 for (i
= inode
->start_sector
; i
< inode
->end_sector
; i
++) {
418 if (!bfs
->io
->write(bfs
->io
, p
, bfs
->start_sector
+ i
))
424 memset(tmpbuf
, 0, DEV_BSIZE
);
425 memcpy(tmpbuf
, p
, bufsz
- n
);
426 if (!bfs
->io
->write(bfs
->io
, tmpbuf
, bfs
->start_sector
+ i
))
432 bfs_writeback_dirent(bfs
, file
, true);
433 bfs_writeback_inode(bfs
, inode
);
439 bfs_writeback_dirent(const struct bfs
*bfs
, struct bfs_dirent
*dir
,
442 struct bfs_dirent
*dir_base
= bfs
->dirent
;
443 struct bfs_inode
*root_inode
= bfs
->root_inode
;
447 i
= ((dir
- dir_base
) * sizeof *dir
) >> DEV_BSHIFT
;
449 eof
= (uintptr_t)(dir
+ 1) - 1;
450 eof
= eof
- (uintptr_t)dir_base
+
451 (root_inode
->start_sector
<< DEV_BSHIFT
);
453 /* update root directory inode */
455 printf("eof new=%d old=%d\n", eof
, root_inode
->eof_offset_byte
);
458 if (eof
> root_inode
->eof_offset_byte
) {
459 root_inode
->eof_offset_byte
= eof
;
462 /* delete the last entry */
463 if (eof
== root_inode
->eof_offset_byte
) {
464 root_inode
->eof_offset_byte
= eof
- sizeof *dir
;
467 bfs_writeback_inode(bfs
, root_inode
);
470 return bfs
->io
->write(bfs
->io
, (uint8_t *)dir_base
+ (i
<< DEV_BSHIFT
),
471 bfs
->start_sector
+ bfs
->root_inode
->start_sector
+ i
);
475 bfs_writeback_inode(const struct bfs
*bfs
, struct bfs_inode
*inode
)
477 struct bfs_inode
*inode_base
= bfs
->inode
;
480 i
= ((inode
- inode_base
) * sizeof *inode
) >> DEV_BSHIFT
;
482 return bfs
->io
->write(bfs
->io
,
483 (uint8_t *)inode_base
+ (i
<< DEV_BSHIFT
),
484 bfs
->start_sector
+ 1/*super block*/ + i
);
488 bfs_file_lookup(const struct bfs
*bfs
, const char *fname
, int *start
, int *end
,
491 struct bfs_inode
*inode
;
492 struct bfs_dirent
*dirent
;
494 if (!bfs_dirent_lookup_by_name(bfs
, fname
, &dirent
))
496 if (!bfs_inode_lookup(bfs
, dirent
->inode
, &inode
))
500 *start
= inode
->start_sector
+ bfs
->start_sector
;
502 *end
= inode
->end_sector
+ bfs
->start_sector
;
504 *size
= bfs_file_size(inode
);
506 DPRINTF(bfs
->debug
, "%s: %d + %d -> %d (%zd)\n",
507 fname
, bfs
->start_sector
, inode
->start_sector
,
508 inode
->end_sector
, *size
);
514 bfs_dirent_lookup_by_inode(const struct bfs
*bfs
, int inode
,
515 struct bfs_dirent
**dirent
)
517 struct bfs_dirent
*file
;
520 for (file
= bfs
->dirent
, i
= 0; i
< bfs
->max_dirent
; i
++, file
++)
521 if (file
->inode
== inode
)
524 if (i
== bfs
->max_dirent
)
533 bfs_dirent_lookup_by_name(const struct bfs
*bfs
, const char *fname
,
534 struct bfs_dirent
**dirent
)
536 struct bfs_dirent
*file
;
539 for (file
= bfs
->dirent
, i
= 0; i
< bfs
->max_dirent
; i
++, file
++)
540 if ((file
->inode
!= 0) &&
541 (strncmp(file
->name
, fname
, BFS_FILENAME_MAXLEN
) ==0))
544 if (i
== bfs
->max_dirent
)
553 bfs_inode_lookup(const struct bfs
*bfs
, ino_t n
, struct bfs_inode
**iinode
)
555 struct bfs_inode
*inode
;
558 for (inode
= bfs
->inode
, i
= 0; i
< bfs
->max_inode
; i
++, inode
++)
559 if (inode
->number
== n
)
562 if (i
== bfs
->max_inode
)
571 bfs_file_size(const struct bfs_inode
*inode
)
574 return inode
->eof_offset_byte
- inode
->start_sector
* DEV_BSIZE
+ 1;
578 bfs_inode_alloc(const struct bfs
*bfs
, struct bfs_inode
**free_inode
,
579 int *free_inode_number
, int *free_block
)
581 struct bfs_inode
*jnode
, *inode
;
588 for (i
= BFS_ROOT_INODE
; i
< bfs
->max_inode
; i
++, inode
++) {
593 /* Get free i-node */
594 if (jnode
== 0 && (inode
->number
== 0))
597 /* Get free i-node # and data block */
598 if (inode
->number
!= 0) {
599 if (inode
->end_sector
> start
)
600 start
= inode
->end_sector
;
601 if (inode
->number
== j
)
602 j
= 0; /* conflict */
608 DPRINTF(bfs
->debug
, "i-node full.\n");
612 if (start
* DEV_BSIZE
>= bfs
->data_end
) {
613 DPRINTF(bfs
->debug
, "data block full.\n");
614 /* compaction here ? */
619 if (free_inode_number
)
620 *free_inode_number
= j
;
628 bfs_inode_set_attr(const struct bfs
*bfs
, struct bfs_inode
*inode
,
629 const struct bfs_fileattr
*from
)
631 struct bfs_fileattr
*to
= &inode
->attr
;
634 if (from
->uid
!= (uid_t
)-1)
636 if (from
->gid
!= (uid_t
)-1)
638 if (from
->mode
!= (mode_t
)-1)
639 to
->mode
= from
->mode
;
640 if (from
->atime
!= -1)
641 to
->atime
= from
->atime
;
642 if (from
->ctime
!= -1)
643 to
->ctime
= from
->ctime
;
644 if (from
->mtime
!= -1)
645 to
->mtime
= from
->mtime
;
647 bfs_writeback_inode(bfs
, inode
);
651 bfs_superblock_valid(const struct bfs_super_block
*super
)
654 return super
->header
.magic
== BFS_MAGIC
;
658 bfs_dump(const struct bfs
*bfs
)
660 const struct bfs_super_block_header
*h
;
661 const struct bfs_compaction
*compaction
;
662 const struct bfs_inode
*inode
;
663 struct bfs_dirent
*file
;
667 if (!bfs_superblock_valid(bfs
->super_block
)) {
668 DPRINTF(bfs
->debug
, "invalid bfs super block.\n");
671 h
= &bfs
->super_block
->header
;
672 compaction
= &bfs
->super_block
->compaction
;
674 DPRINTF(bfs
->debug
, "super block %zdbyte, inode %zdbyte, dirent %zdbyte\n",
675 sizeof *bfs
->super_block
, sizeof *inode
, sizeof *file
);
677 DPRINTF(bfs
->debug
, "magic=%x\n", h
->magic
);
678 DPRINTF(bfs
->debug
, "data_start_byte=0x%x\n", h
->data_start_byte
);
679 DPRINTF(bfs
->debug
, "data_end_byte=0x%x\n", h
->data_end_byte
);
680 DPRINTF(bfs
->debug
, "from=%#x\n", compaction
->from
);
681 DPRINTF(bfs
->debug
, "to=%#x\n", compaction
->to
);
682 DPRINTF(bfs
->debug
, "from_backup=%#x\n", compaction
->from_backup
);
683 DPRINTF(bfs
->debug
, "to_backup=%#x\n", compaction
->to_backup
);
684 DPRINTF(bfs
->debug
, "fsname=%s\n", bfs
->super_block
->fsname
);
685 DPRINTF(bfs
->debug
, "volume=%s\n", bfs
->super_block
->volume
);
688 DPRINTF(bfs
->debug
, "[inode index list]\n");
689 for (inode
= bfs
->inode
, i
= j
= 0; i
< bfs
->max_inode
; inode
++, i
++) {
690 if (inode
->number
!= 0) {
691 const struct bfs_fileattr
*attr
= &inode
->attr
;
692 DPRINTF(bfs
->debug
, "%3d %8d %8d %8d (%d) ",
694 inode
->eof_offset_byte
-
695 (inode
->start_sector
* DEV_BSIZE
) + 1,/* file size*/
697 inode
->end_sector
, i
);
699 DPRINTF(bfs
->debug
, "%d %d %d %d %d %08x %08x %08x\n",
700 attr
->type
, attr
->mode
, attr
->uid
, attr
->gid
,
701 attr
->nlink
, attr
->atime
, attr
->mtime
, attr
->ctime
);
705 if (j
!= bfs
->n_inode
) {
706 DPRINTF(bfs
->debug
, "inconsistent cached data. (i-node)\n");
709 DPRINTF(bfs
->debug
, "total %d i-node.\n", j
);
712 DPRINTF(bfs
->debug
, "[dirent index list]\n");
713 DPRINTF(bfs
->debug
, "%d file entries.\n", bfs
->max_dirent
);
715 for (i
= j
= 0; i
< bfs
->max_dirent
; i
++, file
++) {
716 if (file
->inode
!= 0) {
717 if (bfs_file_lookup(bfs
, file
->name
, &s
, &e
, &bytes
))
718 DPRINTF(bfs
->debug
, "%3d %14s %8d %8d %8zd\n",
719 file
->inode
, file
->name
, s
, e
, bytes
);
723 if (j
!= bfs
->n_dirent
) {
724 DPRINTF(bfs
->debug
, "inconsistent cached data. (dirent)\n");
727 DPRINTF(bfs
->debug
, "%d files.\n", j
);