diff options
Diffstat (limited to 'lib/libufs/sblock.c')
-rw-r--r-- | lib/libufs/sblock.c | 211 |
1 files changed, 121 insertions, 90 deletions
diff --git a/lib/libufs/sblock.c b/lib/libufs/sblock.c index 06cf97d51581..5242a6db88db 100644 --- a/lib/libufs/sblock.c +++ b/lib/libufs/sblock.c @@ -47,79 +47,48 @@ __FBSDID("$FreeBSD$"); #include <libufs.h> -static int superblocks[] = SBLOCKSEARCH; - int sbread(struct uufsd *disk) { - uint8_t block[MAXBSIZE]; struct fs *fs; - int sb, superblock; - int i, size, blks; - uint8_t *space; ERROR(disk, NULL); - fs = &disk->d_fs; - superblock = superblocks[0]; - - for (sb = 0; (superblock = superblocks[sb]) != -1; sb++) { - if (bread(disk, superblock, disk->d_sb, SBLOCKSIZE) == -1) { + if ((errno = sbget(disk->d_fd, &fs, -1)) != 0) { + switch (errno) { + case EIO: ERROR(disk, "non-existent or truncated superblock"); - return (-1); - } - if (fs->fs_magic == FS_UFS1_MAGIC) - disk->d_ufs = 1; - if (fs->fs_magic == FS_UFS2_MAGIC && - fs->fs_sblockloc == superblock) - disk->d_ufs = 2; - if (fs->fs_bsize <= MAXBSIZE && - (size_t)fs->fs_bsize >= sizeof(*fs)) { - if (disk->d_ufs) - break; + break; + case ENOENT: + ERROR(disk, "no usable known superblock found"); + break; + case ENOSPC: + ERROR(disk, "failed to allocate space for superblock " + "information"); + break; + case EINVAL: + ERROR(disk, "The previous newfs operation on this " + "volume did not complete.\nYou must complete " + "newfs before using this volume."); + break; + default: + ERROR(disk, "unknown superblock read error"); + errno = EIO; + break; } disk->d_ufs = 0; - } - if (superblock == -1 || disk->d_ufs == 0) { - /* - * Other error cases will result in errno being set, here we - * must set it to indicate no superblock could be found with - * which to associate this disk/filesystem. - */ - ERROR(disk, "no usable known superblock found"); - errno = ENOENT; return (-1); } + memcpy(&disk->d_fs, fs, fs->fs_sbsize); + free(fs); + fs = &disk->d_fs; + if (fs->fs_magic == FS_UFS1_MAGIC) + disk->d_ufs = 1; + if (fs->fs_magic == FS_UFS2_MAGIC) + disk->d_ufs = 2; disk->d_bsize = fs->fs_fsize / fsbtodb(fs, 1); - disk->d_sblock = superblock / disk->d_bsize; - /* - * Read in the superblock summary information. - */ - size = fs->fs_cssize; - blks = howmany(size, fs->fs_fsize); - size += fs->fs_ncg * sizeof(int32_t); - space = malloc(size); - if (space == NULL) { - ERROR(disk, "failed to allocate space for summary information"); - return (-1); - } - fs->fs_csp = (struct csum *)space; - for (i = 0; i < blks; i += fs->fs_frag) { - size = fs->fs_bsize; - if (i + fs->fs_frag > blks) - size = (blks - i) * fs->fs_fsize; - if (bread(disk, fsbtodb(fs, fs->fs_csaddr + i), block, size) - == -1) { - ERROR(disk, "Failed to read sb summary information"); - free(fs->fs_csp); - return (-1); - } - bcopy(block, space, size); - space += size; - } - fs->fs_maxcluster = (uint32_t *)space; + disk->d_sblock = fs->fs_sblockloc / disk->d_bsize; disk->d_sbcsum = fs->fs_csp; - return (0); } @@ -127,45 +96,107 @@ int sbwrite(struct uufsd *disk, int all) { struct fs *fs; - int blks, size; - uint8_t *space; - unsigned i; ERROR(disk, NULL); fs = &disk->d_fs; - - if (!disk->d_sblock) { - disk->d_sblock = disk->d_fs.fs_sblockloc / disk->d_bsize; - } - - if (bwrite(disk, disk->d_sblock, fs, SBLOCKSIZE) == -1) { - ERROR(disk, "failed to write superblock"); + if ((errno = sbput(disk->d_fd, fs, all ? fs->fs_ncg : 0)) != 0) { + switch (errno) { + case EIO: + ERROR(disk, "failed to write superblock"); + break; + default: + ERROR(disk, "unknown superblock write error"); + errno = EIO; + break; + } return (-1); } - /* - * Write superblock summary information. - */ - blks = howmany(fs->fs_cssize, fs->fs_fsize); - space = (uint8_t *)disk->d_sbcsum; - for (i = 0; i < blks; i += fs->fs_frag) { - size = fs->fs_bsize; - if (i + fs->fs_frag > blks) - size = (blks - i) * fs->fs_fsize; - if (bwrite(disk, fsbtodb(fs, fs->fs_csaddr + i), space, size) - == -1) { - ERROR(disk, "Failed to write sb summary information"); + return (0); +} + +/* + * These are the low-level functions that actually read and write + * the superblock and its associated data. The actual work is done by + * the functions ffs_sbget and ffs_sbput in /sys/ufs/ffs/ffs_subr.c. + */ +static int use_pread(void *devfd, off_t loc, void **bufp, int size); +static int use_pwrite(void *devfd, off_t loc, void *buf, int size); + +/* + * Read a superblock from the devfd device allocating memory returned + * in fsp. Also read the superblock summary information. + */ +int +sbget(int devfd, struct fs **fsp, off_t sblockloc) +{ + + return (ffs_sbget(&devfd, fsp, sblockloc, "user", use_pread)); +} + +/* + * A read function for use by user-level programs using libufs. + */ +static int +use_pread(void *devfd, off_t loc, void **bufp, int size) +{ + int fd; + + fd = *(int *)devfd; + if ((*bufp = malloc(size)) == NULL) + return (ENOSPC); + if (pread(fd, *bufp, size, loc) != size) + return (EIO); + return (0); +} + +/* + * Write a superblock to the devfd device from the memory pointed to by fs. + * Also write out the superblock summary information but do not free the + * summary information memory. + * + * Additionally write out numaltwrite of the alternate superblocks. Use + * fs->fs_ncg to write out all of the alternate superblocks. + */ +int +sbput(int devfd, struct fs *fs, int numaltwrite) +{ + struct csum *savedcsp; + off_t savedactualloc; + int i, error; + + if ((error = ffs_sbput(&devfd, fs, fs->fs_sblockactualloc, + use_pwrite)) != 0) + return (error); + if (numaltwrite == 0) + return (0); + savedactualloc = fs->fs_sblockactualloc; + savedcsp = fs->fs_csp; + fs->fs_csp = NULL; + for (i = 0; i < numaltwrite; i++) { + fs->fs_sblockactualloc = dbtob(fsbtodb(fs, cgsblock(fs, i))); + if ((error = ffs_sbput(&devfd, fs, fs->fs_sblockactualloc, + use_pwrite)) != 0) { + fs->fs_sblockactualloc = savedactualloc; + fs->fs_csp = savedcsp; return (-1); } - space += size; - } - if (all) { - for (i = 0; i < fs->fs_ncg; i++) - if (bwrite(disk, fsbtodb(fs, cgsblock(fs, i)), - fs, SBLOCKSIZE) == -1) { - ERROR(disk, "failed to update a superblock"); - return (-1); - } } + fs->fs_sblockactualloc = savedactualloc; + fs->fs_csp = savedcsp; + return (0); +} + +/* + * A write function for use by user-level programs using sbput in libufs. + */ +static int +use_pwrite(void *devfd, off_t loc, void *buf, int size) +{ + int fd; + + fd = *(int *)devfd; + if (pwrite(fd, buf, size, loc) != size) + return (EIO); return (0); } |