diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/libufs/Makefile | 2 | ||||
-rw-r--r-- | lib/libufs/libufs.h | 27 | ||||
-rw-r--r-- | lib/libufs/sblock.c | 211 | ||||
-rw-r--r-- | lib/libufs/sbread.3 | 88 |
4 files changed, 216 insertions, 112 deletions
diff --git a/lib/libufs/Makefile b/lib/libufs/Makefile index d24526e829c1..16487bebc957 100644 --- a/lib/libufs/Makefile +++ b/lib/libufs/Makefile @@ -17,6 +17,8 @@ MLINKS+= cgread.3 cgwrite.3 MLINKS+= cgread.3 cgwrite1.3 MLINKS+= cgread.3 cgput.3 MLINKS+= sbread.3 sbwrite.3 +MLINKS+= sbread.3 sbget.3 +MLINKS+= sbread.3 sbput.3 MLINKS+= ufs_disk_close.3 ufs_disk_fillout.3 MLINKS+= ufs_disk_close.3 ufs_disk_fillout_blank.3 MLINKS+= ufs_disk_close.3 ufs_disk_write.3 diff --git a/lib/libufs/libufs.h b/lib/libufs/libufs.h index 400704596148..4598a9999ce2 100644 --- a/lib/libufs/libufs.h +++ b/lib/libufs/libufs.h @@ -99,6 +99,20 @@ __BEGIN_DECLS */ /* + * ffs_subr.c + */ +void ffs_clrblock(struct fs *, u_char *, ufs1_daddr_t); +void ffs_clusteracct(struct fs *, struct cg *, ufs1_daddr_t, int); +void ffs_fragacct(struct fs *, int, int32_t [], int); +int ffs_isblock(struct fs *, u_char *, ufs1_daddr_t); +int ffs_isfreeblock(struct fs *, u_char *, ufs1_daddr_t); +void ffs_setblock(struct fs *, u_char *, ufs1_daddr_t); +int ffs_sbget(void *, struct fs **, off_t, char *, + int (*)(void *, off_t, void **, int)); +int ffs_sbput(void *, struct fs *, off_t, + int (*)(void *, off_t, void *, int)); + +/* * block.c */ ssize_t bread(struct uufsd *, ufs2_daddr_t, void *, size_t); @@ -129,6 +143,9 @@ int putino(struct uufsd *); */ int sbread(struct uufsd *); int sbwrite(struct uufsd *, int); +/* low level superblock read/write functions */ +int sbget(int, struct fs **, off_t); +int sbput(int, struct fs *, int); /* * type.c @@ -139,16 +156,6 @@ int ufs_disk_fillout_blank(struct uufsd *, const char *); int ufs_disk_write(struct uufsd *); /* - * ffs_subr.c - */ -void ffs_clrblock(struct fs *, u_char *, ufs1_daddr_t); -void ffs_clusteracct(struct fs *, struct cg *, ufs1_daddr_t, int); -void ffs_fragacct(struct fs *, int, int32_t [], int); -int ffs_isblock(struct fs *, u_char *, ufs1_daddr_t); -int ffs_isfreeblock(struct fs *, u_char *, ufs1_daddr_t); -void ffs_setblock(struct fs *, u_char *, ufs1_daddr_t); - -/* * crc32c.c */ uint32_t calculate_crc32c(uint32_t, const void *, size_t); 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); } diff --git a/lib/libufs/sbread.3 b/lib/libufs/sbread.3 index 8b5e8c0d4d6b..42342b2f3271 100644 --- a/lib/libufs/sbread.3 +++ b/lib/libufs/sbread.3 @@ -2,6 +2,8 @@ .\" Date: June 04, 2003 .\" Description: .\" Manual page for libufs functions: +.\" sbget(3) +.\" sbput(3) .\" sbread(3) .\" sbwrite(3) .\" @@ -9,11 +11,11 @@ .\" .\" $FreeBSD$ .\" -.Dd June 4, 2003 +.Dd January 19, 2018 .Dt SBREAD 3 .Os .Sh NAME -.Nm sbread , sbwrite +.Nm sbget , sbput , sbread , sbwrite .Nd read and write superblocks of a UFS file system .Sh LIBRARY .Lb libufs @@ -25,35 +27,95 @@ .In ufs/ffs/fs.h .In libufs.h .Ft int +.Fn sbget "int devfd" "struct fs **fsp" "off_t sblockloc" +.Ft int +.Fn sbput "int devfd" "struct fs *fs" "int numaltwrite" +.Ft int .Fn sbread "struct uufsd *disk" .Ft int .Fn sbwrite "struct uufsd *disk" "int all" .Sh DESCRIPTION The +.Fn sbget +and .Fn sbread +functions provide superblock reads for +.Xr libufs 3 +consumers. +The +.Fn sbput and .Fn sbwrite -functions provide superblock reads and writes for +functions provide superblock writes for .Xr libufs 3 consumers. +.Pp +The +.Fn sbget +function first allocates a buffer to hold the superblock. +Using the +.Va devfd +file descriptor that references the filesystem disk, +.Fn sbget +reads the superblock located at the byte offset specified by +.Va sblockloc +into the allocated buffer. +If successful, it returns a pointer to the buffer containing the superblock in +.Va fsp . +The +.Fn sbget +function is safe to use in threaded applications. +.Pp +The +.Fn sbput +function writes the superblock specified by +.Va fs +to the location from which it was read on the disk referenced by the +.Va devfd +file descriptor. +Additionally, the +.Fn sbput +function will update the first +.Va numaltwrite +alternate superblock locations. +To update all the alternate superblocks, +specify a +.Va numaltwrite +value of +.Va fs->fs_ncg . +The +.Fn sbput +function is safe to use in threaded applications. +Note that the +.Fn sbput +function needs to be called only if the superblock has been +modified and the on-disk copy needs to be updated. +.Pp The .Fn sbread -and +function reads the standard filesystem superblock into the +.Va d_sb , +structure embedded in the given user-land UFS disk structure. +.Pp +The .Fn sbwrite -functions operate on the superblock field, +function writes the superblock from the .Va d_sb , -associated with a given userland UFS disk structure. +structure embedded in the given user-land UFS disk structure +to the location from which it was read. Additionally, the .Fn sbwrite -function will write to all superblock locations if the +function will write to all the alternate superblock locations if the .Fa all value is non-zero. .Sh RETURN VALUES -.Rv -std sbread sbwrite +.Rv -std sbget sbput sbread sbwrite .Sh ERRORS -The function +The +.Fn sbget +and .Fn sbread -may fail and set +functions may fail and set .Va errno for any of the errors specified for the library function .Xr bread 3 . @@ -62,9 +124,11 @@ Additionally, it may follow the error methodologies in situations where no usable superblock could be found. .Pp -The function +The +.Fn sbput +and .Fn sbwrite -may fail and set +functions may fail and set .Va errno for any of the errors specified for the library function .Xr bwrite 3 . |