diff --git a/lib/libufs/cgread.3 b/lib/libufs/cgread.3 index 70d4c78202d9..cbc633708506 100644 --- a/lib/libufs/cgread.3 +++ b/lib/libufs/cgread.3 @@ -13,7 +13,7 @@ .\" .\" $FreeBSD$ .\" -.Dd January 19, 2018 +.Dd September 2, 2020 .Dt CGREAD 3 .Os .Sh NAME @@ -29,9 +29,9 @@ .In ufs/ffs/fs.h .In libufs.h .Ft int -.Fn cgget "struct uufsd *disk" "int cg" "struct cg *cgp" +.Fn cgget "int devfd" "struct fs *fs" "int cg" "struct cg *cgp" .Ft int -.Fn cgput "struct uufsd *disk" "struct cg *cgp" +.Fn cgput "int devfd" "struct fs *fs" "struct cg *cgp" .Ft int .Fn cgread "struct uufsd *disk" .Ft int @@ -64,7 +64,11 @@ function reads the cylinder group specified by .Fa cg into the buffer pointed to by .Fa cgp -from the disk referenced by the user-land UFS-disk structure. +from the filesystem described by the +.Fa fs +superblock using the +.Fa devfd +file descriptor that references the filesystem disk. The .Fn cgget function is the only cylinder group read function that is safe to use @@ -74,7 +78,11 @@ The .Fn cgput function writes the cylinder group specified by .Va cgp -to the disk referenced by the user-land UFS-disk structure. +to the filesystem described by the +.Fa fs +superblock using the +.Fa devfd +file descriptor that references the filesystem disk. The .Fn cgput function is the only cylinder group write function that is safe to use @@ -172,3 +180,4 @@ in .Fx 5.1 . .Sh AUTHORS .An Juli Mallett Aq Mt jmallett@FreeBSD.org +.An Marshall Kirk McKusick Aq Mt mckusick@FreeBSD.org diff --git a/lib/libufs/cgroup.c b/lib/libufs/cgroup.c index 1f42155ba4e7..1c3e271c4295 100644 --- a/lib/libufs/cgroup.c +++ b/lib/libufs/cgroup.c @@ -188,25 +188,54 @@ cgread(struct uufsd *disk) return (cgread1(disk, disk->d_ccg++)); } +/* Short read/write error messages from cgget()/cgput() */ +static const char *failmsg; + int cgread1(struct uufsd *disk, int c) { - if ((cgget(disk, c, &disk->d_cg)) == 0) + if (cgget(disk->d_fd, &disk->d_fs, c, &disk->d_cg) == 0) { + disk->d_lcg = c; return (1); + } + ERROR(disk, NULL); + if (failmsg != NULL) { + ERROR(disk, failmsg); + return (-1); + } + switch (errno) { + case EINTEGRITY: + ERROR(disk, "cylinder group checks failed"); + break; + case EIO: + ERROR(disk, "read error from block device"); + break; + default: + ERROR(disk, strerror(errno)); + break; + } return (-1); } int -cgget(struct uufsd *disk, int cg, struct cg *cgp) +cgget(int devfd, struct fs *fs, int cg, struct cg *cgp) { - struct fs *fs; uint32_t cghash, calchash; + size_t cnt; - fs = &disk->d_fs; - if (bread(disk, fsbtodb(fs, cgtod(fs, cg)), (void *)cgp, - fs->fs_cgsize) == -1) { - ERROR(disk, "unable to read cylinder group"); + failmsg = NULL; + if ((cnt = pread(devfd, cgp, fs->fs_cgsize, + fsbtodb(fs, cgtod(fs, cg)) * (fs->fs_fsize / fsbtodb(fs,1)))) < 0) + return (-1); + if (cnt == 0) { + failmsg = "end of file from block device"; + errno = EIO; + return (-1); + } + if (cnt != fs->fs_cgsize) { + failmsg = "short read from block device"; + errno = EIO; return (-1); } calchash = cgp->cg_ckhash; @@ -218,11 +247,9 @@ cgget(struct uufsd *disk, int cg, struct cg *cgp) } if (cgp->cg_ckhash != calchash || !cg_chkmagic(cgp) || cgp->cg_cgx != cg) { - ERROR(disk, "cylinder group checks failed"); - errno = EIO; + errno = EINTEGRITY; return (-1); } - disk->d_lcg = cg; return (0); } @@ -230,7 +257,7 @@ int cgwrite(struct uufsd *disk) { - return (cgput(disk, &disk->d_cg)); + return (cgwrite1(disk, disk->d_cg.cg_cgx)); } int @@ -238,8 +265,24 @@ cgwrite1(struct uufsd *disk, int cg) { static char errmsg[BUFSIZ]; - if (cg == disk->d_cg.cg_cgx) - return (cgput(disk, &disk->d_cg)); + if (cg == disk->d_cg.cg_cgx) { + if (cgput(disk->d_fd, &disk->d_fs, &disk->d_cg) == 0) + return (0); + ERROR(disk, NULL); + if (failmsg != NULL) { + ERROR(disk, failmsg); + return (-1); + } + switch (errno) { + case EIO: + ERROR(disk, "unable to write cylinder group"); + break; + default: + ERROR(disk, strerror(errno)); + break; + } + return (-1); + } snprintf(errmsg, BUFSIZ, "Cylinder group %d in buffer does not match " "the cylinder group %d that cgwrite1 requested", disk->d_cg.cg_cgx, cg); @@ -249,19 +292,22 @@ cgwrite1(struct uufsd *disk, int cg) } int -cgput(struct uufsd *disk, struct cg *cgp) +cgput(int devfd, struct fs *fs, struct cg *cgp) { - struct fs *fs; + size_t cnt; - fs = &disk->d_fs; if ((fs->fs_metackhash & CK_CYLGRP) != 0) { cgp->cg_ckhash = 0; cgp->cg_ckhash = calculate_crc32c(~0L, (void *)cgp, fs->fs_cgsize); } - if (bwrite(disk, fsbtodb(fs, cgtod(fs, cgp->cg_cgx)), cgp, - fs->fs_cgsize) == -1) { - ERROR(disk, "unable to write cylinder group"); + failmsg = NULL; + if ((cnt = pwrite(devfd, cgp, fs->fs_cgsize, + fsbtodb(fs, cgtod(fs, cgp->cg_cgx)) * + (fs->fs_fsize / fsbtodb(fs,1)))) < 0) + return (-1); + if (cnt != fs->fs_cgsize) { + failmsg = "short write to block device"; return (-1); } return (0); diff --git a/lib/libufs/getinode.3 b/lib/libufs/getinode.3 index 6aa5388cbd6d..fde249e86102 100644 --- a/lib/libufs/getinode.3 +++ b/lib/libufs/getinode.3 @@ -9,7 +9,7 @@ .\" .\" $FreeBSD$ .\" -.Dd November 10, 2018 +.Dd September 2, 2020 .Dt GETINODE 3 .Os .Sh NAME @@ -128,4 +128,4 @@ These functions first appeared as part of in .Fx 13.0 . .Sh AUTHORS -.An Marshall Kirk McKusick Aq Mt mckusick@freebsd.org +.An Marshall Kirk McKusick Aq Mt mckusick@FreeBSD.org diff --git a/lib/libufs/libufs.3 b/lib/libufs/libufs.3 index f4f44a6d8de6..578b63d87345 100644 --- a/lib/libufs/libufs.3 +++ b/lib/libufs/libufs.3 @@ -7,7 +7,7 @@ .\" .\" $FreeBSD$ .\" -.Dd November 26, 2018 +.Dd September 2, 2020 .Dt LIBUFS 3 .Os .Sh NAME @@ -80,6 +80,7 @@ library first appeared in .Fx 5.0 . .Sh AUTHORS .An Juli Mallett Aq Mt jmallett@FreeBSD.org +.An Marshall Kirk McKusick Aq Mt mckusick@FreeBSD.org .Pp .An -nosplit Additional design, feedback, and ideas were provided by diff --git a/lib/libufs/libufs.h b/lib/libufs/libufs.h index ad990bbc0930..8160fdcd68a9 100644 --- a/lib/libufs/libufs.h +++ b/lib/libufs/libufs.h @@ -136,8 +136,8 @@ int berase(struct uufsd *, ufs2_daddr_t, ufs2_daddr_t); ufs2_daddr_t cgballoc(struct uufsd *); int cgbfree(struct uufsd *, ufs2_daddr_t, long); ino_t cgialloc(struct uufsd *); -int cgget(struct uufsd *, int, struct cg *); -int cgput(struct uufsd *, struct cg *); +int cgget(int, struct fs *, int, struct cg *); +int cgput(int, struct fs *, struct cg *); int cgread(struct uufsd *); int cgread1(struct uufsd *, int); int cgwrite(struct uufsd *); diff --git a/lib/libufs/sblock.c b/lib/libufs/sblock.c index 54e6234633e3..1d687d6d41aa 100644 --- a/lib/libufs/sblock.c +++ b/lib/libufs/sblock.c @@ -186,7 +186,7 @@ sbput(int devfd, struct fs *fs, int numaltwrite) use_pwrite)) != 0) { fs->fs_sblockactualloc = savedactualloc; fs->fs_csp = savedcsp; - return (-1); + return (error); } } fs->fs_sblockactualloc = savedactualloc; diff --git a/lib/libufs/sbread.3 b/lib/libufs/sbread.3 index 13cadd39d9b2..e97469f86873 100644 --- a/lib/libufs/sbread.3 +++ b/lib/libufs/sbread.3 @@ -11,7 +11,7 @@ .\" .\" $FreeBSD$ .\" -.Dd January 19, 2018 +.Dd September 2, 2020 .Dt SBREAD 3 .Os .Sh NAME @@ -145,3 +145,4 @@ in .Fx 5.0 . .Sh AUTHORS .An Juli Mallett Aq Mt jmallett@FreeBSD.org +.An Marshall Kirk McKusick Aq Mt mckusick@FreeBSD.org diff --git a/sbin/fsck_ffs/fsutil.c b/sbin/fsck_ffs/fsutil.c index 98db9e2d50f5..94ea2cf792bf 100644 --- a/sbin/fsck_ffs/fsutil.c +++ b/sbin/fsck_ffs/fsutil.c @@ -217,6 +217,9 @@ bufinit(void) /* * Manage cylinder group buffers. + * + * Use getblk() here rather than cgget() because the cylinder group + * may be corrupted but we want it anyway so we can fix it. */ static struct bufarea *cgbufs; /* header for cylinder group cache */ static int flushtries; /* number of tries to reclaim memory */ @@ -370,7 +373,7 @@ flush(int fd, struct bufarea *bp) fsmodified = 1; break; case BT_CYLGRP: - if (cgput(&disk, bp->b_un.b_cg) == 0) + if (cgput(fswritefd, &sblock, bp->b_un.b_cg) == 0) fsmodified = 1; break; default: diff --git a/sbin/fsck_ffs/gjournal.c b/sbin/fsck_ffs/gjournal.c index 88d5c0e6c668..6e3dbd2da41e 100644 --- a/sbin/fsck_ffs/gjournal.c +++ b/sbin/fsck_ffs/gjournal.c @@ -133,7 +133,7 @@ getcg(int cg) if (cgc == NULL) err(1, "malloc(%zu)", sizeof(*cgc)); } - if (cgget(diskp, cg, &cgc->cgc_cg) == -1) + if (cgget(fsreadfd, fs, cg, &cgc->cgc_cg) == -1) err(1, "cgget(%d)", cg); cgc->cgc_busy = 0; cgc->cgc_dirty = 0; @@ -189,7 +189,7 @@ putcgs(void) LIST_REMOVE(cgc, cgc_next); ncgs--; if (cgc->cgc_dirty) { - if (cgput(diskp, &cgc->cgc_cg) == -1) + if (cgput(fswritefd, fs, &cgc->cgc_cg) == -1) err(1, "cgput(%d)", cgc->cgc_cg.cg_cgx); //printf("%s: Wrote cg=%d\n", __func__, // cgc->cgc_cg.cg_cgx); diff --git a/sbin/fsck_ffs/suj.c b/sbin/fsck_ffs/suj.c index e1e3da19e195..8ecd1f686ea7 100644 --- a/sbin/fsck_ffs/suj.c +++ b/sbin/fsck_ffs/suj.c @@ -1912,7 +1912,7 @@ cg_write(struct suj_cg *sc) * before writing the block. */ fs->fs_cs(fs, sc->sc_cgx) = cgp->cg_cs; - if (cgput(&disk, cgp) == -1) + if (cgput(fswritefd, fs, cgp) == -1) err_suj("Unable to write cylinder group %d\n", sc->sc_cgx); }