aboutsummaryrefslogtreecommitdiff
path: root/lib/libufs
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libufs')
-rw-r--r--lib/libufs/Makefile2
-rw-r--r--lib/libufs/libufs.h27
-rw-r--r--lib/libufs/sblock.c211
-rw-r--r--lib/libufs/sbread.388
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 .