diff options
Diffstat (limited to 'sys')
46 files changed, 2797 insertions, 1243 deletions
diff --git a/sys/amd64/Makefile b/sys/amd64/Makefile index 14ba0b3..b7d021a 100644 --- a/sys/amd64/Makefile +++ b/sys/amd64/Makefile @@ -5,6 +5,7 @@ # SYS is normally set in Make.tags.inc # SYS=/sys +SYS=/nsys TAGDIR= i386 diff --git a/sys/boot/common/ufsread.c b/sys/boot/common/ufsread.c index 053dbe0..b0a1547 100644 --- a/sys/boot/common/ufsread.c +++ b/sys/boot/common/ufsread.c @@ -1,4 +1,13 @@ /* + * Copyright (c) 2002 Networks Associates Technology, Inc. + * All rights reserved. + * + * This software was developed for the FreeBSD Project by Marshall + * Kirk McKusick and Network Associates Laboratories, the Security + * Research Division of Network Associates, Inc. under DARPA/SPAWAR + * contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS + * research program + * * Copyright (c) 1998 Robert Nordier * All rights reserved. * @@ -17,31 +26,33 @@ * $FreeBSD$ */ -#include <ufs/ffs/fs.h> #include <ufs/ufs/dinode.h> +#include <ufs/ffs/fs.h> /* * We use 4k `virtual' blocks for filesystem data, whatever the actual * filesystem block size. FFS blocks are always a multiple of 4k. */ #define VBLKSIZE 4096 +#define VBLKSHIFT 12 #define VBLKMASK (VBLKSIZE - 1) #define DBPERVBLK (VBLKSIZE / DEV_BSIZE) -#define IPERVBLK (VBLKSIZE / sizeof(struct dinode)) -#define INDIRPERVBLK (VBLKSIZE / sizeof(ufs_daddr_t)) -#define INO_TO_VBA(fs, x) (fsbtodb(fs, ino_to_fsba(fs, x)) + \ - (ino_to_fsbo(fs, x) / IPERVBLK) * DBPERVBLK) -#define INO_TO_VBO(fs, x) (ino_to_fsbo(fs, x) % IPERVBLK) +#define INDIRPERVBLK(fs) (NINDIR(fs) / ((fs)->fs_bsize / VBLKSIZE)) +#define IPERVBLK(fs) (INOPB(fs) / ((fs)->fs_bsize / VBLKSIZE)) +#define INO_TO_VBA(fs, ipervblk, x) \ + (fsbtodb(fs, cgimin(fs, ino_to_cg(fs, x))) + \ + (((x) % (fs)->fs_ipg) / (ipervblk) * DBPERVBLK)) +#define INO_TO_VBO(ipervblk, x) ((x) % ipervblk) #define FS_TO_VBA(fs, fsb, off) (fsbtodb(fs, fsb) + \ ((off) / VBLKSIZE) * DBPERVBLK) #define FS_TO_VBO(fs, fsb, off) ((off) & VBLKMASK) /* Buffers that must not span a 64k boundary. */ struct dmadat { - char blkbuf[VBLKSIZE]; /* filesystem blocks */ - ufs_daddr_t indbuf[VBLKSIZE / sizeof(ufs_daddr_t)]; /* indir blocks */ - char sbbuf[SBSIZE]; /* superblock */ - char secbuf[DEV_BSIZE]; /* for MBR/disklabel */ + char blkbuf[VBLKSIZE]; /* filesystem blocks */ + char indbuf[VBLKSIZE]; /* indir blocks */ + char sbbuf[SBLOCKSIZE]; /* superblock */ + char secbuf[DEV_BSIZE]; /* for MBR/disklabel */ }; static struct dmadat *dmadat; @@ -61,16 +72,16 @@ fsfind(const char *name, ino_t * ino) fs_off = 0; while ((n = fsread(*ino, buf, DEV_BSIZE)) > 0) - for (s = buf; s < buf + DEV_BSIZE;) { - d = (void *)s; - if (ls) - printf("%s ", d->d_name); - else if (!strcmp(name, d->d_name)) { - *ino = d->d_fileno; - return d->d_type; + for (s = buf; s < buf + DEV_BSIZE;) { + d = (void *)s; + if (ls) + printf("%s ", d->d_name); + else if (!strcmp(name, d->d_name)) { + *ino = d->d_fileno; + return d->d_type; + } + s += d->d_reclen; } - s += d->d_reclen; - } if (n != -1 && ls) printf("\n"); return 0; @@ -95,8 +106,8 @@ lookup(const char *path) if (!*path) break; for (s = path; *s && *s != '/'; s++); - if ((n = s - path) > MAXNAMLEN) - return 0; + if ((n = s - path) > MAXNAMLEN) + return 0; ls = *path == '?' && n == 1 && !*s; memcpy(name, path, n); name[n] = 0; @@ -111,28 +122,31 @@ lookup(const char *path) return dt == DT_REG ? ino : 0; } +#define UFS1_ONLY +#ifdef UFS1_ONLY + static ssize_t fsread(ino_t inode, void *buf, size_t nbyte) { - static struct dinode din; + static struct ufs1_dinode dp1; static ino_t inomap; - static daddr_t blkmap, indmap; char *blkbuf; - ufs_daddr_t *indbuf; + caddr_t indbuf; struct fs *fs; char *s; - ufs_daddr_t lbn, addr; - daddr_t vbaddr; - size_t n, nb, off, vboff; + size_t n, nb, size, off, vboff; + long lbn; + ufs1_daddr_t addr, vbaddr; + static ufs1_daddr_t blkmap, indmap; blkbuf = dmadat->blkbuf; indbuf = dmadat->indbuf; fs = (struct fs *)dmadat->sbbuf; if (!dsk_meta) { inomap = 0; - if (dskread(fs, SBOFF / DEV_BSIZE, SBSIZE / DEV_BSIZE)) + if (dskread(fs, SBLOCK_UFS1 / DEV_BSIZE, SBLOCKSIZE / DEV_BSIZE)) return -1; - if (fs->fs_magic != FS_MAGIC) { + if (fs->fs_magic != FS_UFS1_MAGIC) { printf("Not ufs\n"); return -1; } @@ -141,35 +155,40 @@ fsread(ino_t inode, void *buf, size_t nbyte) if (!inode) return 0; if (inomap != inode) { - if (dskread(blkbuf, INO_TO_VBA(fs, inode), DBPERVBLK)) + n = IPERVBLK(fs); + if (dskread(blkbuf, INO_TO_VBA(fs, n, inode), DBPERVBLK)) return -1; - din = ((struct dinode *)blkbuf)[INO_TO_VBO(fs, inode)]; + dp1 = ((struct ufs1_dinode *)blkbuf)[INO_TO_VBO(n, inode)]; inomap = inode; fs_off = 0; blkmap = indmap = 0; } s = buf; - if (nbyte > (n = din.di_size - fs_off)) + size = dp1.di_size; + n = size - fs_off; + if (nbyte > n) nbyte = n; nb = nbyte; while (nb) { lbn = lblkno(fs, fs_off); off = blkoff(fs, fs_off); - if (lbn < NDADDR) - addr = din.di_db[lbn]; - else { - vbaddr = FS_TO_VBA(fs, din.di_ib[0], sizeof(indbuf[0]) * - ((lbn - NDADDR) % NINDIR(fs))); + if (lbn < NDADDR) { + addr = dp1.di_db[lbn]; + } else { + n = INDIRPERVBLK(fs); + addr = dp1.di_ib[0]; + vbaddr = fsbtodb(fs, addr) + + (lbn - NDADDR) / n * DBPERVBLK; if (indmap != vbaddr) { if (dskread(indbuf, vbaddr, DBPERVBLK)) return -1; indmap = vbaddr; } - addr = indbuf[(lbn - NDADDR) % INDIRPERVBLK]; + addr = ((ufs1_daddr_t *)indbuf)[(lbn - NDADDR) % n]; } - vbaddr = FS_TO_VBA(fs, addr, off); - vboff = FS_TO_VBO(fs, addr, off); - n = dblksize(fs, &din, lbn) - (off & ~VBLKMASK); + vbaddr = fsbtodb(fs, addr) + (off >> VBLKSHIFT) * DBPERVBLK; + vboff = off & VBLKMASK; + n = sblksize(fs, size, lbn) - (off & ~VBLKMASK); if (n > VBLKSIZE) n = VBLKSIZE; if (blkmap != vbaddr) { @@ -187,3 +206,117 @@ fsread(ino_t inode, void *buf, size_t nbyte) } return nbyte; } + +#else /* UFS1_AND_UFS2 */ + +/* + * Possible superblock locations ordered from most to least likely. + */ +static int sblock_try[] = SBLOCKSEARCH; + +#define DIP(field) fs->fs_magic == FS_UFS1_MAGIC ? dp1.field : dp2.field + +static ssize_t +fsread(ino_t inode, void *buf, size_t nbyte) +{ + static struct ufs1_dinode dp1; + static struct ufs2_dinode dp2; + static ino_t inomap; + char *blkbuf; + caddr_t indbuf; + struct fs *fs; + char *s; + size_t n, nb, size, off, vboff; + ufs_lbn_t lbn; + ufs2_daddr_t addr, vbaddr; + static ufs2_daddr_t blkmap, indmap; + + blkbuf = dmadat->blkbuf; + indbuf = dmadat->indbuf; + fs = (struct fs *)dmadat->sbbuf; + if (!dsk_meta) { + inomap = 0; + for (n = 0; sblock_try[n] != -1; n++) { + if (dskread(fs, sblock_try[n] / DEV_BSIZE, + SBLOCKSIZE / DEV_BSIZE)) + return -1; + if ((fs->fs_magic == FS_UFS1_MAGIC || + (fs->fs_magic == FS_UFS2_MAGIC && + fs->fs_sblockloc == numfrags(fs, sblock_try[n]))) && + fs->fs_bsize <= MAXBSIZE && + fs->fs_bsize >= sizeof(struct fs)) + break; + } + if (sblock_try[n] == -1) { + printf("Not ufs\n"); + return -1; + } + dsk_meta++; + } + if (!inode) + return 0; + if (inomap != inode) { + n = IPERVBLK(fs); + if (dskread(blkbuf, INO_TO_VBA(fs, n, inode), DBPERVBLK)) + return -1; + n = INO_TO_VBO(n, inode); + if (fs->fs_magic == FS_UFS1_MAGIC) + dp1 = ((struct ufs1_dinode *)blkbuf)[n]; + else + dp2 = ((struct ufs2_dinode *)blkbuf)[n]; + inomap = inode; + fs_off = 0; + blkmap = indmap = 0; + } + s = buf; + size = DIP(di_size); + n = size - fs_off; + if (nbyte > n) + nbyte = n; + nb = nbyte; + while (nb) { + lbn = lblkno(fs, fs_off); + off = blkoff(fs, fs_off); + if (lbn < NDADDR) { + addr = DIP(di_db[lbn]); + } else if (lbn < NDADDR + NINDIR(fs)) { + n = INDIRPERVBLK(fs); + addr = DIP(di_ib[0]); + vbaddr = fsbtodb(fs, addr) + + (lbn - NDADDR) / n * DBPERVBLK; + if (indmap != vbaddr) { + if (dskread(indbuf, vbaddr, DBPERVBLK)) + return -1; + indmap = vbaddr; + } + n = (lbn - NDADDR) % n; + if (fs->fs_magic == FS_UFS1_MAGIC) + addr = ((ufs1_daddr_t *)indbuf)[n]; + else + addr = ((ufs2_daddr_t *)indbuf)[n]; + } else { + printf("file too big\n"); + return -1; + } + vbaddr = fsbtodb(fs, addr) + (off >> VBLKSHIFT) * DBPERVBLK; + vboff = off & VBLKMASK; + n = sblksize(fs, size, lbn) - (off & ~VBLKMASK); + if (n > VBLKSIZE) + n = VBLKSIZE; + if (blkmap != vbaddr) { + if (dskread(blkbuf, vbaddr, n >> DEV_BSHIFT)) + return -1; + blkmap = vbaddr; + } + n -= vboff; + if (n > nb) + n = nb; + memcpy(s, blkbuf + vboff, n); + s += n; + fs_off += n; + nb -= n; + } + return nbyte; +} + +#endif /* UFS1_AND_UFS2 */ diff --git a/sys/boot/i386/Makefile b/sys/boot/i386/Makefile index 4fd9447..3fbdc45 100644 --- a/sys/boot/i386/Makefile +++ b/sys/boot/i386/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -SUBDIR= mbr boot0 btx boot2 cdboot kgzldr libi386 loader +SUBDIR= libi386 mbr boot0 btx boot2 cdboot kgzldr loader # special boot programs, 'self-extracting boot2+loader' SUBDIR+= pxeldr diff --git a/sys/boot/i386/boot2/Makefile b/sys/boot/i386/boot2/Makefile index 2883b93..75e4fe3 100644 --- a/sys/boot/i386/boot2/Makefile +++ b/sys/boot/i386/boot2/Makefile @@ -75,7 +75,7 @@ boot2.bin: boot2.out boot2.out: boot2.o sio.o ${LD} ${LDFLAGS} -Ttext ${ORG2} -o ${.TARGET} \ - ${BTX}/lib/crt0.o boot2.o sio.o + ${BTX}/lib/crt0.o boot2.o sio.o ../libi386/libi386.a boot2.o: boot2.h diff --git a/sys/boot/i386/boot2/boot2.c b/sys/boot/i386/boot2/boot2.c index fa82999..e506c29 100644 --- a/sys/boot/i386/boot2/boot2.c +++ b/sys/boot/i386/boot2/boot2.c @@ -73,9 +73,10 @@ #define TYPE_AD 0 #define TYPE_WD 1 -#define TYPE_WFD 2 -#define TYPE_FD 3 -#define TYPE_DA 4 +#define TYPE_DA 2 +#define TYPE_MAXHARD TYPE_DA +#define TYPE_WFD 3 +#define TYPE_FD 4 extern uint32_t _end; @@ -97,8 +98,8 @@ static const unsigned char flags[NOPT] = { RBX_VERBOSE }; -static const char *const dev_nm[] = {"ad", "wd", " ", "fd", "da"}; -static const unsigned dev_maj[] = {30, 0, 1, 2, 4}; +static const char *const dev_nm[NDEV] = {"ad", "wd", "da", " ", "fd"}; +static const unsigned char dev_maj[NDEV] = {30, 0, 4, 1, 2}; static struct dsk { unsigned drive; @@ -111,16 +112,14 @@ static struct dsk { } dsk; static char cmd[512]; static char kname[1024]; -static uint32_t opts; +static uint32_t opts = RB_BOOTINFO; static struct bootinfo bootinfo; static uint8_t ioctrl = IO_KEYBOARD; void exit(int); static void load(const char *); static int parse(char *); -static ino_t lookup(const char *); static int xfsread(ino_t, void *, size_t); -static ssize_t fsread(ino_t, void *, size_t); static int dskread(void *, unsigned, unsigned); static int printf(const char *,...); static int putchar(int); @@ -131,16 +130,17 @@ static int xputc(int); static int xgetc(int); static int getc(int); +#if 1 #define memcpy __builtin_memcpy - -static inline void -readfile(const char *fname, void *buf, size_t size) +#else +static void memcpy(char *, const char *, int); +static void +memcpy(char *dst, const char *src, int len) { - ino_t ino; - - if ((ino = lookup(fname))) - fsread(ino, buf, size); + while (len--) + *dst++ = *src++; } +#endif static inline int strcmp(const char *s1, const char *s2) @@ -151,15 +151,14 @@ strcmp(const char *s1, const char *s2) #include "ufsread.c" -static inline int -getchar(void) +static int +xfsread(ino_t inode, void *buf, size_t nbyte) { - int c; - - c = xgetc(0); - if (c == '\r') - c = '\n'; - return c; + if (fsread(inode, buf, nbyte) != nbyte) { + printf("Invalid %s\n", "format"); + return -1; + } + return 0; } static inline void @@ -169,12 +168,13 @@ getstr(char *str, int size) int c; s = str; - do { - switch (c = getchar()) { + for (;;) { + switch (c = xgetc(0)) { case 0: break; - case '\b': case '\177': + c = '\b'; + case '\b': if (s > str) { s--; putchar('\b'); @@ -183,15 +183,16 @@ getstr(char *str, int size) c = 0; break; case '\n': + case '\r': *s = 0; - break; + return; default: if (s - str < size - 1) *s++ = c; } if (c) putchar(c); - } while (c != '\n'); + } } static inline uint32_t @@ -220,6 +221,7 @@ int main(void) { int autoboot, i; + ino_t ino; dmadat = (void *)(roundup2(__base + _end, 0x10000) - __base); v86.ctl = V86_FLAGS; @@ -238,7 +240,10 @@ main(void) /* Process configuration file */ autoboot = 1; - readfile(PATH_CONFIG, cmd, sizeof(cmd)); + + if ((ino = lookup(PATH_CONFIG))) + fsread(ino, cmd, sizeof(cmd)); + if (*cmd) { printf("%s: %s", PATH_CONFIG, cmd); if (parse(cmd)) @@ -328,7 +333,7 @@ load(const char *fname) return; p += hdr.ex.a_data + roundup2(hdr.ex.a_bss, PAGE_SIZE); bootinfo.bi_symtab = VTOP(p); - memcpy(p, &hdr.ex.a_syms, sizeof(hdr.ex.a_syms)); + memcpy(p, (char *)&hdr.ex.a_syms, sizeof(hdr.ex.a_syms)); p += sizeof(hdr.ex.a_syms); if (hdr.ex.a_syms) { if (xfsread(ino, p, hdr.ex.a_syms)) @@ -365,7 +370,7 @@ load(const char *fname) if (xfsread(ino, &es, sizeof(es))) return; for (i = 0; i < 2; i++) { - memcpy(p, &es[i].sh_size, sizeof(es[i].sh_size)); + memcpy(p, (char *)&es[i].sh_size, sizeof(es[i].sh_size)); p += sizeof(es[i].sh_size); fs_off = es[i].sh_offset; if (xfsread(ino, p, es[i].sh_size)) @@ -378,7 +383,7 @@ load(const char *fname) bootinfo.bi_esymtab = VTOP(p); bootinfo.bi_kernelname = VTOP(fname); bootinfo.bi_bios_dev = dsk.drive; - __exec((caddr_t)addr, RB_BOOTINFO | (opts & RBX_MASK), + __exec((caddr_t)addr, opts & RBX_MASK, MAKEBOOTDEV(dev_maj[dsk.type], 0, dsk.slice, dsk.unit, dsk.part), 0, 0, 0, VTOP(&bootinfo)); } @@ -449,9 +454,8 @@ parse(char *arg) arg += 2; if (drv == -1) drv = dsk.unit; - dsk.drive = (dsk.type == TYPE_WD || - dsk.type == TYPE_AD || - dsk.type == TYPE_DA ? DRV_HARD : 0) + drv; + dsk.drive = (dsk.type <= TYPE_MAXHARD + ? DRV_HARD : 0) + drv; dsk_meta = 0; fsread(0, NULL, 0); } @@ -467,16 +471,6 @@ parse(char *arg) } static int -xfsread(ino_t inode, void *buf, size_t nbyte) -{ - if (fsread(inode, buf, nbyte) != nbyte) { - printf("Invalid %s\n", "format"); - return -1; - } - return 0; -} - -static int dskread(void *buf, unsigned lba, unsigned nblk) { struct dos_partition *dp; diff --git a/sys/boot/i386/gptboot/Makefile b/sys/boot/i386/gptboot/Makefile index 2883b93..75e4fe3 100644 --- a/sys/boot/i386/gptboot/Makefile +++ b/sys/boot/i386/gptboot/Makefile @@ -75,7 +75,7 @@ boot2.bin: boot2.out boot2.out: boot2.o sio.o ${LD} ${LDFLAGS} -Ttext ${ORG2} -o ${.TARGET} \ - ${BTX}/lib/crt0.o boot2.o sio.o + ${BTX}/lib/crt0.o boot2.o sio.o ../libi386/libi386.a boot2.o: boot2.h diff --git a/sys/boot/i386/gptboot/gptboot.c b/sys/boot/i386/gptboot/gptboot.c index fa82999..e506c29 100644 --- a/sys/boot/i386/gptboot/gptboot.c +++ b/sys/boot/i386/gptboot/gptboot.c @@ -73,9 +73,10 @@ #define TYPE_AD 0 #define TYPE_WD 1 -#define TYPE_WFD 2 -#define TYPE_FD 3 -#define TYPE_DA 4 +#define TYPE_DA 2 +#define TYPE_MAXHARD TYPE_DA +#define TYPE_WFD 3 +#define TYPE_FD 4 extern uint32_t _end; @@ -97,8 +98,8 @@ static const unsigned char flags[NOPT] = { RBX_VERBOSE }; -static const char *const dev_nm[] = {"ad", "wd", " ", "fd", "da"}; -static const unsigned dev_maj[] = {30, 0, 1, 2, 4}; +static const char *const dev_nm[NDEV] = {"ad", "wd", "da", " ", "fd"}; +static const unsigned char dev_maj[NDEV] = {30, 0, 4, 1, 2}; static struct dsk { unsigned drive; @@ -111,16 +112,14 @@ static struct dsk { } dsk; static char cmd[512]; static char kname[1024]; -static uint32_t opts; +static uint32_t opts = RB_BOOTINFO; static struct bootinfo bootinfo; static uint8_t ioctrl = IO_KEYBOARD; void exit(int); static void load(const char *); static int parse(char *); -static ino_t lookup(const char *); static int xfsread(ino_t, void *, size_t); -static ssize_t fsread(ino_t, void *, size_t); static int dskread(void *, unsigned, unsigned); static int printf(const char *,...); static int putchar(int); @@ -131,16 +130,17 @@ static int xputc(int); static int xgetc(int); static int getc(int); +#if 1 #define memcpy __builtin_memcpy - -static inline void -readfile(const char *fname, void *buf, size_t size) +#else +static void memcpy(char *, const char *, int); +static void +memcpy(char *dst, const char *src, int len) { - ino_t ino; - - if ((ino = lookup(fname))) - fsread(ino, buf, size); + while (len--) + *dst++ = *src++; } +#endif static inline int strcmp(const char *s1, const char *s2) @@ -151,15 +151,14 @@ strcmp(const char *s1, const char *s2) #include "ufsread.c" -static inline int -getchar(void) +static int +xfsread(ino_t inode, void *buf, size_t nbyte) { - int c; - - c = xgetc(0); - if (c == '\r') - c = '\n'; - return c; + if (fsread(inode, buf, nbyte) != nbyte) { + printf("Invalid %s\n", "format"); + return -1; + } + return 0; } static inline void @@ -169,12 +168,13 @@ getstr(char *str, int size) int c; s = str; - do { - switch (c = getchar()) { + for (;;) { + switch (c = xgetc(0)) { case 0: break; - case '\b': case '\177': + c = '\b'; + case '\b': if (s > str) { s--; putchar('\b'); @@ -183,15 +183,16 @@ getstr(char *str, int size) c = 0; break; case '\n': + case '\r': *s = 0; - break; + return; default: if (s - str < size - 1) *s++ = c; } if (c) putchar(c); - } while (c != '\n'); + } } static inline uint32_t @@ -220,6 +221,7 @@ int main(void) { int autoboot, i; + ino_t ino; dmadat = (void *)(roundup2(__base + _end, 0x10000) - __base); v86.ctl = V86_FLAGS; @@ -238,7 +240,10 @@ main(void) /* Process configuration file */ autoboot = 1; - readfile(PATH_CONFIG, cmd, sizeof(cmd)); + + if ((ino = lookup(PATH_CONFIG))) + fsread(ino, cmd, sizeof(cmd)); + if (*cmd) { printf("%s: %s", PATH_CONFIG, cmd); if (parse(cmd)) @@ -328,7 +333,7 @@ load(const char *fname) return; p += hdr.ex.a_data + roundup2(hdr.ex.a_bss, PAGE_SIZE); bootinfo.bi_symtab = VTOP(p); - memcpy(p, &hdr.ex.a_syms, sizeof(hdr.ex.a_syms)); + memcpy(p, (char *)&hdr.ex.a_syms, sizeof(hdr.ex.a_syms)); p += sizeof(hdr.ex.a_syms); if (hdr.ex.a_syms) { if (xfsread(ino, p, hdr.ex.a_syms)) @@ -365,7 +370,7 @@ load(const char *fname) if (xfsread(ino, &es, sizeof(es))) return; for (i = 0; i < 2; i++) { - memcpy(p, &es[i].sh_size, sizeof(es[i].sh_size)); + memcpy(p, (char *)&es[i].sh_size, sizeof(es[i].sh_size)); p += sizeof(es[i].sh_size); fs_off = es[i].sh_offset; if (xfsread(ino, p, es[i].sh_size)) @@ -378,7 +383,7 @@ load(const char *fname) bootinfo.bi_esymtab = VTOP(p); bootinfo.bi_kernelname = VTOP(fname); bootinfo.bi_bios_dev = dsk.drive; - __exec((caddr_t)addr, RB_BOOTINFO | (opts & RBX_MASK), + __exec((caddr_t)addr, opts & RBX_MASK, MAKEBOOTDEV(dev_maj[dsk.type], 0, dsk.slice, dsk.unit, dsk.part), 0, 0, 0, VTOP(&bootinfo)); } @@ -449,9 +454,8 @@ parse(char *arg) arg += 2; if (drv == -1) drv = dsk.unit; - dsk.drive = (dsk.type == TYPE_WD || - dsk.type == TYPE_AD || - dsk.type == TYPE_DA ? DRV_HARD : 0) + drv; + dsk.drive = (dsk.type <= TYPE_MAXHARD + ? DRV_HARD : 0) + drv; dsk_meta = 0; fsread(0, NULL, 0); } @@ -467,16 +471,6 @@ parse(char *arg) } static int -xfsread(ino_t inode, void *buf, size_t nbyte) -{ - if (fsread(inode, buf, nbyte) != nbyte) { - printf("Invalid %s\n", "format"); - return -1; - } - return 0; -} - -static int dskread(void *buf, unsigned lba, unsigned nblk) { struct dos_partition *dp; diff --git a/sys/boot/i386/libi386/Makefile b/sys/boot/i386/libi386/Makefile index 1268e02..5c5292b 100644 --- a/sys/boot/i386/libi386/Makefile +++ b/sys/boot/i386/libi386/Makefile @@ -4,9 +4,9 @@ LIB= i386 INTERNALLIB= true SRCS= aout_freebsd.c biosacpi.c bioscd.c biosdisk.c biosmem.c biospnp.c \ - biospci.c bootinfo.c comconsole.c devicename.c elf_freebsd.c gatea20.c \ - i386_copy.c i386_module.c nullconsole.c pxe.c pxetramp.s \ - time.c vidconsole.c + biospci.c bootinfo.c comconsole.c devicename.c divdi3.c elf_freebsd.c \ + gatea20.c i386_copy.c i386_module.c moddi3.c nullconsole.c pxe.c \ + pxetramp.s qdivrem.c time.c vidconsole.c CFLAGS+= -ffreestanding BOOT_COMCONSOLE_PORT?= 0x3f8 @@ -39,9 +39,12 @@ beforedepend ${OBJS}: machine machine: ln -sf ${.CURDIR}/../../../i386/include machine + ln -sf ${.CURDIR}/../../../../lib/libc/quad/divdi3.c divdi3.c + ln -sf ${.CURDIR}/../../../../lib/libc/quad/moddi3.c moddi3.c + ln -sf ${.CURDIR}/../../../../lib/libc/quad/qdivrem.c qdivrem.c .endif -CLEANFILES+= machine +CLEANFILES+= machine divdi3.c moddi3.c qdivrem.c .include <bsd.lib.mk> diff --git a/sys/boot/i386/loader/Makefile b/sys/boot/i386/loader/Makefile index 0ad1276..8ff4779 100644 --- a/sys/boot/i386/loader/Makefile +++ b/sys/boot/i386/loader/Makefile @@ -119,7 +119,7 @@ FILES+= loader.rc ${BASE}.sym: ${OBJS} ${LIBI386} ${LIBSTAND} ${LIBFICL} vers.o ${CC} ${LDFLAGS} -o ${.TARGET} ${BTXCRT} ${OBJS} vers.o \ - ${LIBFICL} ${LIBI386} ${LIBSTAND} + ${LIBFICL} ${LIBI386} ${LIBSTAND} ${LIBI386} # If it's not there, don't consider it a target .if exists(${.CURDIR}/../../../i386/include) diff --git a/sys/i386/Makefile b/sys/i386/Makefile index 14ba0b3..b7d021a 100644 --- a/sys/i386/Makefile +++ b/sys/i386/Makefile @@ -5,6 +5,7 @@ # SYS is normally set in Make.tags.inc # SYS=/sys +SYS=/nsys TAGDIR= i386 diff --git a/sys/kern/subr_disklabel.c b/sys/kern/subr_disklabel.c index 176dafe..3bedc9c 100644 --- a/sys/kern/subr_disklabel.c +++ b/sys/kern/subr_disklabel.c @@ -41,6 +41,7 @@ #include <sys/param.h> #include <sys/systm.h> +#include <sys/stdint.h> #include <sys/bio.h> #include <sys/buf.h> #include <sys/conf.h> @@ -398,11 +399,11 @@ diskerr(bp, what, blkdone, lp) bp->bio_cmd == BIO_READ ? "read" : "writ"); sn = bp->bio_blkno; if (bp->bio_bcount <= DEV_BSIZE) - printf("%ld", (long)sn); + printf("%lld", (intmax_t)sn); else { if (blkdone >= 0) { sn += blkdone; - printf("%ld of ", (long)sn); + printf("%lld of ", (intmax_t)sn); } printf("%ld-%ld", (long)bp->bio_blkno, (long)(bp->bio_blkno + (bp->bio_bcount - 1) / DEV_BSIZE)); @@ -416,9 +417,9 @@ diskerr(bp, what, blkdone, lp) * independent of slices, labels and bad sector remapping, * but some drivers don't set bp->b_pblkno. */ - printf(" (%s bn %ld; cn %ld", sname, (long)sn, - (long)(sn / lp->d_secpercyl)); - sn %= (long)lp->d_secpercyl; + printf(" (%s bn %lld; cn %lld", sname, (intmax_t)sn, + (intmax_t)(sn / lp->d_secpercyl)); + sn %= lp->d_secpercyl; printf(" tn %ld sn %ld)", (long)(sn / lp->d_nsectors), (long)(sn % lp->d_nsectors)); } diff --git a/sys/kern/subr_diskslice.c b/sys/kern/subr_diskslice.c index a52e301..ec6099e 100644 --- a/sys/kern/subr_diskslice.c +++ b/sys/kern/subr_diskslice.c @@ -152,15 +152,15 @@ dscheck(bp, ssp) struct bio *bp; struct diskslices *ssp; { - daddr_t blkno; - u_long endsecno; - daddr_t labelsect; + daddr_t blkno; + daddr_t endsecno; + daddr_t labelsect; struct disklabel *lp; char *msg; long nsec; struct partition *pp; - daddr_t secno; - daddr_t slicerel_secno; + daddr_t secno; + daddr_t slicerel_secno; struct diskslice *sp; blkno = bp->bio_blkno; diff --git a/sys/kern/vfs_bio.c b/sys/kern/vfs_bio.c index be0778b..100aebf 100644 --- a/sys/kern/vfs_bio.c +++ b/sys/kern/vfs_bio.c @@ -29,6 +29,7 @@ #include <sys/param.h> #include <sys/systm.h> +#include <sys/stdint.h> #include <sys/bio.h> #include <sys/buf.h> #include <sys/eventhandler.h> @@ -2368,7 +2369,7 @@ loop: else bsize = size; - offset = (off_t)blkno * bsize; + offset = blkno * bsize; vmio = (VOP_GETVOBJECT(vp, NULL) == 0) && (vp->v_flag & VOBJBUF); maxsize = vmio ? size + (offset & PAGE_MASK) : size; maxsize = imax(maxsize, bsize); @@ -2946,13 +2947,13 @@ bufdone(struct buf *bp) (int) m->pindex, (int)(foff >> 32), (int) foff & 0xffffffff, resid, i); if (!vn_isdisk(vp, NULL)) - printf(" iosize: %ld, lblkno: %d, flags: 0x%lx, npages: %d\n", + printf(" iosize: %ld, lblkno: %lld, flags: 0x%lx, npages: %d\n", bp->b_vp->v_mount->mnt_stat.f_iosize, - (int) bp->b_lblkno, + (intmax_t) bp->b_lblkno, bp->b_flags, bp->b_npages); else - printf(" VDEV, lblkno: %d, flags: 0x%lx, npages: %d\n", - (int) bp->b_lblkno, + printf(" VDEV, lblkno: %lld, flags: 0x%lx, npages: %d\n", + (intmax_t) bp->b_lblkno, bp->b_flags, bp->b_npages); printf(" valid: 0x%x, dirty: 0x%x, wired: %d\n", m->valid, m->dirty, m->wire_count); @@ -3336,8 +3337,8 @@ vm_hold_free_pages(struct buf * bp, vm_offset_t from, vm_offset_t to) if (p->busy) { printf( "vm_hold_free_pages: blkno: %lld, lblkno: %lld\n", - (long long)bp->b_blkno, - (long long)bp->b_lblkno); + (intmax_t)bp->b_blkno, + (intmax_t)bp->b_lblkno); } bp->b_pages[index] = NULL; pmap_qremove(pg, 1); @@ -3371,7 +3372,7 @@ DB_SHOW_COMMAND(buffer, db_show_buffer) "b_dev = (%d,%d), b_data = %p, b_blkno = %lld, b_pblkno = %lld\n", bp->b_error, bp->b_bufsize, bp->b_bcount, bp->b_resid, major(bp->b_dev), minor(bp->b_dev), bp->b_data, - (long long)bp->b_blkno, (long long)bp->b_pblkno); + (intmax_t)bp->b_blkno, (intmax_t)bp->b_pblkno); if (bp->b_npages) { int i; db_printf("b_npages = %d, pages(OBJ, IDX, PA): ", bp->b_npages); diff --git a/sys/kern/vfs_cluster.c b/sys/kern/vfs_cluster.c index c0eed78..4c11952 100644 --- a/sys/kern/vfs_cluster.c +++ b/sys/kern/vfs_cluster.c @@ -40,6 +40,7 @@ #include <sys/param.h> #include <sys/systm.h> +#include <sys/stdint.h> #include <sys/kernel.h> #include <sys/proc.h> #include <sys/bio.h> @@ -280,15 +281,13 @@ single_block_read: #if defined(CLUSTERDEBUG) if (rcluster) { if (bp) - printf("A+(%ld,%ld,%ld,%d) ", - (long)rbp->b_lblkno, rbp->b_bcount, - (long)(rbp->b_lblkno - origblkno), - seqcount); + printf("A+"); else - printf("A(%ld,%ld,%ld,%d) ", - (long)rbp->b_lblkno, rbp->b_bcount, - (long)(rbp->b_lblkno - origblkno), - seqcount); + printf("A"); + printf("(%lld,%ld,%lld,%d) ", + (intmax_t)rbp->b_lblkno, rbp->b_bcount, + (intmax_t)(rbp->b_lblkno - origblkno), + seqcount); } #endif diff --git a/sys/kern/vfs_extattr.c b/sys/kern/vfs_extattr.c index 5c73224..d66417e 100644 --- a/sys/kern/vfs_extattr.c +++ b/sys/kern/vfs_extattr.c @@ -2631,8 +2631,8 @@ cvtnstat(sb, nsb) nsb->st_blksize = sb->st_blksize; nsb->st_flags = sb->st_flags; nsb->st_gen = sb->st_gen; - nsb->st_qspare[0] = sb->st_qspare[0]; - nsb->st_qspare[1] = sb->st_qspare[1]; + nsb->st_createtimespec = sb->st_createtimespec; + nsb->st_qspare = sb->st_qspare; } #ifndef _SYS_SYSPROTO_H_ diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c index 5c73224..d66417e 100644 --- a/sys/kern/vfs_syscalls.c +++ b/sys/kern/vfs_syscalls.c @@ -2631,8 +2631,8 @@ cvtnstat(sb, nsb) nsb->st_blksize = sb->st_blksize; nsb->st_flags = sb->st_flags; nsb->st_gen = sb->st_gen; - nsb->st_qspare[0] = sb->st_qspare[0]; - nsb->st_qspare[1] = sb->st_qspare[1]; + nsb->st_createtimespec = sb->st_createtimespec; + nsb->st_qspare = sb->st_qspare; } #ifndef _SYS_SYSPROTO_H_ diff --git a/sys/kern/vfs_vnops.c b/sys/kern/vfs_vnops.c index 64e26be..8dcf5c3 100644 --- a/sys/kern/vfs_vnops.c +++ b/sys/kern/vfs_vnops.c @@ -563,8 +563,7 @@ vn_stat(vp, sb, td) * Zero the spare stat fields */ sb->st_lspare = 0; - sb->st_qspare[0] = 0; - sb->st_qspare[1] = 0; + sb->st_qspare = 0; /* * Copy from vattr table @@ -616,6 +615,7 @@ vn_stat(vp, sb, td) sb->st_atimespec = vap->va_atime; sb->st_mtimespec = vap->va_mtime; sb->st_ctimespec = vap->va_ctime; + sb->st_createtimespec = vap->va_createtime; /* * According to www.opengroup.org, the meaning of st_blksize is diff --git a/sys/sys/stat.h b/sys/sys/stat.h index 00c8de0..ce48cef 100644 --- a/sys/sys/stat.h +++ b/sys/sys/stat.h @@ -109,8 +109,9 @@ struct stat { u_int32_t st_blksize; /* optimal blocksize for I/O */ fflags_t st_flags; /* user defined flags for file */ u_int32_t st_gen; /* file generation number */ + struct timespec st_createtimespec; /* time of file creation */ int32_t st_lspare; - int64_t st_qspare[2]; + int64_t st_qspare; }; #ifndef _POSIX_SOURCE @@ -139,7 +140,8 @@ struct nstat { u_int32_t st_blksize; /* optimal blocksize for I/O */ fflags_t st_flags; /* user defined flags for file */ u_int32_t st_gen; /* file generation number */ - int64_t st_qspare[2]; + struct timespec st_createtimespec; /* time of file creation */ + int64_t st_qspare; }; #endif diff --git a/sys/sys/types.h b/sys/sys/types.h index 4390743..ded6f77 100644 --- a/sys/sys/types.h +++ b/sys/sys/types.h @@ -148,8 +148,6 @@ typedef _BSD_SEGSZ_T_ segsz_t; /* segment size (in pages) */ #endif typedef int32_t swblk_t; /* swap offset */ -typedef int32_t ufs_daddr_t; -typedef int32_t ufs_time_t; #ifdef _BSD_UID_T_ typedef _BSD_UID_T_ uid_t; /* user id */ diff --git a/sys/sys/vnode.h b/sys/sys/vnode.h index 182854a..be774bd 100644 --- a/sys/sys/vnode.h +++ b/sys/sys/vnode.h @@ -203,6 +203,7 @@ struct vattr { struct timespec va_atime; /* time of last access */ struct timespec va_mtime; /* time of last modification */ struct timespec va_ctime; /* time file changed */ + struct timespec va_createtime; /* time file created */ u_long va_gen; /* generation number of file */ u_long va_flags; /* flags defined for file */ udev_t va_rdev; /* device the special file represents */ diff --git a/sys/ufs/ffs/ffs_alloc.c b/sys/ufs/ffs/ffs_alloc.c index 2dbb487..dbd757e 100644 --- a/sys/ufs/ffs/ffs_alloc.c +++ b/sys/ufs/ffs/ffs_alloc.c @@ -1,4 +1,16 @@ /* + * Copyright (c) 2002 Networks Associates Technology, Inc. + * All rights reserved. + * + * This software was developed for the FreeBSD Project by Marshall + * Kirk McKusick and Network Associates Laboratories, the Security + * Research Division of Network Associates, Inc. under DARPA/SPAWAR + * contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS + * research program + * + * Copyright (c) 1982, 1989, 1993 + * The Regents of the University of California. All rights reserved. + * (c) UNIX System Laboratories, Inc. * Copyright (c) 1982, 1986, 1989, 1993 * The Regents of the University of California. All rights reserved. * @@ -46,6 +58,7 @@ #include <sys/vnode.h> #include <sys/mount.h> #include <sys/kernel.h> +#include <sys/stdint.h> #include <sys/sysctl.h> #include <sys/syslog.h> @@ -58,23 +71,25 @@ #include <ufs/ffs/fs.h> #include <ufs/ffs/ffs_extern.h> -typedef ufs_daddr_t allocfcn_t(struct inode *ip, int cg, ufs_daddr_t bpref, +typedef ufs2_daddr_t allocfcn_t(struct inode *ip, int cg, ufs2_daddr_t bpref, int size); -static ufs_daddr_t ffs_alloccg(struct inode *, int, ufs_daddr_t, int); -static ufs_daddr_t - ffs_alloccgblk(struct inode *, struct buf *, ufs_daddr_t); +static ufs2_daddr_t ffs_alloccg(struct inode *, int, ufs2_daddr_t, int); +static ufs2_daddr_t + ffs_alloccgblk(struct inode *, struct buf *, ufs2_daddr_t); #ifdef DIAGNOSTIC -static int ffs_checkblk(struct inode *, ufs_daddr_t, long); +static int ffs_checkblk(struct inode *, ufs2_daddr_t, long); #endif -static ufs_daddr_t ffs_clusteralloc(struct inode *, int, ufs_daddr_t, int); +static ufs2_daddr_t ffs_clusteralloc(struct inode *, int, ufs2_daddr_t, int); static ino_t ffs_dirpref(struct inode *); -static ufs_daddr_t ffs_fragextend(struct inode *, int, long, int, int); +static ufs2_daddr_t ffs_fragextend(struct inode *, int, ufs2_daddr_t, int, int); static void ffs_fserr(struct fs *, ino_t, char *); -static u_long ffs_hashalloc - (struct inode *, int, long, int, allocfcn_t *); -static ino_t ffs_nodealloccg(struct inode *, int, ufs_daddr_t, int); -static ufs_daddr_t ffs_mapsearch(struct fs *, struct cg *, ufs_daddr_t, int); +static ufs2_daddr_t ffs_hashalloc + (struct inode *, int, ufs2_daddr_t, int, allocfcn_t *); +static ino_t ffs_nodealloccg(struct inode *, int, ufs2_daddr_t, int); +static ufs1_daddr_t ffs_mapsearch(struct fs *, struct cg *, ufs2_daddr_t, int); +static int ffs_reallocblks_ufs1(struct vop_reallocblks_args *); +static int ffs_reallocblks_ufs2(struct vop_reallocblks_args *); /* * Allocate a block in the filesystem. @@ -98,13 +113,13 @@ static ufs_daddr_t ffs_mapsearch(struct fs *, struct cg *, ufs_daddr_t, int); int ffs_alloc(ip, lbn, bpref, size, cred, bnp) struct inode *ip; - ufs_daddr_t lbn, bpref; + ufs2_daddr_t lbn, bpref; int size; struct ucred *cred; - ufs_daddr_t *bnp; + ufs2_daddr_t *bnp; { struct fs *fs; - ufs_daddr_t bno; + ufs2_daddr_t bno; int cg, reclaimed; #ifdef QUOTA int error; @@ -130,7 +145,7 @@ retry: freespace(fs, fs->fs_minfree) - numfrags(fs, size) < 0) goto nospace; #ifdef QUOTA - error = chkdq(ip, (long)btodb(size), cred, 0); + error = chkdq(ip, btodb(size), cred, 0); if (error) return (error); #endif @@ -140,10 +155,9 @@ retry: cg = ino_to_cg(fs, ip->i_number); else cg = dtog(fs, bpref); - bno = (ufs_daddr_t)ffs_hashalloc(ip, cg, (long)bpref, size, - ffs_alloccg); + bno = ffs_hashalloc(ip, cg, bpref, size, ffs_alloccg); if (bno > 0) { - ip->i_blocks += btodb(size); + DIP(ip, i_blocks) += btodb(size); ip->i_flag |= IN_CHANGE | IN_UPDATE; *bnp = bno; return (0); @@ -152,7 +166,7 @@ retry: /* * Restore user's disk quota because allocation failed. */ - (void) chkdq(ip, (long)-btodb(size), cred, FORCE); + (void) chkdq(ip, -btodb(size), cred, FORCE); #endif nospace: if (fs->fs_pendingblocks > 0 && reclaimed == 0) { @@ -176,8 +190,8 @@ nospace: int ffs_realloccg(ip, lbprev, bpref, osize, nsize, cred, bpp) struct inode *ip; - ufs_daddr_t lbprev; - ufs_daddr_t bpref; + ufs2_daddr_t lbprev; + ufs2_daddr_t bpref; int osize, nsize; struct ucred *cred; struct buf **bpp; @@ -186,7 +200,7 @@ ffs_realloccg(ip, lbprev, bpref, osize, nsize, cred, bpp) struct fs *fs; struct buf *bp; int cg, request, error, reclaimed; - ufs_daddr_t bprev, bno; + ufs2_daddr_t bprev, bno; *bpp = 0; vp = ITOV(ip); @@ -210,9 +224,9 @@ retry: if (suser_cred(cred, PRISON_ROOT) && freespace(fs, fs->fs_minfree) - numfrags(fs, nsize - osize) < 0) goto nospace; - if ((bprev = ip->i_db[lbprev]) == 0) { - printf("dev = %s, bsize = %ld, bprev = %ld, fs = %s\n", - devtoname(ip->i_dev), (long)fs->fs_bsize, (long)bprev, + if ((bprev = DIP(ip, i_db[lbprev])) == 0) { + printf("dev = %s, bsize = %ld, bprev = %lld, fs = %s\n", + devtoname(ip->i_dev), (long)fs->fs_bsize, (intmax_t)bprev, fs->fs_fsmnt); panic("ffs_realloccg: bad bprev"); } @@ -225,14 +239,14 @@ retry: return (error); } - if( bp->b_blkno == bp->b_lblkno) { - if( lbprev >= NDADDR) + if (bp->b_blkno == bp->b_lblkno) { + if (lbprev >= NDADDR) panic("ffs_realloccg: lbprev out of range"); bp->b_blkno = fsbtodb(fs, bprev); } #ifdef QUOTA - error = chkdq(ip, (long)btodb(nsize - osize), cred, 0); + error = chkdq(ip, btodb(nsize - osize), cred, 0); if (error) { brelse(bp); return (error); @@ -242,11 +256,11 @@ retry: * Check for extension in the existing location. */ cg = dtog(fs, bprev); - bno = ffs_fragextend(ip, cg, (long)bprev, osize, nsize); + bno = ffs_fragextend(ip, cg, bprev, osize, nsize); if (bno) { if (bp->b_blkno != fsbtodb(fs, bno)) panic("ffs_realloccg: bad blockno"); - ip->i_blocks += btodb(nsize - osize); + DIP(ip, i_blocks) += btodb(nsize - osize); ip->i_flag |= IN_CHANGE | IN_UPDATE; allocbuf(bp, nsize); bp->b_flags |= B_DONE; @@ -302,8 +316,7 @@ retry: panic("ffs_realloccg: bad optim"); /* NOTREACHED */ } - bno = (ufs_daddr_t)ffs_hashalloc(ip, cg, (long)bpref, request, - ffs_alloccg); + bno = ffs_hashalloc(ip, cg, bpref, request, ffs_alloccg); if (bno > 0) { bp->b_blkno = fsbtodb(fs, bno); if (!DOINGSOFTDEP(vp)) @@ -312,7 +325,7 @@ retry: if (nsize < request) ffs_blkfree(fs, ip->i_devvp, bno + numfrags(fs, nsize), (long)(request - nsize), ip->i_number); - ip->i_blocks += btodb(nsize - osize); + DIP(ip, i_blocks) += btodb(nsize - osize); ip->i_flag |= IN_CHANGE | IN_UPDATE; allocbuf(bp, nsize); bp->b_flags |= B_DONE; @@ -324,7 +337,7 @@ retry: /* * Restore user's disk quota because allocation failed. */ - (void) chkdq(ip, (long)-btodb(nsize - osize), cred, FORCE); + (void) chkdq(ip, -btodb(nsize - osize), cred, FORCE); #endif brelse(bp); nospace: @@ -346,14 +359,14 @@ nospace: * * The vnode and an array of buffer pointers for a range of sequential * logical blocks to be made contiguous is given. The allocator attempts - * to find a range of sequential blocks starting as close as possible to - * an fs_rotdelay offset from the end of the allocation for the logical - * block immediately preceding the current range. If successful, the - * physical block numbers in the buffer pointers and in the inode are - * changed to reflect the new allocation. If unsuccessful, the allocation - * is left unchanged. The success in doing the reallocation is returned. - * Note that the error return is not reflected back to the user. Rather - * the previous block allocation will be used. + * to find a range of sequential blocks starting as close as possible + * from the end of the allocation for the logical block immediately + * preceding the current range. If successful, the physical block numbers + * in the buffer pointers and in the inode are changed to reflect the new + * allocation. If unsuccessful, the allocation is left unchanged. The + * success in doing the reallocation is returned. Note that the error + * return is not reflected back to the user. Rather the previous block + * allocation will be used. */ SYSCTL_NODE(_vfs, OID_AUTO, ffs, CTLFLAG_RW, 0, "FFS filesystem"); @@ -375,18 +388,33 @@ ffs_reallocblks(ap) struct cluster_save *a_buflist; } */ *ap; { + + if (doreallocblks == 0) + return (ENOSPC); + if (VTOI(ap->a_vp)->i_ump->um_fstype == UFS1) + return (ffs_reallocblks_ufs1(ap)); + return (ffs_reallocblks_ufs2(ap)); +} + +static int +ffs_reallocblks_ufs1(ap) + struct vop_reallocblks_args /* { + struct vnode *a_vp; + struct cluster_save *a_buflist; + } */ *ap; +{ struct fs *fs; struct inode *ip; struct vnode *vp; struct buf *sbp, *ebp; - ufs_daddr_t *bap, *sbap, *ebap = 0; + ufs1_daddr_t *bap, *sbap, *ebap = 0; struct cluster_save *buflist; - ufs_daddr_t start_lbn, end_lbn, soff, newblk, blkno; + ufs_lbn_t start_lbn, end_lbn; + ufs1_daddr_t soff, newblk, blkno; + ufs2_daddr_t pref; struct indir start_ap[NIADDR + 1], end_ap[NIADDR + 1], *idp; - int i, len, start_lvl, end_lvl, pref, ssize; + int i, len, start_lvl, end_lvl, ssize; - if (doreallocblks == 0) - return (ENOSPC); vp = ap->a_vp; ip = VTOI(vp); fs = ip->i_fs; @@ -425,7 +453,7 @@ ffs_reallocblks(ap) * Get the starting offset and block map for the first block. */ if (start_lvl == 0) { - sbap = &ip->i_db[0]; + sbap = &ip->i_din1->di_db[0]; soff = start_lbn; } else { idp = &start_ap[start_lvl - 1]; @@ -433,13 +461,13 @@ ffs_reallocblks(ap) brelse(sbp); return (ENOSPC); } - sbap = (ufs_daddr_t *)sbp->b_data; + sbap = (ufs1_daddr_t *)sbp->b_data; soff = idp->in_off; } /* * Find the preferred location for the cluster. */ - pref = ffs_blkpref(ip, start_lbn, soff, sbap); + pref = ffs_blkpref_ufs1(ip, start_lbn, soff, sbap); /* * If the block range spans two block maps, get the second map. */ @@ -453,12 +481,12 @@ ffs_reallocblks(ap) ssize = len - (idp->in_off + 1); if (bread(vp, idp->in_lbn, (int)fs->fs_bsize, NOCRED, &ebp)) goto fail; - ebap = (ufs_daddr_t *)ebp->b_data; + ebap = (ufs1_daddr_t *)ebp->b_data; } /* * Search the block map looking for an allocation of the desired size. */ - if ((newblk = (ufs_daddr_t)ffs_hashalloc(ip, dtog(fs, pref), (long)pref, + if ((newblk = ffs_hashalloc(ip, dtog(fs, pref), pref, len, ffs_clusteralloc)) == 0) goto fail; /* @@ -470,8 +498,8 @@ ffs_reallocblks(ap) */ #ifdef DEBUG if (prtrealloc) - printf("realloc: ino %d, lbns %d-%d\n\told:", ip->i_number, - start_lbn, end_lbn); + printf("realloc: ino %d, lbns %lld-%lld\n\told:", ip->i_number, + (intmax_t)start_lbn, (intmax_t)end_lbn); #endif blkno = newblk; for (bap = &sbap[soff], i = 0; i < len; i++, blkno += fs->fs_frag) { @@ -491,7 +519,7 @@ ffs_reallocblks(ap) printf(" %d,", *bap); #endif if (DOINGSOFTDEP(vp)) { - if (sbap == &ip->i_db[0] && i < ssize) + if (sbap == &ip->i_din1->di_db[0] && i < ssize) softdep_setup_allocdirect(ip, start_lbn + i, blkno, *bap, fs->fs_bsize, fs->fs_bsize, buflist->bs_children[i]); @@ -516,7 +544,7 @@ ffs_reallocblks(ap) * We can then check below to see if it is set, and do the * synchronous write only when it has been cleared. */ - if (sbap != &ip->i_db[0]) { + if (sbap != &ip->i_din1->di_db[0]) { if (doasyncfree) bdwrite(sbp); else @@ -566,7 +594,209 @@ ffs_reallocblks(ap) fail: if (ssize < len) brelse(ebp); - if (sbap != &ip->i_db[0]) + if (sbap != &ip->i_din1->di_db[0]) + brelse(sbp); + return (ENOSPC); +} + +static int +ffs_reallocblks_ufs2(ap) + struct vop_reallocblks_args /* { + struct vnode *a_vp; + struct cluster_save *a_buflist; + } */ *ap; +{ + struct fs *fs; + struct inode *ip; + struct vnode *vp; + struct buf *sbp, *ebp; + ufs2_daddr_t *bap, *sbap, *ebap = 0; + struct cluster_save *buflist; + ufs_lbn_t start_lbn, end_lbn; + ufs2_daddr_t soff, newblk, blkno, pref; + struct indir start_ap[NIADDR + 1], end_ap[NIADDR + 1], *idp; + int i, len, start_lvl, end_lvl, ssize; + + vp = ap->a_vp; + ip = VTOI(vp); + fs = ip->i_fs; + if (fs->fs_contigsumsize <= 0) + return (ENOSPC); + buflist = ap->a_buflist; + len = buflist->bs_nchildren; + start_lbn = buflist->bs_children[0]->b_lblkno; + end_lbn = start_lbn + len - 1; +#ifdef DIAGNOSTIC + for (i = 0; i < len; i++) + if (!ffs_checkblk(ip, + dbtofsb(fs, buflist->bs_children[i]->b_blkno), fs->fs_bsize)) + panic("ffs_reallocblks: unallocated block 1"); + for (i = 1; i < len; i++) + if (buflist->bs_children[i]->b_lblkno != start_lbn + i) + panic("ffs_reallocblks: non-logical cluster"); + blkno = buflist->bs_children[0]->b_blkno; + ssize = fsbtodb(fs, fs->fs_frag); + for (i = 1; i < len - 1; i++) + if (buflist->bs_children[i]->b_blkno != blkno + (i * ssize)) + panic("ffs_reallocblks: non-physical cluster %d", i); +#endif + /* + * If the latest allocation is in a new cylinder group, assume that + * the filesystem has decided to move and do not force it back to + * the previous cylinder group. + */ + if (dtog(fs, dbtofsb(fs, buflist->bs_children[0]->b_blkno)) != + dtog(fs, dbtofsb(fs, buflist->bs_children[len - 1]->b_blkno))) + return (ENOSPC); + if (ufs_getlbns(vp, start_lbn, start_ap, &start_lvl) || + ufs_getlbns(vp, end_lbn, end_ap, &end_lvl)) + return (ENOSPC); + /* + * Get the starting offset and block map for the first block. + */ + if (start_lvl == 0) { + sbap = &ip->i_din2->di_db[0]; + soff = start_lbn; + } else { + idp = &start_ap[start_lvl - 1]; + if (bread(vp, idp->in_lbn, (int)fs->fs_bsize, NOCRED, &sbp)) { + brelse(sbp); + return (ENOSPC); + } + sbap = (ufs2_daddr_t *)sbp->b_data; + soff = idp->in_off; + } + /* + * Find the preferred location for the cluster. + */ + pref = ffs_blkpref_ufs2(ip, start_lbn, soff, sbap); + /* + * If the block range spans two block maps, get the second map. + */ + if (end_lvl == 0 || (idp = &end_ap[end_lvl - 1])->in_off + 1 >= len) { + ssize = len; + } else { +#ifdef DIAGNOSTIC + if (start_ap[start_lvl-1].in_lbn == idp->in_lbn) + panic("ffs_reallocblk: start == end"); +#endif + ssize = len - (idp->in_off + 1); + if (bread(vp, idp->in_lbn, (int)fs->fs_bsize, NOCRED, &ebp)) + goto fail; + ebap = (ufs2_daddr_t *)ebp->b_data; + } + /* + * Search the block map looking for an allocation of the desired size. + */ + if ((newblk = ffs_hashalloc(ip, dtog(fs, pref), pref, + len, ffs_clusteralloc)) == 0) + goto fail; + /* + * We have found a new contiguous block. + * + * First we have to replace the old block pointers with the new + * block pointers in the inode and indirect blocks associated + * with the file. + */ +#ifdef DEBUG + if (prtrealloc) + printf("realloc: ino %d, lbns %lld-%lld\n\told:", ip->i_number, + (intmax_t)start_lbn, (intmax_t)end_lbn); +#endif + blkno = newblk; + for (bap = &sbap[soff], i = 0; i < len; i++, blkno += fs->fs_frag) { + if (i == ssize) { + bap = ebap; + soff = -i; + } +#ifdef DIAGNOSTIC + if (!ffs_checkblk(ip, + dbtofsb(fs, buflist->bs_children[i]->b_blkno), fs->fs_bsize)) + panic("ffs_reallocblks: unallocated block 2"); + if (dbtofsb(fs, buflist->bs_children[i]->b_blkno) != *bap) + panic("ffs_reallocblks: alloc mismatch"); +#endif +#ifdef DEBUG + if (prtrealloc) + printf(" %lld,", (intmax_t)*bap); +#endif + if (DOINGSOFTDEP(vp)) { + if (sbap == &ip->i_din2->di_db[0] && i < ssize) + softdep_setup_allocdirect(ip, start_lbn + i, + blkno, *bap, fs->fs_bsize, fs->fs_bsize, + buflist->bs_children[i]); + else + softdep_setup_allocindir_page(ip, start_lbn + i, + i < ssize ? sbp : ebp, soff + i, blkno, + *bap, buflist->bs_children[i]); + } + *bap++ = blkno; + } + /* + * Next we must write out the modified inode and indirect blocks. + * For strict correctness, the writes should be synchronous since + * the old block values may have been written to disk. In practise + * they are almost never written, but if we are concerned about + * strict correctness, the `doasyncfree' flag should be set to zero. + * + * The test on `doasyncfree' should be changed to test a flag + * that shows whether the associated buffers and inodes have + * been written. The flag should be set when the cluster is + * started and cleared whenever the buffer or inode is flushed. + * We can then check below to see if it is set, and do the + * synchronous write only when it has been cleared. + */ + if (sbap != &ip->i_din2->di_db[0]) { + if (doasyncfree) + bdwrite(sbp); + else + bwrite(sbp); + } else { + ip->i_flag |= IN_CHANGE | IN_UPDATE; + if (!doasyncfree) + UFS_UPDATE(vp, 1); + } + if (ssize < len) { + if (doasyncfree) + bdwrite(ebp); + else + bwrite(ebp); + } + /* + * Last, free the old blocks and assign the new blocks to the buffers. + */ +#ifdef DEBUG + if (prtrealloc) + printf("\n\tnew:"); +#endif + for (blkno = newblk, i = 0; i < len; i++, blkno += fs->fs_frag) { + if (!DOINGSOFTDEP(vp)) + ffs_blkfree(fs, ip->i_devvp, + dbtofsb(fs, buflist->bs_children[i]->b_blkno), + fs->fs_bsize, ip->i_number); + buflist->bs_children[i]->b_blkno = fsbtodb(fs, blkno); +#ifdef DIAGNOSTIC + if (!ffs_checkblk(ip, + dbtofsb(fs, buflist->bs_children[i]->b_blkno), fs->fs_bsize)) + panic("ffs_reallocblks: unallocated block 3"); +#endif +#ifdef DEBUG + if (prtrealloc) + printf(" %d,", blkno); +#endif + } +#ifdef DEBUG + if (prtrealloc) { + prtrealloc--; + printf("\n"); + } +#endif + return (0); + +fail: + if (ssize < len) + brelse(ebp); + if (sbap != &ip->i_din2->di_db[0]) brelse(sbp); return (ENOSPC); } @@ -596,6 +826,7 @@ ffs_valloc(pvp, mode, cred, vpp) struct inode *pip; struct fs *fs; struct inode *ip; + struct timespec ts; ino_t ino, ipref; int cg, error; @@ -623,7 +854,7 @@ ffs_valloc(pvp, mode, cred, vpp) if (fs->fs_contigdirs[cg] > 0) fs->fs_contigdirs[cg]--; } - ino = (ino_t)ffs_hashalloc(pip, cg, (long)ipref, mode, + ino = (ino_t)ffs_hashalloc(pip, cg, ipref, mode, (allocfcn_t *)ffs_nodealloccg); if (ino == 0) goto noinodes; @@ -638,17 +869,24 @@ ffs_valloc(pvp, mode, cred, vpp) ip->i_mode, (u_long)ip->i_number, fs->fs_fsmnt); panic("ffs_valloc: dup alloc"); } - if (ip->i_blocks && (fs->fs_flags & FS_UNCLEAN) == 0) { /* XXX */ + if (DIP(ip, i_blocks) && (fs->fs_flags & FS_UNCLEAN) == 0) { /* XXX */ printf("free inode %s/%lu had %ld blocks\n", - fs->fs_fsmnt, (u_long)ino, (long)ip->i_blocks); - ip->i_blocks = 0; + fs->fs_fsmnt, (u_long)ino, (long)DIP(ip, i_blocks)); + DIP(ip, i_blocks) = 0; } ip->i_flags = 0; + DIP(ip, i_flags) = 0; /* * Set up a new generation number for this inode. */ if (ip->i_gen == 0 || ++ip->i_gen == 0) ip->i_gen = random() / 2 + 1; + DIP(ip, i_gen) = ip->i_gen; + if (fs->fs_magic == FS_UFS2_MAGIC) { + vfs_timestamp(&ts); + ip->i_din2->di_createtime = ts.tv_sec; + ip->i_din2->di_creatensec = ts.tv_nsec; + } return (0); noinodes: ffs_fserr(fs, pip->i_number, "out of inodes"); @@ -785,23 +1023,20 @@ ffs_dirpref(pip) * allocated. * * If a section is already partially allocated, the policy is to - * contiguously allocate fs_maxcontig blocks. The end of one of these - * contiguous blocks and the beginning of the next is physically separated - * so that the disk head will be in transit between them for at least - * fs_rotdelay milliseconds. This is to allow time for the processor to - * schedule another I/O transfer. + * contiguously allocate fs_maxcontig blocks. The end of one of these + * contiguous blocks and the beginning of the next is laid out + * contiguously if possible. */ -ufs_daddr_t -ffs_blkpref(ip, lbn, indx, bap) +ufs2_daddr_t +ffs_blkpref_ufs1(ip, lbn, indx, bap) struct inode *ip; - ufs_daddr_t lbn; + ufs_lbn_t lbn; int indx; - ufs_daddr_t *bap; + ufs1_daddr_t *bap; { struct fs *fs; int cg; int avgbfree, startcg; - ufs_daddr_t nextblk; fs = ip->i_fs; if (indx % fs->fs_maxbpg == 0 || bap[indx - 1] == 0) { @@ -833,25 +1068,58 @@ ffs_blkpref(ip, lbn, indx, bap) return (0); } /* - * One or more previous blocks have been laid out. If less - * than fs_maxcontig previous blocks are contiguous, the - * next block is requested contiguously, otherwise it is - * requested rotationally delayed by fs_rotdelay milliseconds. + * We just always try to lay things out contiguously. */ - nextblk = bap[indx - 1] + fs->fs_frag; - if (fs->fs_rotdelay == 0 || indx < fs->fs_maxcontig || - bap[indx - fs->fs_maxcontig] + - blkstofrags(fs, fs->fs_maxcontig) != nextblk) - return (nextblk); + return (bap[indx - 1] + fs->fs_frag); +} + +/* + * Same as above, but for UFS2 + */ +ufs2_daddr_t +ffs_blkpref_ufs2(ip, lbn, indx, bap) + struct inode *ip; + ufs_lbn_t lbn; + int indx; + ufs2_daddr_t *bap; +{ + struct fs *fs; + int cg; + int avgbfree, startcg; + + fs = ip->i_fs; + if (indx % fs->fs_maxbpg == 0 || bap[indx - 1] == 0) { + if (lbn < NDADDR + NINDIR(fs)) { + cg = ino_to_cg(fs, ip->i_number); + return (fs->fs_fpg * cg + fs->fs_frag); + } + /* + * Find a cylinder with greater than average number of + * unused data blocks. + */ + if (indx == 0 || bap[indx - 1] == 0) + startcg = + ino_to_cg(fs, ip->i_number) + lbn / fs->fs_maxbpg; + else + startcg = dtog(fs, bap[indx - 1]) + 1; + startcg %= fs->fs_ncg; + avgbfree = fs->fs_cstotal.cs_nbfree / fs->fs_ncg; + for (cg = startcg; cg < fs->fs_ncg; cg++) + if (fs->fs_cs(fs, cg).cs_nbfree >= avgbfree) { + fs->fs_cgrotor = cg; + return (fs->fs_fpg * cg + fs->fs_frag); + } + for (cg = 0; cg <= startcg; cg++) + if (fs->fs_cs(fs, cg).cs_nbfree >= avgbfree) { + fs->fs_cgrotor = cg; + return (fs->fs_fpg * cg + fs->fs_frag); + } + return (0); + } /* - * Here we convert ms of delay to frags as: - * (frags) = (ms) * (rev/sec) * (sect/rev) / - * ((sect/frag) * (ms/sec)) - * then round up to the next block. + * We just always try to lay things out contiguously. */ - nextblk += roundup(fs->fs_rotdelay * fs->fs_rps * fs->fs_nsect / - (NSPF(fs) * 1000), fs->fs_frag); - return (nextblk); + return (bap[indx - 1] + fs->fs_frag); } /* @@ -863,16 +1131,16 @@ ffs_blkpref(ip, lbn, indx, bap) * 3) brute force search for a free block. */ /*VARARGS5*/ -static u_long +static ufs2_daddr_t ffs_hashalloc(ip, cg, pref, size, allocator) struct inode *ip; int cg; - long pref; + ufs2_daddr_t pref; int size; /* size for data blocks, mode for inodes */ allocfcn_t *allocator; { struct fs *fs; - long result; /* XXX why not same type as we return? */ + ufs2_daddr_t result; int i, icg = cg; #ifdef DIAGNOSTIC @@ -920,11 +1188,11 @@ ffs_hashalloc(ip, cg, pref, size, allocator) * Check to see if the necessary fragments are available, and * if they are, allocate them. */ -static ufs_daddr_t +static ufs2_daddr_t ffs_fragextend(ip, cg, bprev, osize, nsize) struct inode *ip; int cg; - long bprev; + ufs2_daddr_t bprev; int osize, nsize; { struct fs *fs; @@ -956,7 +1224,7 @@ ffs_fragextend(ip, cg, bprev, osize, nsize) return (0); } bp->b_xflags |= BX_BKGRDWRITE; - cgp->cg_time = time_second; + cgp->cg_old_time = cgp->cg_time = time_second; bno = dtogd(fs, bprev); blksfree = cg_blksfree(cgp); for (i = numfrags(fs, osize); i < frags; i++) @@ -997,19 +1265,19 @@ ffs_fragextend(ip, cg, bprev, osize, nsize) * Check to see if a block of the appropriate size is available, * and if it is, allocate it. */ -static ufs_daddr_t +static ufs2_daddr_t ffs_alloccg(ip, cg, bpref, size) struct inode *ip; int cg; - ufs_daddr_t bpref; + ufs2_daddr_t bpref; int size; { struct fs *fs; struct cg *cgp; struct buf *bp; - int i; - ufs_daddr_t bno, blkno; - int allocsiz, error, frags; + ufs1_daddr_t bno; + ufs2_daddr_t blkno; + int i, allocsiz, error, frags; u_int8_t *blksfree; fs = ip->i_fs; @@ -1028,13 +1296,13 @@ ffs_alloccg(ip, cg, bpref, size) return (0); } bp->b_xflags |= BX_BKGRDWRITE; - cgp->cg_time = time_second; + cgp->cg_old_time = cgp->cg_time = time_second; if (size == fs->fs_bsize) { - bno = ffs_alloccgblk(ip, bp, bpref); + blkno = ffs_alloccgblk(ip, bp, bpref); if (fs->fs_active != 0) atomic_clear_int(&ACTIVECGNUM(fs, cg), ACTIVECGOFF(cg)); bdwrite(bp); - return (bno); + return (blkno); } /* * check to see if any fragments are already available @@ -1055,10 +1323,10 @@ ffs_alloccg(ip, cg, bpref, size) brelse(bp); return (0); } - bno = ffs_alloccgblk(ip, bp, bpref); - bpref = dtogd(fs, bno); + blkno = ffs_alloccgblk(ip, bp, bpref); + bno = dtogd(fs, blkno); for (i = frags; i < fs->fs_frag; i++) - setbit(blksfree, bpref + i); + setbit(blksfree, bno + i); i = fs->fs_frag - frags; cgp->cg_cs.cs_nffree += i; fs->fs_cstotal.cs_nffree += i; @@ -1068,7 +1336,7 @@ ffs_alloccg(ip, cg, bpref, size) if (fs->fs_active != 0) atomic_clear_int(&ACTIVECGNUM(fs, cg), ACTIVECGOFF(cg)); bdwrite(bp); - return (bno); + return (blkno); } bno = ffs_mapsearch(fs, cgp, bpref, allocsiz); if (bno < 0) { @@ -1090,7 +1358,7 @@ ffs_alloccg(ip, cg, bpref, size) if (fs->fs_active != 0) atomic_clear_int(&ACTIVECGNUM(fs, cg), ACTIVECGOFF(cg)); bdwrite(bp); - return ((u_long)blkno); + return (blkno); } /* @@ -1104,18 +1372,16 @@ ffs_alloccg(ip, cg, bpref, size) * Note that this routine only allocates fs_bsize blocks; these * blocks may be fragmented by the routine that allocates them. */ -static ufs_daddr_t +static ufs2_daddr_t ffs_alloccgblk(ip, bp, bpref) struct inode *ip; struct buf *bp; - ufs_daddr_t bpref; + ufs2_daddr_t bpref; { struct fs *fs; struct cg *cgp; - ufs_daddr_t bno, blkno; - int cylno, pos, delta; - short *cylbp; - int i; + ufs1_daddr_t bno; + ufs2_daddr_t blkno; u_int8_t *blksfree; fs = ip->i_fs; @@ -1123,78 +1389,17 @@ ffs_alloccgblk(ip, bp, bpref) blksfree = cg_blksfree(cgp); if (bpref == 0 || dtog(fs, bpref) != cgp->cg_cgx) { bpref = cgp->cg_rotor; - goto norot; - } - bpref = blknum(fs, bpref); - bpref = dtogd(fs, bpref); - /* - * if the requested block is available, use it - */ - if (ffs_isblock(fs, blksfree, fragstoblks(fs, bpref))) { - bno = bpref; - goto gotit; - } - if (fs->fs_nrpos <= 1 || fs->fs_cpc == 0) { - /* - * Block layout information is not available. - * Leaving bpref unchanged means we take the - * next available free block following the one - * we just allocated. Hopefully this will at - * least hit a track cache on drives of unknown - * geometry (e.g. SCSI). - */ - goto norot; - } - /* - * check for a block available on the same cylinder - */ - cylno = cbtocylno(fs, bpref); - if (cg_blktot(cgp)[cylno] == 0) - goto norot; - /* - * check the summary information to see if a block is - * available in the requested cylinder starting at the - * requested rotational position and proceeding around. - */ - cylbp = cg_blks(fs, cgp, cylno); - pos = cbtorpos(fs, bpref); - for (i = pos; i < fs->fs_nrpos; i++) - if (cylbp[i] > 0) - break; - if (i == fs->fs_nrpos) - for (i = 0; i < pos; i++) - if (cylbp[i] > 0) - break; - if (cylbp[i] > 0) { + } else { + bpref = blknum(fs, bpref); + bno = dtogd(fs, bpref); /* - * found a rotational position, now find the actual - * block. A panic if none is actually there. + * if the requested block is available, use it */ - pos = cylno % fs->fs_cpc; - bno = (cylno - pos) * fs->fs_spc / NSPB(fs); - if (fs_postbl(fs, pos)[i] == -1) { - printf("pos = %d, i = %d, fs = %s\n", - pos, i, fs->fs_fsmnt); - panic("ffs_alloccgblk: cyl groups corrupted"); - } - for (i = fs_postbl(fs, pos)[i];; ) { - if (ffs_isblock(fs, blksfree, bno + i)) { - bno = blkstofrags(fs, (bno + i)); - goto gotit; - } - delta = fs_rotbl(fs)[i]; - if (delta <= 0 || - delta + i > fragstoblks(fs, fs->fs_fpg)) - break; - i += delta; - } - printf("pos = %d, i = %d, fs = %s\n", pos, i, fs->fs_fsmnt); - panic("ffs_alloccgblk: can't find blk in cyl"); + if (ffs_isblock(fs, blksfree, fragstoblks(fs, bno))) + goto gotit; } -norot: /* - * no blocks in the requested cylinder, so take next - * available one in this cylinder group. + * Take the next available block in this cylinder group. */ bno = ffs_mapsearch(fs, cgp, bpref, (int)fs->fs_frag); if (bno < 0) @@ -1207,9 +1412,6 @@ gotit: cgp->cg_cs.cs_nbfree--; fs->fs_cstotal.cs_nbfree--; fs->fs_cs(fs, cgp->cg_cgx).cs_nbfree--; - cylno = cbtocylno(fs, bno); - cg_blks(fs, cgp, cylno)[cbtorpos(fs, bno)]--; - cg_blktot(cgp)[cylno]--; fs->fs_fmod = 1; blkno = cgp->cg_cgx * fs->fs_fpg + bno; if (DOINGSOFTDEP(ITOV(ip))) @@ -1224,17 +1426,18 @@ gotit: * are multiple choices in the same cylinder group. Instead we just * take the first one that we find following bpref. */ -static ufs_daddr_t +static ufs2_daddr_t ffs_clusteralloc(ip, cg, bpref, len) struct inode *ip; int cg; - ufs_daddr_t bpref; + ufs2_daddr_t bpref; int len; { struct fs *fs; struct cg *cgp; struct buf *bp; - int i, got, run, bno, bit, map; + int i, run, bit, map, got; + ufs2_daddr_t bno; u_char *mapp; int32_t *lp; u_int8_t *blksfree; @@ -1319,7 +1522,7 @@ ffs_clusteralloc(ip, cg, bpref, len) panic("ffs_clusteralloc: allocated out of group"); len = blkstofrags(fs, len); for (i = 0; i < len; i += fs->fs_frag) - if ((got = ffs_alloccgblk(ip, bp, bno + i)) != bno + i) + if (ffs_alloccgblk(ip, bp, bno + i) != bno + i) panic("ffs_clusteralloc: lost block"); if (fs->fs_active != 0) atomic_clear_int(&ACTIVECGNUM(fs, cg), ACTIVECGOFF(cg)); @@ -1344,13 +1547,14 @@ static ino_t ffs_nodealloccg(ip, cg, ipref, mode) struct inode *ip; int cg; - ufs_daddr_t ipref; + ufs2_daddr_t ipref; int mode; { struct fs *fs; struct cg *cgp; - struct buf *bp; + struct buf *bp, *ibp; u_int8_t *inosused; + struct ufs2_dinode *dp2; int error, start, len, loc, map, i; fs = ip->i_fs; @@ -1368,7 +1572,7 @@ ffs_nodealloccg(ip, cg, ipref, mode) return (0); } bp->b_xflags |= BX_BKGRDWRITE; - cgp->cg_time = time_second; + cgp->cg_old_time = cgp->cg_time = time_second; inosused = cg_inosused(cgp); if (ipref) { ipref %= fs->fs_ipg; @@ -1414,6 +1618,24 @@ gotit: fs->fs_cstotal.cs_ndir++; fs->fs_cs(fs, cg).cs_ndir++; } + /* + * Check to see if we need to initialize more inodes. + */ + if (fs->fs_magic == FS_UFS2_MAGIC && + ipref + INOPB(fs) > cgp->cg_initediblk && + cgp->cg_initediblk < cgp->cg_niblk) { + ibp = getblk(ip->i_devvp, fsbtodb(fs, + ino_to_fsba(fs, cg * fs->fs_ipg + cgp->cg_initediblk)), + (int)fs->fs_bsize, 0, 0); + bzero(ibp->b_data, (int)fs->fs_bsize); + dp2 = (struct ufs2_dinode *)(ibp->b_data); + for (i = 0; i < INOPB(fs); i++) { + dp2->di_gen = random() / 2 + 1; + dp2++; + } + bawrite(ibp); + cgp->cg_initediblk += INOPB(fs); + } if (fs->fs_active != 0) atomic_clear_int(&ACTIVECGNUM(fs, cg), ACTIVECGOFF(cg)); bdwrite(bp); @@ -1431,13 +1653,14 @@ void ffs_blkfree(fs, devvp, bno, size, inum) struct fs *fs; struct vnode *devvp; - ufs_daddr_t bno; + ufs2_daddr_t bno; long size; ino_t inum; { struct cg *cgp; struct buf *bp; - ufs_daddr_t fragno, cgbno; + ufs1_daddr_t fragno, cgbno; + ufs2_daddr_t cgblkno; int i, error, cg, blk, frags, bbase; u_int8_t *blksfree; dev_t dev; @@ -1446,11 +1669,11 @@ ffs_blkfree(fs, devvp, bno, size, inum) if (devvp->v_type != VCHR) { /* devvp is a snapshot */ dev = VTOI(devvp)->i_devvp->v_rdev; - cgbno = fragstoblks(fs, cgtod(fs, cg)); + cgblkno = fragstoblks(fs, cgtod(fs, cg)); } else { /* devvp is a normal disk device */ dev = devvp->v_rdev; - cgbno = fsbtodb(fs, cgtod(fs, cg)); + cgblkno = fsbtodb(fs, cgtod(fs, cg)); if ((devvp->v_flag & VCOPYONWRITE) && ffs_snapblkfree(fs, devvp, bno, size, inum)) return; @@ -1462,18 +1685,19 @@ ffs_blkfree(fs, devvp, bno, size, inum) panic("ffs_blkfree: deallocation on suspended filesystem"); if ((u_int)size > fs->fs_bsize || fragoff(fs, size) != 0 || fragnum(fs, bno) + numfrags(fs, size) > fs->fs_frag) { - printf("dev=%s, bno = %ld, bsize = %ld, size = %ld, fs = %s\n", - devtoname(dev), (long)bno, (long)fs->fs_bsize, + printf("dev=%s, bno = %lld, bsize = %ld, size = %ld, fs = %s\n", + devtoname(dev), (intmax_t)bno, (long)fs->fs_bsize, size, fs->fs_fsmnt); panic("ffs_blkfree: bad size"); } #endif if ((u_int)bno >= fs->fs_size) { - printf("bad block %ld, ino %lu\n", (long)bno, (u_long)inum); + printf("bad block %lld, ino %lu\n", (intmax_t)bno, + (u_long)inum); ffs_fserr(fs, inum, "bad block"); return; } - if ((error = bread(devvp, cgbno, (int)fs->fs_cgsize, NOCRED, &bp))) { + if ((error = bread(devvp, cgblkno, (int)fs->fs_cgsize, NOCRED, &bp))) { brelse(bp); return; } @@ -1483,7 +1707,7 @@ ffs_blkfree(fs, devvp, bno, size, inum) return; } bp->b_xflags |= BX_BKGRDWRITE; - cgp->cg_time = time_second; + cgp->cg_old_time = cgp->cg_time = time_second; cgbno = dtogd(fs, bno); blksfree = cg_blksfree(cgp); if (size == fs->fs_bsize) { @@ -1494,8 +1718,8 @@ ffs_blkfree(fs, devvp, bno, size, inum) brelse(bp); return; } - printf("dev = %s, block = %ld, fs = %s\n", - devtoname(dev), (long)bno, fs->fs_fsmnt); + printf("dev = %s, block = %lld, fs = %s\n", + devtoname(dev), (intmax_t)bno, fs->fs_fsmnt); panic("ffs_blkfree: freeing free block"); } ffs_setblock(fs, blksfree, fragno); @@ -1503,9 +1727,6 @@ ffs_blkfree(fs, devvp, bno, size, inum) cgp->cg_cs.cs_nbfree++; fs->fs_cstotal.cs_nbfree++; fs->fs_cs(fs, cg).cs_nbfree++; - i = cbtocylno(fs, cgbno); - cg_blks(fs, cgp, i)[cbtorpos(fs, cgbno)]++; - cg_blktot(cgp)[i]++; } else { bbase = cgbno - fragnum(fs, cgbno); /* @@ -1519,8 +1740,8 @@ ffs_blkfree(fs, devvp, bno, size, inum) frags = numfrags(fs, size); for (i = 0; i < frags; i++) { if (isset(blksfree, cgbno + i)) { - printf("dev = %s, block = %ld, fs = %s\n", - devtoname(dev), (long)(bno + i), + printf("dev = %s, block = %lld, fs = %s\n", + devtoname(dev), (intmax_t)(bno + i), fs->fs_fsmnt); panic("ffs_blkfree: freeing free frag"); } @@ -1546,9 +1767,6 @@ ffs_blkfree(fs, devvp, bno, size, inum) cgp->cg_cs.cs_nbfree++; fs->fs_cstotal.cs_nbfree++; fs->fs_cs(fs, cg).cs_nbfree++; - i = cbtocylno(fs, bbase); - cg_blks(fs, cgp, i)[cbtorpos(fs, bbase)]++; - cg_blktot(cgp)[i]++; } } fs->fs_fmod = 1; @@ -1565,12 +1783,13 @@ ffs_blkfree(fs, devvp, bno, size, inum) static int ffs_checkblk(ip, bno, size) struct inode *ip; - ufs_daddr_t bno; + ufs2_daddr_t bno; long size; { struct fs *fs; struct cg *cgp; struct buf *bp; + ufs1_daddr_t cgbno; int i, error, frags, free; u_int8_t *blksfree; @@ -1581,7 +1800,7 @@ ffs_checkblk(ip, bno, size) panic("ffs_checkblk: bad size"); } if ((u_int)bno >= fs->fs_size) - panic("ffs_checkblk: bad block %d", bno); + panic("ffs_checkblk: bad block %lld", (intmax_t)bno); error = bread(ip->i_devvp, fsbtodb(fs, cgtod(fs, dtog(fs, bno))), (int)fs->fs_cgsize, NOCRED, &bp); if (error) @@ -1591,13 +1810,13 @@ ffs_checkblk(ip, bno, size) panic("ffs_checkblk: cg magic mismatch"); bp->b_xflags |= BX_BKGRDWRITE; blksfree = cg_blksfree(cgp); - bno = dtogd(fs, bno); + cgbno = dtogd(fs, bno); if (size == fs->fs_bsize) { - free = ffs_isblock(fs, blksfree, fragstoblks(fs, bno)); + free = ffs_isblock(fs, blksfree, fragstoblks(fs, cgbno)); } else { frags = numfrags(fs, size); for (free = 0, i = 0; i < frags; i++) - if (isset(blksfree, bno + i)) + if (isset(blksfree, cgbno + i)) free++; if (free != 0 && free != frags) panic("ffs_checkblk: partially free fragment"); @@ -1636,7 +1855,8 @@ ffs_freefile(fs, devvp, ino, mode) { struct cg *cgp; struct buf *bp; - int error, cgbno, cg; + ufs2_daddr_t cgbno; + int error, cg; u_int8_t *inosused; dev_t dev; @@ -1663,7 +1883,7 @@ ffs_freefile(fs, devvp, ino, mode) return (0); } bp->b_xflags |= BX_BKGRDWRITE; - cgp->cg_time = time_second; + cgp->cg_old_time = cgp->cg_time = time_second; inosused = cg_inosused(cgp); ino %= fs->fs_ipg; if (isclr(inosused, ino)) { @@ -1696,14 +1916,14 @@ ffs_freefile(fs, devvp, ino, mode) * It is a panic if a request is made to find a block if none are * available. */ -static ufs_daddr_t +static ufs1_daddr_t ffs_mapsearch(fs, cgp, bpref, allocsiz) struct fs *fs; struct cg *cgp; - ufs_daddr_t bpref; + ufs2_daddr_t bpref; int allocsiz; { - ufs_daddr_t bno; + ufs1_daddr_t bno; int start, len, loc, i; int blk, field, subfield, pos; u_int8_t *blksfree; @@ -1766,7 +1986,7 @@ void ffs_clusteracct(fs, cgp, blkno, cnt) struct fs *fs; struct cg *cgp; - ufs_daddr_t blkno; + ufs1_daddr_t blkno; int cnt; { int32_t *sump; @@ -1925,7 +2145,7 @@ sysctl_ffs_fsck(SYSCTL_HANDLER_ARGS) struct inode *ip; struct mount *mp; struct fs *fs; - ufs_daddr_t blkno; + ufs2_daddr_t blkno; long blkcnt, blksize; struct file *fp; int filetype, error; @@ -1979,6 +2199,7 @@ sysctl_ffs_fsck(SYSCTL_HANDLER_ARGS) break; ip = VTOI(vp); ip->i_nlink += cmd.size; + DIP(ip, i_nlink) = ip->i_nlink; ip->i_effnlink += cmd.size; ip->i_flag |= IN_CHANGE; if (DOINGSOFTDEP(vp)) @@ -1997,7 +2218,7 @@ sysctl_ffs_fsck(SYSCTL_HANDLER_ARGS) if ((error = VFS_VGET(mp, (ino_t)cmd.value, LK_EXCLUSIVE, &vp))) break; ip = VTOI(vp); - ip->i_blocks += cmd.size; + DIP(ip, i_blocks) += cmd.size; ip->i_flag |= IN_CHANGE; vput(vp); break; @@ -2035,17 +2256,17 @@ sysctl_ffs_fsck(SYSCTL_HANDLER_ARGS) #ifdef DEBUG if (fsckcmds) { if (cmd.size == 1) - printf("%s: free block %d\n", + printf("%s: free block %lld\n", mp->mnt_stat.f_mntonname, - (ufs_daddr_t)cmd.value); + (intmax_t)cmd.value); else - printf("%s: free blocks %d-%ld\n", + printf("%s: free blocks %lld-%lld\n", mp->mnt_stat.f_mntonname, - (ufs_daddr_t)cmd.value, - (ufs_daddr_t)cmd.value + cmd.size - 1); + (intmax_t)cmd.value, + (intmax_t)cmd.value + cmd.size - 1); } #endif /* DEBUG */ - blkno = (ufs_daddr_t)cmd.value; + blkno = cmd.value; blkcnt = cmd.size; blksize = fs->fs_frag - (blkno % fs->fs_frag); while (blkcnt > 0) { diff --git a/sys/ufs/ffs/ffs_balloc.c b/sys/ufs/ffs/ffs_balloc.c index b2e3595..6b00abd 100644 --- a/sys/ufs/ffs/ffs_balloc.c +++ b/sys/ufs/ffs/ffs_balloc.c @@ -1,4 +1,16 @@ /* + * Copyright (c) 2002 Networks Associates Technology, Inc. + * All rights reserved. + * + * This software was developed for the FreeBSD Project by Marshall + * Kirk McKusick and Network Associates Laboratories, the Security + * Research Division of Network Associates, Inc. under DARPA/SPAWAR + * contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS + * research program + * + * Copyright (c) 1982, 1989, 1993 + * The Regents of the University of California. All rights reserved. + * (c) UNIX System Laboratories, Inc. * Copyright (c) 1982, 1986, 1989, 1993 * The Regents of the University of California. All rights reserved. * @@ -53,60 +65,402 @@ * Balloc defines the structure of filesystem storage * by allocating the physical blocks on a device given * the inode and the logical block number in a file. + * This is the allocation strategy for UFS1. Below is + * the allocation strategy for UFS2. + */ +int +ffs_balloc_ufs1(struct vnode *vp, off_t startoffset, int size, + struct ucred *cred, int flags, struct buf **bpp) +{ + struct inode *ip; + ufs_lbn_t lbn, lastlbn; + struct fs *fs; + ufs1_daddr_t nb; + struct buf *bp, *nbp; + struct indir indirs[NIADDR + 2]; + int deallocated, osize, nsize, num, i, error; + ufs2_daddr_t newb; + ufs1_daddr_t *bap, pref; + ufs1_daddr_t *allocib, *blkp, *allocblk, allociblk[NIADDR + 1]; + int unwindidx = -1; + struct thread *td = curthread; /* XXX */ + + ip = VTOI(vp); + fs = ip->i_fs; + lbn = lblkno(fs, startoffset); + size = blkoff(fs, startoffset) + size; + if (size > fs->fs_bsize) + panic("ffs_balloc_ufs1: blk too big"); + *bpp = NULL; + if (lbn < 0) + return (EFBIG); + + /* + * If the next write will extend the file into a new block, + * and the file is currently composed of a fragment + * this fragment has to be extended to be a full block. + */ + lastlbn = lblkno(fs, ip->i_size); + if (lastlbn < NDADDR && lastlbn < lbn) { + nb = lastlbn; + osize = blksize(fs, ip, nb); + if (osize < fs->fs_bsize && osize > 0) { + error = ffs_realloccg(ip, nb, + ffs_blkpref_ufs1(ip, lastlbn, (int)nb, + &ip->i_din1->di_db[0]), + osize, (int)fs->fs_bsize, cred, &bp); + if (error) + return (error); + if (DOINGSOFTDEP(vp)) + softdep_setup_allocdirect(ip, nb, + dbtofsb(fs, bp->b_blkno), + ip->i_din1->di_db[nb], + fs->fs_bsize, osize, bp); + ip->i_size = smalllblktosize(fs, nb + 1); + ip->i_din1->di_size = ip->i_size; + ip->i_din1->di_db[nb] = dbtofsb(fs, bp->b_blkno); + ip->i_flag |= IN_CHANGE | IN_UPDATE; + if (flags & B_SYNC) + bwrite(bp); + else + bawrite(bp); + } + } + /* + * The first NDADDR blocks are direct blocks + */ + if (lbn < NDADDR) { + if (flags & B_METAONLY) + panic("ffs_balloc_ufs1: B_METAONLY for direct block"); + nb = ip->i_din1->di_db[lbn]; + if (nb != 0 && ip->i_size >= smalllblktosize(fs, lbn + 1)) { + error = bread(vp, lbn, fs->fs_bsize, NOCRED, &bp); + if (error) { + brelse(bp); + return (error); + } + bp->b_blkno = fsbtodb(fs, nb); + *bpp = bp; + return (0); + } + if (nb != 0) { + /* + * Consider need to reallocate a fragment. + */ + osize = fragroundup(fs, blkoff(fs, ip->i_size)); + nsize = fragroundup(fs, size); + if (nsize <= osize) { + error = bread(vp, lbn, osize, NOCRED, &bp); + if (error) { + brelse(bp); + return (error); + } + bp->b_blkno = fsbtodb(fs, nb); + } else { + error = ffs_realloccg(ip, lbn, + ffs_blkpref_ufs1(ip, lbn, (int)lbn, + &ip->i_din1->di_db[0]), + osize, nsize, cred, &bp); + if (error) + return (error); + if (DOINGSOFTDEP(vp)) + softdep_setup_allocdirect(ip, lbn, + dbtofsb(fs, bp->b_blkno), nb, + nsize, osize, bp); + } + } else { + if (ip->i_size < smalllblktosize(fs, lbn + 1)) + nsize = fragroundup(fs, size); + else + nsize = fs->fs_bsize; + error = ffs_alloc(ip, lbn, + ffs_blkpref_ufs1(ip, lbn, (int)lbn, + &ip->i_din1->di_db[0]), + nsize, cred, &newb); + if (error) + return (error); + bp = getblk(vp, lbn, nsize, 0, 0); + bp->b_blkno = fsbtodb(fs, newb); + if (flags & B_CLRBUF) + vfs_bio_clrbuf(bp); + if (DOINGSOFTDEP(vp)) + softdep_setup_allocdirect(ip, lbn, newb, 0, + nsize, 0, bp); + } + ip->i_din1->di_db[lbn] = dbtofsb(fs, bp->b_blkno); + ip->i_flag |= IN_CHANGE | IN_UPDATE; + *bpp = bp; + return (0); + } + /* + * Determine the number of levels of indirection. + */ + pref = 0; + if ((error = ufs_getlbns(vp, lbn, indirs, &num)) != 0) + return(error); +#ifdef DIAGNOSTIC + if (num < 1) + panic ("ffs_balloc_ufs1: ufs_getlbns returned indirect block"); +#endif + /* + * Fetch the first indirect block allocating if necessary. + */ + --num; + nb = ip->i_din1->di_ib[indirs[0].in_off]; + allocib = NULL; + allocblk = allociblk; + if (nb == 0) { + pref = ffs_blkpref_ufs1(ip, lbn, 0, (ufs1_daddr_t *)0); + if ((error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, + cred, &newb)) != 0) + return (error); + nb = newb; + *allocblk++ = nb; + bp = getblk(vp, indirs[1].in_lbn, fs->fs_bsize, 0, 0); + bp->b_blkno = fsbtodb(fs, nb); + vfs_bio_clrbuf(bp); + if (DOINGSOFTDEP(vp)) { + softdep_setup_allocdirect(ip, NDADDR + indirs[0].in_off, + newb, 0, fs->fs_bsize, 0, bp); + bdwrite(bp); + } else { + /* + * Write synchronously so that indirect blocks + * never point at garbage. + */ + if (DOINGASYNC(vp)) + bdwrite(bp); + else if ((error = bwrite(bp)) != 0) + goto fail; + } + allocib = &ip->i_din1->di_ib[indirs[0].in_off]; + *allocib = nb; + ip->i_flag |= IN_CHANGE | IN_UPDATE; + } + /* + * Fetch through the indirect blocks, allocating as necessary. + */ + for (i = 1;;) { + error = bread(vp, + indirs[i].in_lbn, (int)fs->fs_bsize, NOCRED, &bp); + if (error) { + brelse(bp); + goto fail; + } + bap = (ufs1_daddr_t *)bp->b_data; + nb = bap[indirs[i].in_off]; + if (i == num) + break; + i += 1; + if (nb != 0) { + bqrelse(bp); + continue; + } + if (pref == 0) + pref = ffs_blkpref_ufs1(ip, lbn, 0, (ufs1_daddr_t *)0); + if ((error = + ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, cred, &newb)) != 0) { + brelse(bp); + goto fail; + } + nb = newb; + *allocblk++ = nb; + nbp = getblk(vp, indirs[i].in_lbn, fs->fs_bsize, 0, 0); + nbp->b_blkno = fsbtodb(fs, nb); + vfs_bio_clrbuf(nbp); + if (DOINGSOFTDEP(vp)) { + softdep_setup_allocindir_meta(nbp, ip, bp, + indirs[i - 1].in_off, nb); + bdwrite(nbp); + } else { + /* + * Write synchronously so that indirect blocks + * never point at garbage. + */ + if ((error = bwrite(nbp)) != 0) { + brelse(bp); + goto fail; + } + } + bap[indirs[i - 1].in_off] = nb; + if (allocib == NULL && unwindidx < 0) + unwindidx = i - 1; + /* + * If required, write synchronously, otherwise use + * delayed write. + */ + if (flags & B_SYNC) { + bwrite(bp); + } else { + if (bp->b_bufsize == fs->fs_bsize) + bp->b_flags |= B_CLUSTEROK; + bdwrite(bp); + } + } + /* + * If asked only for the indirect block, then return it. + */ + if (flags & B_METAONLY) { + *bpp = bp; + return (0); + } + /* + * Get the data block, allocating if necessary. + */ + if (nb == 0) { + pref = ffs_blkpref_ufs1(ip, lbn, indirs[i].in_off, &bap[0]); + error = ffs_alloc(ip, + lbn, pref, (int)fs->fs_bsize, cred, &newb); + if (error) { + brelse(bp); + goto fail; + } + nb = newb; + *allocblk++ = nb; + nbp = getblk(vp, lbn, fs->fs_bsize, 0, 0); + nbp->b_blkno = fsbtodb(fs, nb); + if (flags & B_CLRBUF) + vfs_bio_clrbuf(nbp); + if (DOINGSOFTDEP(vp)) + softdep_setup_allocindir_page(ip, lbn, bp, + indirs[i].in_off, nb, 0, nbp); + bap[indirs[i].in_off] = nb; + /* + * If required, write synchronously, otherwise use + * delayed write. + */ + if (flags & B_SYNC) { + bwrite(bp); + } else { + if (bp->b_bufsize == fs->fs_bsize) + bp->b_flags |= B_CLUSTEROK; + bdwrite(bp); + } + *bpp = nbp; + return (0); + } + brelse(bp); + if (flags & B_CLRBUF) { + error = bread(vp, lbn, (int)fs->fs_bsize, NOCRED, &nbp); + if (error) { + brelse(nbp); + goto fail; + } + } else { + nbp = getblk(vp, lbn, fs->fs_bsize, 0, 0); + nbp->b_blkno = fsbtodb(fs, nb); + } + *bpp = nbp; + return (0); +fail: + /* + * If we have failed part way through block allocation, we + * have to deallocate any indirect blocks that we have allocated. + * We have to fsync the file before we start to get rid of all + * of its dependencies so that we do not leave them dangling. + * We have to sync it at the end so that the soft updates code + * does not find any untracked changes. Although this is really + * slow, running out of disk space is not expected to be a common + * occurence. The error return from fsync is ignored as we already + * have an error to return to the user. + */ + (void) VOP_FSYNC(vp, cred, MNT_WAIT, td); + for (deallocated = 0, blkp = allociblk; blkp < allocblk; blkp++) { + ffs_blkfree(fs, ip->i_devvp, *blkp, fs->fs_bsize, ip->i_number); + deallocated += fs->fs_bsize; + } + if (allocib != NULL) { + *allocib = 0; + } else if (unwindidx >= 0) { + int r; + + r = bread(vp, indirs[unwindidx].in_lbn, + (int)fs->fs_bsize, NOCRED, &bp); + if (r) { + panic("Could not unwind indirect block, error %d", r); + brelse(bp); + } else { + bap = (ufs1_daddr_t *)bp->b_data; + bap[indirs[unwindidx].in_off] = 0; + if (flags & B_SYNC) { + bwrite(bp); + } else { + if (bp->b_bufsize == fs->fs_bsize) + bp->b_flags |= B_CLUSTEROK; + bdwrite(bp); + } + } + } + if (deallocated) { +#ifdef QUOTA + /* + * Restore user's disk quota because allocation failed. + */ + (void) chkdq(ip, -btodb(deallocated), cred, FORCE); +#endif + ip->i_din1->di_blocks -= btodb(deallocated); + ip->i_flag |= IN_CHANGE | IN_UPDATE; + } + (void) VOP_FSYNC(vp, cred, MNT_WAIT, td); + return (error); +} + +/* + * Balloc defines the structure of file system storage + * by allocating the physical blocks on a device given + * the inode and the logical block number in a file. + * This is the allocation strategy for UFS2. Above is + * the allocation strategy for UFS1. */ int -ffs_balloc(struct vnode *a_vp, off_t a_startoffset, int a_size, - struct ucred *a_cred, int a_flags, struct buf **a_bpp) +ffs_balloc_ufs2(struct vnode *vp, off_t startoffset, int size, + struct ucred *cred, int flags, struct buf **bpp) { struct inode *ip; - ufs_daddr_t lbn; - int size; - struct ucred *cred; - int flags; + ufs_lbn_t lbn, lastlbn; struct fs *fs; - ufs_daddr_t nb; struct buf *bp, *nbp; - struct vnode *vp; struct indir indirs[NIADDR + 2]; - ufs_daddr_t newb, *bap, pref; + ufs2_daddr_t nb, newb, *bap, pref; + ufs2_daddr_t *allocib, *blkp, *allocblk, allociblk[NIADDR + 1]; int deallocated, osize, nsize, num, i, error; - ufs_daddr_t *allocib, *blkp, *allocblk, allociblk[NIADDR + 1]; int unwindidx = -1; struct thread *td = curthread; /* XXX */ - vp = a_vp; ip = VTOI(vp); fs = ip->i_fs; - lbn = lblkno(fs, a_startoffset); - size = blkoff(fs, a_startoffset) + a_size; + lbn = lblkno(fs, startoffset); + size = blkoff(fs, startoffset) + size; if (size > fs->fs_bsize) - panic("ffs_balloc: blk too big"); - *a_bpp = NULL; + panic("ffs_balloc_ufs2: blk too big"); + *bpp = NULL; if (lbn < 0) return (EFBIG); - cred = a_cred; - flags = a_flags; /* * If the next write will extend the file into a new block, * and the file is currently composed of a fragment * this fragment has to be extended to be a full block. */ - nb = lblkno(fs, ip->i_size); - if (nb < NDADDR && nb < lbn) { + lastlbn = lblkno(fs, ip->i_size); + if (lastlbn < NDADDR && lastlbn < lbn) { + nb = lastlbn; osize = blksize(fs, ip, nb); if (osize < fs->fs_bsize && osize > 0) { error = ffs_realloccg(ip, nb, - ffs_blkpref(ip, nb, (int)nb, &ip->i_db[0]), + ffs_blkpref_ufs2(ip, lastlbn, (int)nb, + &ip->i_din2->di_db[0]), osize, (int)fs->fs_bsize, cred, &bp); if (error) return (error); if (DOINGSOFTDEP(vp)) softdep_setup_allocdirect(ip, nb, - dbtofsb(fs, bp->b_blkno), ip->i_db[nb], + dbtofsb(fs, bp->b_blkno), + ip->i_din2->di_db[nb], fs->fs_bsize, osize, bp); ip->i_size = smalllblktosize(fs, nb + 1); - ip->i_db[nb] = dbtofsb(fs, bp->b_blkno); + ip->i_din2->di_size = ip->i_size; + ip->i_din2->di_db[nb] = dbtofsb(fs, bp->b_blkno); ip->i_flag |= IN_CHANGE | IN_UPDATE; if (flags & B_SYNC) bwrite(bp); @@ -119,8 +473,8 @@ ffs_balloc(struct vnode *a_vp, off_t a_startoffset, int a_size, */ if (lbn < NDADDR) { if (flags & B_METAONLY) - panic("ffs_balloc: B_METAONLY for direct block"); - nb = ip->i_db[lbn]; + panic("ffs_balloc_ufs2: B_METAONLY for direct block"); + nb = ip->i_din2->di_db[lbn]; if (nb != 0 && ip->i_size >= smalllblktosize(fs, lbn + 1)) { error = bread(vp, lbn, fs->fs_bsize, NOCRED, &bp); if (error) { @@ -128,7 +482,7 @@ ffs_balloc(struct vnode *a_vp, off_t a_startoffset, int a_size, return (error); } bp->b_blkno = fsbtodb(fs, nb); - *a_bpp = bp; + *bpp = bp; return (0); } if (nb != 0) { @@ -146,8 +500,9 @@ ffs_balloc(struct vnode *a_vp, off_t a_startoffset, int a_size, bp->b_blkno = fsbtodb(fs, nb); } else { error = ffs_realloccg(ip, lbn, - ffs_blkpref(ip, lbn, (int)lbn, - &ip->i_db[0]), osize, nsize, cred, &bp); + ffs_blkpref_ufs2(ip, lbn, (int)lbn, + &ip->i_din2->di_db[0]), + osize, nsize, cred, &bp); if (error) return (error); if (DOINGSOFTDEP(vp)) @@ -161,7 +516,8 @@ ffs_balloc(struct vnode *a_vp, off_t a_startoffset, int a_size, else nsize = fs->fs_bsize; error = ffs_alloc(ip, lbn, - ffs_blkpref(ip, lbn, (int)lbn, &ip->i_db[0]), + ffs_blkpref_ufs2(ip, lbn, (int)lbn, + &ip->i_din2->di_db[0]), nsize, cred, &newb); if (error) return (error); @@ -173,9 +529,9 @@ ffs_balloc(struct vnode *a_vp, off_t a_startoffset, int a_size, softdep_setup_allocdirect(ip, lbn, newb, 0, nsize, 0, bp); } - ip->i_db[lbn] = dbtofsb(fs, bp->b_blkno); + ip->i_din2->di_db[lbn] = dbtofsb(fs, bp->b_blkno); ip->i_flag |= IN_CHANGE | IN_UPDATE; - *a_bpp = bp; + *bpp = bp; return (0); } /* @@ -186,17 +542,17 @@ ffs_balloc(struct vnode *a_vp, off_t a_startoffset, int a_size, return(error); #ifdef DIAGNOSTIC if (num < 1) - panic ("ffs_balloc: ufs_bmaparray returned indirect block"); + panic ("ffs_balloc_ufs2: ufs_getlbns returned indirect block"); #endif /* * Fetch the first indirect block allocating if necessary. */ --num; - nb = ip->i_ib[indirs[0].in_off]; + nb = ip->i_din2->di_ib[indirs[0].in_off]; allocib = NULL; allocblk = allociblk; if (nb == 0) { - pref = ffs_blkpref(ip, lbn, 0, (ufs_daddr_t *)0); + pref = ffs_blkpref_ufs2(ip, lbn, 0, (ufs2_daddr_t *)0); if ((error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, cred, &newb)) != 0) return (error); @@ -219,7 +575,7 @@ ffs_balloc(struct vnode *a_vp, off_t a_startoffset, int a_size, else if ((error = bwrite(bp)) != 0) goto fail; } - allocib = &ip->i_ib[indirs[0].in_off]; + allocib = &ip->i_din2->di_ib[indirs[0].in_off]; *allocib = nb; ip->i_flag |= IN_CHANGE | IN_UPDATE; } @@ -233,7 +589,7 @@ ffs_balloc(struct vnode *a_vp, off_t a_startoffset, int a_size, brelse(bp); goto fail; } - bap = (ufs_daddr_t *)bp->b_data; + bap = (ufs2_daddr_t *)bp->b_data; nb = bap[indirs[i].in_off]; if (i == num) break; @@ -243,7 +599,7 @@ ffs_balloc(struct vnode *a_vp, off_t a_startoffset, int a_size, continue; } if (pref == 0) - pref = ffs_blkpref(ip, lbn, 0, (ufs_daddr_t *)0); + pref = ffs_blkpref_ufs2(ip, lbn, 0, (ufs2_daddr_t *)0); if ((error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, cred, &newb)) != 0) { brelse(bp); @@ -287,14 +643,14 @@ ffs_balloc(struct vnode *a_vp, off_t a_startoffset, int a_size, * If asked only for the indirect block, then return it. */ if (flags & B_METAONLY) { - *a_bpp = bp; + *bpp = bp; return (0); } /* * Get the data block, allocating if necessary. */ if (nb == 0) { - pref = ffs_blkpref(ip, lbn, indirs[i].in_off, &bap[0]); + pref = ffs_blkpref_ufs2(ip, lbn, indirs[i].in_off, &bap[0]); error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, cred, &newb); if (error) { @@ -322,7 +678,7 @@ ffs_balloc(struct vnode *a_vp, off_t a_startoffset, int a_size, bp->b_flags |= B_CLUSTEROK; bdwrite(bp); } - *a_bpp = nbp; + *bpp = nbp; return (0); } brelse(bp); @@ -336,7 +692,7 @@ ffs_balloc(struct vnode *a_vp, off_t a_startoffset, int a_size, nbp = getblk(vp, lbn, fs->fs_bsize, 0, 0); nbp->b_blkno = fsbtodb(fs, nb); } - *a_bpp = nbp; + *bpp = nbp; return (0); fail: /* @@ -366,7 +722,7 @@ fail: panic("Could not unwind indirect block, error %d", r); brelse(bp); } else { - bap = (ufs_daddr_t *)bp->b_data; + bap = (ufs2_daddr_t *)bp->b_data; bap[indirs[unwindidx].in_off] = 0; if (flags & B_SYNC) { bwrite(bp); @@ -382,9 +738,9 @@ fail: /* * Restore user's disk quota because allocation failed. */ - (void) chkdq(ip, (long)-btodb(deallocated), cred, FORCE); + (void) chkdq(ip, -btodb(deallocated), cred, FORCE); #endif - ip->i_blocks -= btodb(deallocated); + ip->i_din2->di_blocks -= btodb(deallocated); ip->i_flag |= IN_CHANGE | IN_UPDATE; } (void) VOP_FSYNC(vp, cred, MNT_WAIT, td); diff --git a/sys/ufs/ffs/ffs_extern.h b/sys/ufs/ffs/ffs_extern.h index bbb12ab..8274765 100644 --- a/sys/ufs/ffs/ffs_extern.h +++ b/sys/ufs/ffs/ffs_extern.h @@ -49,26 +49,30 @@ struct sockaddr; struct statfs; struct ucred; struct vnode; -struct vop_balloc_args; struct vop_fsync_args; struct vop_reallocblks_args; struct vop_copyonwrite_args; int ffs_alloc(struct inode *, - ufs_daddr_t, ufs_daddr_t, int, struct ucred *, ufs_daddr_t *); -int ffs_balloc(struct vnode *a_vp, off_t a_startoffset, int a_size, + ufs2_daddr_t, ufs2_daddr_t, int, struct ucred *, ufs2_daddr_t *); +int ffs_balloc_ufs1(struct vnode *a_vp, off_t a_startoffset, int a_size, + struct ucred *a_cred, int a_flags, struct buf **a_bpp); +int ffs_balloc_ufs2(struct vnode *a_vp, off_t a_startoffset, int a_size, struct ucred *a_cred, int a_flags, struct buf **a_bpp); int ffs_blkatoff(struct vnode *, off_t, char **, struct buf **); -void ffs_blkfree(struct fs *, struct vnode *, ufs_daddr_t, long, ino_t); -ufs_daddr_t ffs_blkpref(struct inode *, ufs_daddr_t, int, ufs_daddr_t *); -void ffs_clrblock(struct fs *, u_char *, ufs_daddr_t); -void ffs_clusteracct (struct fs *, struct cg *, ufs_daddr_t, int); +void ffs_blkfree(struct fs *, struct vnode *, ufs2_daddr_t, long, ino_t); +ufs2_daddr_t ffs_blkpref_ufs1(struct inode *, ufs_lbn_t, int, ufs1_daddr_t *); +ufs2_daddr_t ffs_blkpref_ufs2(struct inode *, ufs_lbn_t, int, ufs2_daddr_t *); +void ffs_clrblock(struct fs *, u_char *, ufs1_daddr_t); +void ffs_clusteracct (struct fs *, struct cg *, ufs1_daddr_t, int); int ffs_fhtovp(struct mount *, struct fid *, struct vnode **); int ffs_flushfiles(struct mount *, int, struct thread *); void ffs_fragacct(struct fs *, int, int32_t [], int); int ffs_freefile(struct fs *, struct vnode *, ino_t, int ); -int ffs_isblock(struct fs *, u_char *, ufs_daddr_t); -int ffs_isfreeblock(struct fs *, unsigned char *, ufs_daddr_t); +int ffs_isblock(struct fs *, u_char *, ufs1_daddr_t); +int ffs_isfreeblock(struct fs *, unsigned char *, ufs1_daddr_t); +void ffs_load_inode(struct buf *, struct inode *, struct malloc_type *, + struct fs *, ino_t); int ffs_mountfs(struct vnode *, struct mount *, struct thread *, struct malloc_type *); int ffs_mountroot(void); @@ -76,9 +80,9 @@ int ffs_mount(struct mount *, char *, caddr_t, struct nameidata *, struct thread *); int ffs_reallocblks(struct vop_reallocblks_args *); int ffs_realloccg(struct inode *, - ufs_daddr_t, ufs_daddr_t, int, int, struct ucred *, struct buf **); -void ffs_setblock(struct fs *, u_char *, ufs_daddr_t); -int ffs_snapblkfree(struct fs *, struct vnode *, ufs_daddr_t, long, ino_t); + ufs2_daddr_t, ufs2_daddr_t, int, int, struct ucred *, struct buf **); +void ffs_setblock(struct fs *, u_char *, ufs1_daddr_t); +int ffs_snapblkfree(struct fs *, struct vnode *, ufs2_daddr_t, long, ino_t); void ffs_snapremove(struct vnode *vp); int ffs_snapshot(struct mount *mp, char *snapfile); void ffs_snapshot_mount(struct mount *mp); @@ -112,13 +116,13 @@ void softdep_freefile(struct vnode *, ino_t, int); int softdep_request_cleanup(struct fs *, struct vnode *); void softdep_setup_freeblocks(struct inode *, off_t); void softdep_setup_inomapdep(struct buf *, struct inode *, ino_t); -void softdep_setup_blkmapdep(struct buf *, struct fs *, ufs_daddr_t); -void softdep_setup_allocdirect(struct inode *, ufs_lbn_t, ufs_daddr_t, - ufs_daddr_t, long, long, struct buf *); +void softdep_setup_blkmapdep(struct buf *, struct fs *, ufs2_daddr_t); +void softdep_setup_allocdirect(struct inode *, ufs_lbn_t, ufs2_daddr_t, + ufs2_daddr_t, long, long, struct buf *); void softdep_setup_allocindir_meta(struct buf *, struct inode *, - struct buf *, int, ufs_daddr_t); + struct buf *, int, ufs2_daddr_t); void softdep_setup_allocindir_page(struct inode *, ufs_lbn_t, - struct buf *, int, ufs_daddr_t, ufs_daddr_t, struct buf *); + struct buf *, int, ufs2_daddr_t, ufs2_daddr_t, struct buf *); void softdep_fsync_mountdev(struct vnode *); int softdep_sync_metadata(struct vop_fsync_args *); /* XXX incorrectly moved to mount.h - should be indirect function */ diff --git a/sys/ufs/ffs/ffs_inode.c b/sys/ufs/ffs/ffs_inode.c index 215cc85..fe9af1e 100644 --- a/sys/ufs/ffs/ffs_inode.c +++ b/sys/ufs/ffs/ffs_inode.c @@ -60,8 +60,8 @@ #include <ufs/ffs/fs.h> #include <ufs/ffs/ffs_extern.h> -static int ffs_indirtrunc(struct inode *, ufs_daddr_t, ufs_daddr_t, - ufs_daddr_t, int, long *); +static int ffs_indirtrunc(struct inode *, ufs2_daddr_t, ufs2_daddr_t, + ufs2_daddr_t, int, ufs2_daddr_t *); /* * Update the access, modified, and inode change times as specified by the @@ -94,9 +94,10 @@ ffs_update(vp, waitfor) * Ensure that uid and gid are correct. This is a temporary * fix until fsck has been changed to do the update. */ - if (fs->fs_inodefmt < FS_44INODEFMT) { /* XXX */ - ip->i_din.di_ouid = ip->i_uid; /* XXX */ - ip->i_din.di_ogid = ip->i_gid; /* XXX */ + if (fs->fs_magic == FS_UFS1_MAGIC && /* XXX */ + fs->fs_old_inodefmt < FS_44INODEFMT) { /* XXX */ + ip->i_din1->di_ouid = ip->i_uid; /* XXX */ + ip->i_din1->di_ogid = ip->i_gid; /* XXX */ } /* XXX */ error = bread(ip->i_devvp, fsbtodb(fs, ino_to_fsba(fs, ip->i_number)), (int)fs->fs_bsize, NOCRED, &bp); @@ -108,8 +109,12 @@ ffs_update(vp, waitfor) softdep_update_inodeblock(ip, bp, waitfor); else if (ip->i_effnlink != ip->i_nlink) panic("ffs_update: bad link cnt"); - *((struct dinode *)bp->b_data + - ino_to_fsbo(fs, ip->i_number)) = ip->i_din; + if (ip->i_ump->um_fstype == UFS1) + *((struct ufs1_dinode *)bp->b_data + + ino_to_fsbo(fs, ip->i_number)) = *ip->i_din1; + else + *((struct ufs2_dinode *)bp->b_data + + ino_to_fsbo(fs, ip->i_number)) = *ip->i_din2; if (waitfor && !DOINGASYNC(vp)) { return (bwrite(bp)); } else if (vm_page_count_severe() || buf_dirty_count_severe()) { @@ -138,16 +143,14 @@ ffs_truncate(vp, length, flags, cred, td) struct thread *td; { struct vnode *ovp = vp; - ufs_daddr_t lastblock; struct inode *oip; - ufs_daddr_t bn, lbn, lastiblock[NIADDR], indir_lbn[NIADDR]; - ufs_daddr_t oldblks[NDADDR + NIADDR], newblks[NDADDR + NIADDR]; + ufs2_daddr_t bn, lbn, lastblock, lastiblock[NIADDR], indir_lbn[NIADDR]; + ufs2_daddr_t oldblks[NDADDR + NIADDR], newblks[NDADDR + NIADDR]; + ufs2_daddr_t count, blocksreleased = 0; struct fs *fs; struct buf *bp; - int offset, size, level; - long count, nblocks, blocksreleased = 0; - int i; - int aflags, error, allerror; + int offset, size, level, nblocks; + int i, aflags, error, allerror; off_t osize; oip = VTOI(ovp); @@ -157,13 +160,15 @@ ffs_truncate(vp, length, flags, cred, td) if (length > fs->fs_maxfilesize) return (EFBIG); if (ovp->v_type == VLNK && - (oip->i_size < ovp->v_mount->mnt_maxsymlinklen || oip->i_din.di_blocks == 0)) { + (oip->i_size < ovp->v_mount->mnt_maxsymlinklen || + DIP(oip, i_blocks) == 0)) { #ifdef DIAGNOSTIC if (length != 0) panic("ffs_truncate: partial truncate of symlink"); #endif - bzero((char *)&oip->i_shortlink, (u_int)oip->i_size); + bzero(SHORTLINK(oip), (u_int)oip->i_size); oip->i_size = 0; + DIP(oip, i_size) = 0; oip->i_flag |= IN_CHANGE | IN_UPDATE; return (UFS_UPDATE(ovp, 1)); } @@ -196,10 +201,10 @@ ffs_truncate(vp, length, flags, cred, td) td)) != 0) return (error); if (oip->i_flag & IN_SPACECOUNTED) - fs->fs_pendingblocks -= oip->i_blocks; + fs->fs_pendingblocks -= DIP(oip, i_blocks); } else { #ifdef QUOTA - (void) chkdq(oip, -oip->i_blocks, NOCRED, 0); + (void) chkdq(oip, -DIP(oip, i_blocks), NOCRED, 0); #endif softdep_setup_freeblocks(oip, length); vinvalbuf(ovp, 0, cred, td, 0, 0); @@ -223,6 +228,7 @@ ffs_truncate(vp, length, flags, cred, td) if (error) return (error); oip->i_size = length; + DIP(oip, i_size) = length; if (bp->b_bufsize == fs->fs_bsize) bp->b_flags |= B_CLUSTEROK; if (aflags & B_SYNC) @@ -243,6 +249,7 @@ ffs_truncate(vp, length, flags, cred, td) offset = blkoff(fs, length); if (offset == 0) { oip->i_size = length; + DIP(oip, i_size) = length; } else { lbn = lblkno(fs, length); aflags = B_CLRBUF; @@ -265,6 +272,7 @@ ffs_truncate(vp, length, flags, cred, td) (error = VOP_FSYNC(ovp, cred, MNT_WAIT, td)) != 0) return (error); oip->i_size = length; + DIP(oip, i_size) = length; size = blksize(fs, oip, lbn); if (ovp->v_type != VDIR) bzero((char *)bp->b_data + offset, @@ -295,14 +303,18 @@ ffs_truncate(vp, length, flags, cred, td) * will be returned to the free list. lastiblock values are also * normalized to -1 for calls to ffs_indirtrunc below. */ - bcopy((caddr_t)&oip->i_db[0], (caddr_t)oldblks, sizeof oldblks); - for (level = TRIPLE; level >= SINGLE; level--) + for (level = TRIPLE; level >= SINGLE; level--) { + oldblks[NDADDR + level] = DIP(oip, i_ib[level]); if (lastiblock[level] < 0) { - oip->i_ib[level] = 0; + DIP(oip, i_ib[level]) = 0; lastiblock[level] = -1; } - for (i = NDADDR - 1; i > lastblock; i--) - oip->i_db[i] = 0; + } + for (i = 0; i < NDADDR; i++) { + oldblks[i] = DIP(oip, i_db[i]); + if (i > lastblock) + DIP(oip, i_db[i]) = 0; + } oip->i_flag |= IN_CHANGE | IN_UPDATE; allerror = UFS_UPDATE(ovp, 1); @@ -312,9 +324,16 @@ ffs_truncate(vp, length, flags, cred, td) * Note that we save the new block configuration so we can check it * when we are done. */ - bcopy((caddr_t)&oip->i_db[0], (caddr_t)newblks, sizeof newblks); - bcopy((caddr_t)oldblks, (caddr_t)&oip->i_db[0], sizeof oldblks); + for (i = 0; i < NDADDR; i++) { + newblks[i] = DIP(oip, i_db[i]); + DIP(oip, i_db[i]) = oldblks[i]; + } + for (i = 0; i < NIADDR; i++) { + newblks[NDADDR + i] = DIP(oip, i_ib[i]); + DIP(oip, i_ib[i]) = oldblks[NDADDR + i]; + } oip->i_size = osize; + DIP(oip, i_size) = osize; error = vtruncbuf(ovp, cred, td, length, fs->fs_bsize); if (error && (allerror == 0)) @@ -327,7 +346,7 @@ ffs_truncate(vp, length, flags, cred, td) indir_lbn[DOUBLE] = indir_lbn[SINGLE] - NINDIR(fs) - 1; indir_lbn[TRIPLE] = indir_lbn[DOUBLE] - NINDIR(fs) * NINDIR(fs) - 1; for (level = TRIPLE; level >= SINGLE; level--) { - bn = oip->i_ib[level]; + bn = DIP(oip, i_ib[level]); if (bn != 0) { error = ffs_indirtrunc(oip, indir_lbn[level], fsbtodb(fs, bn), lastiblock[level], level, &count); @@ -335,7 +354,7 @@ ffs_truncate(vp, length, flags, cred, td) allerror = error; blocksreleased += count; if (lastiblock[level] < 0) { - oip->i_ib[level] = 0; + DIP(oip, i_ib[level]) = 0; ffs_blkfree(fs, oip->i_devvp, bn, fs->fs_bsize, oip->i_number); blocksreleased += nblocks; @@ -351,10 +370,10 @@ ffs_truncate(vp, length, flags, cred, td) for (i = NDADDR - 1; i > lastblock; i--) { long bsize; - bn = oip->i_db[i]; + bn = DIP(oip, i_db[i]); if (bn == 0) continue; - oip->i_db[i] = 0; + DIP(oip, i_db[i]) = 0; bsize = blksize(fs, oip, i); ffs_blkfree(fs, oip->i_devvp, bn, bsize, oip->i_number); blocksreleased += btodb(bsize); @@ -366,7 +385,7 @@ ffs_truncate(vp, length, flags, cred, td) * Finally, look for a change in size of the * last direct block; release any frags. */ - bn = oip->i_db[lastblock]; + bn = DIP(oip, i_db[lastblock]); if (bn != 0) { long oldspace, newspace; @@ -376,6 +395,7 @@ ffs_truncate(vp, length, flags, cred, td) */ oldspace = blksize(fs, oip, lastblock); oip->i_size = length; + DIP(oip, i_size) = length; newspace = blksize(fs, oip, lastblock); if (newspace == 0) panic("ffs_truncate: newspace"); @@ -394,10 +414,10 @@ ffs_truncate(vp, length, flags, cred, td) done: #ifdef DIAGNOSTIC for (level = SINGLE; level <= TRIPLE; level++) - if (newblks[NDADDR + level] != oip->i_ib[level]) + if (newblks[NDADDR + level] != DIP(oip, i_ib[level])) panic("ffs_truncate1"); for (i = 0; i < NDADDR; i++) - if (newblks[i] != oip->i_db[i]) + if (newblks[i] != DIP(oip, i_db[i])) panic("ffs_truncate2"); if (length == 0 && (!TAILQ_EMPTY(&ovp->v_dirtyblkhd) || @@ -408,10 +428,11 @@ done: * Put back the real size. */ oip->i_size = length; - oip->i_blocks -= blocksreleased; + DIP(oip, i_size) = length; + DIP(oip, i_blocks) -= blocksreleased; - if (oip->i_blocks < 0) /* sanity */ - oip->i_blocks = 0; + if (DIP(oip, i_blocks) < 0) /* sanity */ + DIP(oip, i_blocks) = 0; oip->i_flag |= IN_CHANGE; #ifdef QUOTA (void) chkdq(oip, -blocksreleased, NOCRED, 0); @@ -425,26 +446,25 @@ done: * lastbn. If level is greater than SINGLE, the block is an indirect block * and recursive calls to indirtrunc must be used to cleanse other indirect * blocks. - * - * NB: triple indirect blocks are untested. */ static int ffs_indirtrunc(ip, lbn, dbn, lastbn, level, countp) struct inode *ip; - ufs_daddr_t lbn, lastbn; - ufs_daddr_t dbn; + ufs2_daddr_t lbn, lastbn; + ufs2_daddr_t dbn; int level; - long *countp; + ufs2_daddr_t *countp; { - int i; struct buf *bp; struct fs *fs = ip->i_fs; - ufs_daddr_t *bap; struct vnode *vp; - ufs_daddr_t *copy = NULL, nb, nlbn, last; - long blkcount, factor; - int nblocks, blocksreleased = 0; - int error = 0, allerror = 0; + caddr_t copy = NULL; + int i, nblocks, error = 0, allerror = 0; + ufs2_daddr_t nb, nlbn, last; + ufs2_daddr_t blkcount, factor, blocksreleased = 0; + ufs1_daddr_t *bap1 = NULL; + ufs2_daddr_t *bap2 = NULL; +# define BAP(ip, i) (((ip)->i_ump->um_fstype == UFS1) ? bap1[i] : bap2[i]) /* * Calculate index in current block of last @@ -486,12 +506,15 @@ ffs_indirtrunc(ip, lbn, dbn, lastbn, level, countp) return (error); } - bap = (ufs_daddr_t *)bp->b_data; + if (ip->i_ump->um_fstype == UFS1) + bap1 = (ufs1_daddr_t *)bp->b_data; + else + bap2 = (ufs2_daddr_t *)bp->b_data; if (lastbn != -1) { - MALLOC(copy, ufs_daddr_t *, fs->fs_bsize, M_TEMP, M_WAITOK); - bcopy((caddr_t)bap, (caddr_t)copy, (u_int)fs->fs_bsize); - bzero((caddr_t)&bap[last + 1], - (u_int)(NINDIR(fs) - (last + 1)) * sizeof (ufs_daddr_t)); + MALLOC(copy, caddr_t, fs->fs_bsize, M_TEMP, M_WAITOK); + bcopy((caddr_t)bp->b_data, copy, (u_int)fs->fs_bsize); + for (i = last + 1; i < NINDIR(fs); i++) + BAP(ip, i) = 0; if (DOINGASYNC(vp)) { bawrite(bp); } else { @@ -499,7 +522,10 @@ ffs_indirtrunc(ip, lbn, dbn, lastbn, level, countp) if (error) allerror = error; } - bap = copy; + if (ip->i_ump->um_fstype == UFS1) + bap1 = (ufs1_daddr_t *)copy; + else + bap2 = (ufs2_daddr_t *)copy; } /* @@ -507,12 +533,12 @@ ffs_indirtrunc(ip, lbn, dbn, lastbn, level, countp) */ for (i = NINDIR(fs) - 1, nlbn = lbn + 1 - i * factor; i > last; i--, nlbn += factor) { - nb = bap[i]; + nb = BAP(ip, i); if (nb == 0) continue; if (level > SINGLE) { if ((error = ffs_indirtrunc(ip, nlbn, fsbtodb(fs, nb), - (ufs_daddr_t)-1, level - 1, &blkcount)) != 0) + (ufs2_daddr_t)-1, level - 1, &blkcount)) != 0) allerror = error; blocksreleased += blkcount; } @@ -525,7 +551,7 @@ ffs_indirtrunc(ip, lbn, dbn, lastbn, level, countp) */ if (level > SINGLE && lastbn >= 0) { last = lastbn % factor; - nb = bap[i]; + nb = BAP(ip, i); if (nb != 0) { error = ffs_indirtrunc(ip, nlbn, fsbtodb(fs, nb), last, level - 1, &blkcount); @@ -540,7 +566,7 @@ ffs_indirtrunc(ip, lbn, dbn, lastbn, level, countp) bp->b_flags |= B_INVAL | B_NOCACHE; brelse(bp); } - + *countp = blocksreleased; return (allerror); } diff --git a/sys/ufs/ffs/ffs_snapshot.c b/sys/ufs/ffs/ffs_snapshot.c index 7965211..7bc4656 100644 --- a/sys/ufs/ffs/ffs_snapshot.c +++ b/sys/ufs/ffs/ffs_snapshot.c @@ -35,6 +35,7 @@ */ #include <sys/param.h> +#include <sys/stdint.h> #include <sys/systm.h> #include <sys/conf.h> #include <sys/disklabel.h> @@ -47,6 +48,7 @@ #include <sys/mount.h> #include <sys/resource.h> #include <sys/resourcevar.h> +#include <sys/disklabel.h> #include <sys/vnode.h> #include <ufs/ufs/extattr.h> @@ -62,20 +64,34 @@ #define DEBUG 1 static int cgaccount(int, struct vnode *, struct buf *, int); -static int expunge(struct vnode *, struct inode *, struct fs *, - int (*)(struct vnode *, ufs_daddr_t *, ufs_daddr_t *, struct fs *, - ufs_daddr_t, int), int); -static int indiracct(struct vnode *, struct vnode *, int, ufs_daddr_t, - int, int, int, int, struct fs *, int (*)(struct vnode *, - ufs_daddr_t *, ufs_daddr_t *, struct fs *, ufs_daddr_t, int), int); -static int fullacct(struct vnode *, ufs_daddr_t *, ufs_daddr_t *, - struct fs *, ufs_daddr_t, int); -static int snapacct(struct vnode *, ufs_daddr_t *, ufs_daddr_t *, - struct fs *, ufs_daddr_t, int); -static int mapacct(struct vnode *, ufs_daddr_t *, ufs_daddr_t *, - struct fs *, ufs_daddr_t, int); +static int expunge_ufs1(struct vnode *, struct inode *, struct fs *, + int (*)(struct vnode *, ufs1_daddr_t *, ufs1_daddr_t *, struct fs *, + ufs_lbn_t, int), int); +static int indiracct_ufs1(struct vnode *, struct vnode *, int, + ufs1_daddr_t, ufs_lbn_t, ufs_lbn_t, ufs_lbn_t, ufs_lbn_t, struct fs *, + int (*)(struct vnode *, ufs1_daddr_t *, ufs1_daddr_t *, struct fs *, + ufs_lbn_t, int), int); +static int fullacct_ufs1(struct vnode *, ufs1_daddr_t *, ufs1_daddr_t *, + struct fs *, ufs_lbn_t, int); +static int snapacct_ufs1(struct vnode *, ufs1_daddr_t *, ufs1_daddr_t *, + struct fs *, ufs_lbn_t, int); +static int mapacct_ufs1(struct vnode *, ufs1_daddr_t *, ufs1_daddr_t *, + struct fs *, ufs_lbn_t, int); +static int expunge_ufs2(struct vnode *, struct inode *, struct fs *, + int (*)(struct vnode *, ufs2_daddr_t *, ufs2_daddr_t *, struct fs *, + ufs_lbn_t, int), int); +static int indiracct_ufs2(struct vnode *, struct vnode *, int, + ufs2_daddr_t, ufs_lbn_t, ufs_lbn_t, ufs_lbn_t, ufs_lbn_t, struct fs *, + int (*)(struct vnode *, ufs2_daddr_t *, ufs2_daddr_t *, struct fs *, + ufs_lbn_t, int), int); +static int fullacct_ufs2(struct vnode *, ufs2_daddr_t *, ufs2_daddr_t *, + struct fs *, ufs_lbn_t, int); +static int snapacct_ufs2(struct vnode *, ufs2_daddr_t *, ufs2_daddr_t *, + struct fs *, ufs_lbn_t, int); +static int mapacct_ufs2(struct vnode *, ufs2_daddr_t *, ufs2_daddr_t *, + struct fs *, ufs_lbn_t, int); static int ffs_copyonwrite(struct vnode *, struct buf *); -static int readblock(struct buf *, daddr_t); +static int readblock(struct buf *, ufs2_daddr_t); /* * To ensure the consistency of snapshots across crashes, we must @@ -104,8 +120,8 @@ ffs_snapshot(mp, snapfile) struct mount *mp; char *snapfile; { - ufs_daddr_t blkno; - int error, cg, snaploc, numblks; + ufs2_daddr_t numblks, blkno; + int error, cg, snaploc; int i, size, len, loc; int flag = mp->mnt_flag; struct timespec starttime = {0, 0}, endtime; @@ -191,6 +207,7 @@ restart: if (error) goto out; ip->i_size = lblktosize(fs, (off_t)numblks); + DIP(ip, i_size) = ip->i_size; ip->i_flag |= IN_CHANGE | IN_UPDATE; if ((error = readblock(bp, numblks - 1)) != 0) goto out; @@ -216,7 +233,8 @@ restart: /* * Allocate copies for the superblock and its summary information. */ - error = UFS_BALLOC(vp, (off_t)(SBOFF), SBSIZE, KERNCRED, 0, &nbp); + error = UFS_BALLOC(vp, lfragtosize(fs, fs->fs_sblockloc), + fs->fs_sbsize, KERNCRED, 0, &nbp); if (error) goto out; bawrite(nbp); @@ -266,6 +284,7 @@ restart: * Change inode to snapshot type file. */ ip->i_flags |= SF_SNAPSHOT; + DIP(ip, i_flags) = ip->i_flags; ip->i_flag |= IN_CHANGE | IN_UPDATE; /* * Ensure that the snapshot is completely on disk. @@ -315,19 +334,21 @@ restart: * Grab a copy of the superblock and its summary information. * We delay writing it until the suspension is released below. */ - error = bread(vp, lblkno(fs, SBOFF), fs->fs_bsize, KERNCRED, &sbp); + error = bread(vp, fragstoblks(fs, fs->fs_sblockloc), fs->fs_bsize, + KERNCRED, &sbp); if (error) { brelse(sbp); sbp = NULL; goto out1; } - copy_fs = (struct fs *)(sbp->b_data + blkoff(fs, SBOFF)); + loc = blkoff(fs, lfragtosize(fs, fs->fs_sblockloc)); + copy_fs = (struct fs *)(sbp->b_data + loc); bcopy(fs, copy_fs, fs->fs_sbsize); if ((fs->fs_flags & (FS_UNCLEAN | FS_NEEDSFSCK)) == 0) copy_fs->fs_clean = 1; - if (fs->fs_sbsize < SBSIZE) - bzero(&sbp->b_data[blkoff(fs, SBOFF) + fs->fs_sbsize], - SBSIZE - fs->fs_sbsize); + if (fs->fs_sbsize < SBLOCKSIZE) + bzero(&sbp->b_data[loc + fs->fs_sbsize], + SBLOCKSIZE - fs->fs_sbsize); size = blkroundup(fs, fs->fs_cssize); if (fs->fs_contigsumsize > 0) size += fs->fs_ncg * sizeof(int32_t); @@ -399,15 +420,20 @@ loop: if (loc < NDADDR) { len = fragroundup(fs, blkoff(fs, xp->i_size)); if (len < fs->fs_bsize) { - ffs_blkfree(copy_fs, vp, xp->i_db[loc], len, - xp->i_number); - blkno = xp->i_db[loc]; - xp->i_db[loc] = 0; + ffs_blkfree(copy_fs, vp, DIP(xp, i_db[loc]), + len, xp->i_number); + blkno = DIP(xp, i_db[loc]); + DIP(xp, i_db[loc]) = 0; } } - error = expunge(vp, xp, copy_fs, fullacct, BLK_NOCOPY); + if (xp->i_ump->um_fstype == UFS1) + error = expunge_ufs1(vp, xp, copy_fs, fullacct_ufs1, + BLK_NOCOPY); + else + error = expunge_ufs2(vp, xp, copy_fs, fullacct_ufs2, + BLK_NOCOPY); if (blkno) - xp->i_db[loc] = blkno; + DIP(xp, i_db[loc]) = blkno; if (!error) error = ffs_freefile(copy_fs, vp, xp->i_number, xp->i_mode); @@ -458,7 +484,13 @@ out1: TAILQ_FOREACH(xp, snaphead, i_nextsnap) { if (xp == ip) break; - if ((error = expunge(vp, xp, fs, snapacct, BLK_SNAP)) != 0) { + if (xp->i_ump->um_fstype == UFS1) + error = expunge_ufs1(vp, xp, fs, snapacct_ufs1, + BLK_SNAP); + else + error = expunge_ufs2(vp, xp, fs, snapacct_ufs2, + BLK_SNAP); + if (error) { fs->fs_snapinum[snaploc] = 0; goto done; } @@ -467,7 +499,11 @@ out1: * Expunge the blocks used by the snapshots from the set of * blocks marked as used in the snapshot bitmaps. */ - if ((error = expunge(vp, ip, copy_fs, mapacct, BLK_SNAP)) != 0) { + if (ip->i_ump->um_fstype == UFS1) + error = expunge_ufs1(vp, ip, copy_fs, mapacct_ufs1, BLK_SNAP); + else + error = expunge_ufs2(vp, ip, copy_fs, mapacct_ufs2, BLK_SNAP); + if (error) { fs->fs_snapinum[snaploc] = 0; goto done; } @@ -528,7 +564,8 @@ cgaccount(cg, vp, nbp, passno) struct inode *ip; struct cg *cgp; struct fs *fs; - int error, numblks, base, len, loc, indiroff; + ufs2_daddr_t base, numblks; + int error, len, loc, indiroff; ip = VTOI(vp); fs = ip->i_fs; @@ -559,10 +596,10 @@ cgaccount(cg, vp, nbp, passno) if (base < NDADDR) { for ( ; loc < NDADDR; loc++) { if (ffs_isblock(fs, cg_blksfree(cgp), loc)) - ip->i_db[loc] = BLK_NOCOPY; - else if (passno == 2 && ip->i_db[loc] == BLK_NOCOPY) - ip->i_db[loc] = 0; - else if (passno == 1 && ip->i_db[loc] == BLK_NOCOPY) + DIP(ip, i_db[loc]) = BLK_NOCOPY; + else if (passno == 2 && DIP(ip, i_db[loc])== BLK_NOCOPY) + DIP(ip, i_db[loc]) = 0; + else if (passno == 1 && DIP(ip, i_db[loc])== BLK_NOCOPY) panic("ffs_snapshot: lost direct block"); } } @@ -587,13 +624,25 @@ cgaccount(cg, vp, nbp, passno) } indiroff = 0; } + if (ip->i_ump->um_fstype == UFS1) { + if (ffs_isblock(fs, cg_blksfree(cgp), loc)) + ((ufs1_daddr_t *)(ibp->b_data))[indiroff] = + BLK_NOCOPY; + else if (passno == 2 && ((ufs1_daddr_t *)(ibp->b_data)) + [indiroff] == BLK_NOCOPY) + ((ufs1_daddr_t *)(ibp->b_data))[indiroff] = 0; + else if (passno == 1 && ((ufs1_daddr_t *)(ibp->b_data)) + [indiroff] == BLK_NOCOPY) + panic("ffs_snapshot: lost indirect block"); + continue; + } if (ffs_isblock(fs, cg_blksfree(cgp), loc)) - ((ufs_daddr_t *)(ibp->b_data))[indiroff] = BLK_NOCOPY; + ((ufs2_daddr_t *)(ibp->b_data))[indiroff] = BLK_NOCOPY; else if (passno == 2 && - ((ufs_daddr_t *)(ibp->b_data))[indiroff] == BLK_NOCOPY) - ((ufs_daddr_t *)(ibp->b_data))[indiroff] = 0; + ((ufs2_daddr_t *)(ibp->b_data)) [indiroff] == BLK_NOCOPY) + ((ufs2_daddr_t *)(ibp->b_data))[indiroff] = 0; else if (passno == 1 && - ((ufs_daddr_t *)(ibp->b_data))[indiroff] == BLK_NOCOPY) + ((ufs2_daddr_t *)(ibp->b_data)) [indiroff] == BLK_NOCOPY) panic("ffs_snapshot: lost indirect block"); } bqrelse(bp); @@ -608,34 +657,37 @@ cgaccount(cg, vp, nbp, passno) * blocks that it claims with BLK_SNAP so that fsck will * be able to account for those blocks properly and so * that this snapshot knows that it need not copy them - * if the other snapshot holding them is freed. + * if the other snapshot holding them is freed. This code + * is reproduced once each for UFS1 and UFS2. */ static int -expunge(snapvp, cancelip, fs, acctfunc, expungetype) +expunge_ufs1(snapvp, cancelip, fs, acctfunc, expungetype) struct vnode *snapvp; struct inode *cancelip; struct fs *fs; - int (*acctfunc)(struct vnode *, ufs_daddr_t *, ufs_daddr_t *, - struct fs *, ufs_daddr_t, int); + int (*acctfunc)(struct vnode *, ufs1_daddr_t *, ufs1_daddr_t *, + struct fs *, ufs_lbn_t, int); int expungetype; { - int i, len, error, numblks, blksperindir; - ufs_daddr_t lbn, rlbn, blkno, indiroff; + int i, error, indiroff; + ufs_lbn_t lbn, rlbn; + ufs2_daddr_t len, blkno, numblks, blksperindir; + struct ufs1_dinode *dip; struct thread *td = curthread; - struct dinode *dip; struct buf *bp; numblks = howmany(cancelip->i_size, fs->fs_bsize); - if ((error = (*acctfunc)(snapvp, &cancelip->i_db[0], - &cancelip->i_ib[NIADDR], fs, 0, expungetype))) + if ((error = (*acctfunc)(snapvp, &cancelip->i_din1->di_db[0], + &cancelip->i_din1->di_ib[NIADDR], fs, 0, expungetype))) return (error); blksperindir = 1; lbn = -NDADDR; len = numblks - NDADDR; rlbn = NDADDR; for (i = 0; len > 0 && i < NIADDR; i++) { - error = indiracct(snapvp, ITOV(cancelip), i, cancelip->i_ib[i], - lbn, rlbn, len, blksperindir, fs, acctfunc, expungetype); + error = indiracct_ufs1(snapvp, ITOV(cancelip), i, + cancelip->i_din1->di_ib[i], lbn, rlbn, len, + blksperindir, fs, acctfunc, expungetype); if (error) return (error); blksperindir *= NINDIR(fs); @@ -650,7 +702,7 @@ expunge(snapvp, cancelip, fs, acctfunc, expungetype) lbn = fragstoblks(fs, ino_to_fsba(fs, cancelip->i_number)); blkno = 0; if (lbn < NDADDR) { - blkno = cancelip->i_db[lbn]; + blkno = cancelip->i_din1->di_db[lbn]; } else { td->td_proc->p_flag |= P_COWINPROGRESS; error = UFS_BALLOC(snapvp, lblktosize(fs, (off_t)lbn), @@ -659,7 +711,7 @@ expunge(snapvp, cancelip, fs, acctfunc, expungetype) if (error) return (error); indiroff = (lbn - NDADDR) % NINDIR(fs); - blkno = ((ufs_daddr_t *)(bp->b_data))[indiroff]; + blkno = ((ufs1_daddr_t *)(bp->b_data))[indiroff]; bqrelse(bp); } error = UFS_BALLOC(snapvp, lblktosize(fs, (off_t)lbn), @@ -672,13 +724,14 @@ expunge(snapvp, cancelip, fs, acctfunc, expungetype) * Set a snapshot inode to be a zero length file, regular files * to be completely unallocated. */ - dip = (struct dinode *)bp->b_data + ino_to_fsbo(fs, cancelip->i_number); + dip = (struct ufs1_dinode *)bp->b_data + + ino_to_fsbo(fs, cancelip->i_number); if (expungetype == BLK_NOCOPY) dip->di_mode = 0; dip->di_size = 0; dip->di_blocks = 0; dip->di_flags &= ~SF_SNAPSHOT; - bzero(&dip->di_db[0], (NDADDR + NIADDR) * sizeof(ufs_daddr_t)); + bzero(&dip->di_db[0], (NDADDR + NIADDR) * sizeof(ufs1_daddr_t)); bdwrite(bp); return (0); } @@ -688,24 +741,25 @@ expunge(snapvp, cancelip, fs, acctfunc, expungetype) * its indirect blocks in snapvp. */ static int -indiracct(snapvp, cancelvp, level, blkno, lbn, rlbn, remblks, blksperindir, fs, - acctfunc, expungetype) +indiracct_ufs1(snapvp, cancelvp, level, blkno, lbn, rlbn, remblks, + blksperindir, fs, acctfunc, expungetype) struct vnode *snapvp; struct vnode *cancelvp; int level; - ufs_daddr_t blkno; - int lbn; - int rlbn; - int remblks; - int blksperindir; + ufs1_daddr_t blkno; + ufs_lbn_t lbn; + ufs_lbn_t rlbn; + ufs_lbn_t remblks; + ufs_lbn_t blksperindir; struct fs *fs; - int (*acctfunc)(struct vnode *, ufs_daddr_t *, ufs_daddr_t *, - struct fs *, ufs_daddr_t, int); + int (*acctfunc)(struct vnode *, ufs1_daddr_t *, ufs1_daddr_t *, + struct fs *, ufs_lbn_t, int); int expungetype; { - int subblksperindir, error, last, num, i; + int error, num, i; + ufs_lbn_t subblksperindir; struct indir indirs[NIADDR + 2]; - ufs_daddr_t *bap; + ufs1_daddr_t last, *bap; struct buf *bp; if ((error = ufs_getlbns(cancelvp, rlbn, indirs, &num)) != 0) @@ -729,7 +783,7 @@ indiracct(snapvp, cancelvp, level, blkno, lbn, rlbn, remblks, blksperindir, fs, last = howmany(remblks, blksperindir); if (last > NINDIR(fs)) last = NINDIR(fs); - MALLOC(bap, ufs_daddr_t *, fs->fs_bsize, M_DEVBUF, M_WAITOK); + MALLOC(bap, ufs1_daddr_t *, fs->fs_bsize, M_DEVBUF, M_WAITOK); bcopy(bp->b_data, (caddr_t)bap, fs->fs_bsize); bqrelse(bp); error = (*acctfunc)(snapvp, &bap[0], &bap[last], fs, rlbn, expungetype); @@ -741,7 +795,7 @@ indiracct(snapvp, cancelvp, level, blkno, lbn, rlbn, remblks, blksperindir, fs, */ subblksperindir = blksperindir / NINDIR(fs); for (lbn++, level--, i = 0; i < last; i++) { - error = indiracct(snapvp, cancelvp, level, bap[i], lbn, + error = indiracct_ufs1(snapvp, cancelvp, level, bap[i], lbn, rlbn, remblks, subblksperindir, fs, acctfunc, expungetype); if (error) goto out; @@ -758,33 +812,287 @@ out: * Do both snap accounting and map accounting. */ static int -fullacct(vp, oldblkp, lastblkp, fs, lblkno, expungetype) +fullacct_ufs1(vp, oldblkp, lastblkp, fs, lblkno, exptype) + struct vnode *vp; + ufs1_daddr_t *oldblkp, *lastblkp; + struct fs *fs; + ufs_lbn_t lblkno; + int exptype; /* BLK_SNAP or BLK_NOCOPY */ +{ + int error; + + if ((error = snapacct_ufs1(vp, oldblkp, lastblkp, fs, lblkno, exptype))) + return (error); + return (mapacct_ufs1(vp, oldblkp, lastblkp, fs, lblkno, exptype)); +} + +/* + * Identify a set of blocks allocated in a snapshot inode. + */ +static int +snapacct_ufs1(vp, oldblkp, lastblkp, fs, lblkno, expungetype) struct vnode *vp; - ufs_daddr_t *oldblkp, *lastblkp; + ufs1_daddr_t *oldblkp, *lastblkp; struct fs *fs; - ufs_daddr_t lblkno; + ufs_lbn_t lblkno; int expungetype; /* BLK_SNAP or BLK_NOCOPY */ { + struct inode *ip = VTOI(vp); + ufs1_daddr_t blkno, *blkp; + ufs_lbn_t lbn; + struct buf *ibp; + int error; + + for ( ; oldblkp < lastblkp; oldblkp++) { + blkno = *oldblkp; + if (blkno == 0 || blkno == BLK_NOCOPY || blkno == BLK_SNAP) + continue; + lbn = fragstoblks(fs, blkno); + if (lbn < NDADDR) { + blkp = &ip->i_din1->di_db[lbn]; + ip->i_flag |= IN_CHANGE | IN_UPDATE; + } else { + error = UFS_BALLOC(vp, lblktosize(fs, (off_t)lbn), + fs->fs_bsize, KERNCRED, B_METAONLY, &ibp); + if (error) + return (error); + blkp = &((ufs1_daddr_t *)(ibp->b_data)) + [(lbn - NDADDR) % NINDIR(fs)]; + } + /* + * If we are expunging a snapshot vnode and we + * find a block marked BLK_NOCOPY, then it is + * one that has been allocated to this snapshot after + * we took our current snapshot and can be ignored. + */ + if (expungetype == BLK_SNAP && *blkp == BLK_NOCOPY) { + if (lbn >= NDADDR) + brelse(ibp); + } else { + if (*blkp != 0) + panic("snapacct: bad block"); + *blkp = expungetype; + if (lbn >= NDADDR) + bdwrite(ibp); + } + } + return (0); +} + +/* + * Account for a set of blocks allocated in a snapshot inode. + */ +static int +mapacct_ufs1(vp, oldblkp, lastblkp, fs, lblkno, expungetype) + struct vnode *vp; + ufs1_daddr_t *oldblkp, *lastblkp; + struct fs *fs; + ufs_lbn_t lblkno; + int expungetype; +{ + ufs1_daddr_t blkno; + ino_t inum; + + inum = VTOI(vp)->i_number; + for ( ; oldblkp < lastblkp; oldblkp++, lblkno++) { + blkno = *oldblkp; + if (blkno == 0 || blkno == BLK_NOCOPY) + continue; + if (blkno == BLK_SNAP) + blkno = blkstofrags(fs, lblkno); + ffs_blkfree(fs, vp, blkno, fs->fs_bsize, inum); + } + return (0); +} + +/* + * Before expunging a snapshot inode, note all the + * blocks that it claims with BLK_SNAP so that fsck will + * be able to account for those blocks properly and so + * that this snapshot knows that it need not copy them + * if the other snapshot holding them is freed. This code + * is reproduced once each for UFS1 and UFS2. + */ +static int +expunge_ufs2(snapvp, cancelip, fs, acctfunc, expungetype) + struct vnode *snapvp; + struct inode *cancelip; + struct fs *fs; + int (*acctfunc)(struct vnode *, ufs2_daddr_t *, ufs2_daddr_t *, + struct fs *, ufs_lbn_t, int); + int expungetype; +{ + int i, error, indiroff; + ufs_lbn_t lbn, rlbn; + ufs2_daddr_t len, blkno, numblks, blksperindir; + struct ufs2_dinode *dip; + struct thread *td = curthread; + struct buf *bp; + + numblks = howmany(cancelip->i_size, fs->fs_bsize); + if ((error = (*acctfunc)(snapvp, &cancelip->i_din2->di_db[0], + &cancelip->i_din2->di_ib[NIADDR], fs, 0, expungetype))) + return (error); + blksperindir = 1; + lbn = -NDADDR; + len = numblks - NDADDR; + rlbn = NDADDR; + for (i = 0; len > 0 && i < NIADDR; i++) { + error = indiracct_ufs2(snapvp, ITOV(cancelip), i, + cancelip->i_din2->di_ib[i], lbn, rlbn, len, + blksperindir, fs, acctfunc, expungetype); + if (error) + return (error); + blksperindir *= NINDIR(fs); + lbn -= blksperindir + 1; + len -= blksperindir; + rlbn += blksperindir; + } + /* + * Prepare to expunge the inode. If its inode block has not + * yet been copied, then allocate and fill the copy. + */ + lbn = fragstoblks(fs, ino_to_fsba(fs, cancelip->i_number)); + blkno = 0; + if (lbn < NDADDR) { + blkno = cancelip->i_din2->di_db[lbn]; + } else { + td->td_proc->p_flag |= P_COWINPROGRESS; + error = UFS_BALLOC(snapvp, lblktosize(fs, (off_t)lbn), + fs->fs_bsize, KERNCRED, B_METAONLY, &bp); + td->td_proc->p_flag &= ~P_COWINPROGRESS; + if (error) + return (error); + indiroff = (lbn - NDADDR) % NINDIR(fs); + blkno = ((ufs2_daddr_t *)(bp->b_data))[indiroff]; + bqrelse(bp); + } + error = UFS_BALLOC(snapvp, lblktosize(fs, (off_t)lbn), + fs->fs_bsize, KERNCRED, 0, &bp); + if (error) + return (error); + if (blkno == 0 && (error = readblock(bp, lbn))) + return (error); + /* + * Set a snapshot inode to be a zero length file, regular files + * to be completely unallocated. + */ + dip = (struct ufs2_dinode *)bp->b_data + + ino_to_fsbo(fs, cancelip->i_number); + if (expungetype == BLK_NOCOPY) + dip->di_mode = 0; + dip->di_size = 0; + dip->di_blocks = 0; + dip->di_flags &= ~SF_SNAPSHOT; + bzero(&dip->di_db[0], (NDADDR + NIADDR) * sizeof(ufs2_daddr_t)); + bdwrite(bp); + return (0); +} + +/* + * Descend an indirect block chain for vnode cancelvp accounting for all + * its indirect blocks in snapvp. + */ +static int +indiracct_ufs2(snapvp, cancelvp, level, blkno, lbn, rlbn, remblks, + blksperindir, fs, acctfunc, expungetype) + struct vnode *snapvp; + struct vnode *cancelvp; + int level; + ufs2_daddr_t blkno; + ufs_lbn_t lbn; + ufs_lbn_t rlbn; + ufs_lbn_t remblks; + ufs_lbn_t blksperindir; + struct fs *fs; + int (*acctfunc)(struct vnode *, ufs2_daddr_t *, ufs2_daddr_t *, + struct fs *, ufs_lbn_t, int); + int expungetype; +{ + int error, num, i; + ufs_lbn_t subblksperindir; + struct indir indirs[NIADDR + 2]; + ufs2_daddr_t last, *bap; + struct buf *bp; + + if ((error = ufs_getlbns(cancelvp, rlbn, indirs, &num)) != 0) + return (error); + if (lbn != indirs[num - 1 - level].in_lbn || blkno == 0 || num < 2) + panic("indiracct: botched params"); + /* + * We have to expand bread here since it will deadlock looking + * up the block number for any blocks that are not in the cache. + */ + bp = getblk(cancelvp, lbn, fs->fs_bsize, 0, 0); + bp->b_blkno = fsbtodb(fs, blkno); + if ((bp->b_flags & (B_DONE | B_DELWRI)) == 0 && + (error = readblock(bp, fragstoblks(fs, blkno)))) { + brelse(bp); + return (error); + } + /* + * Account for the block pointers in this indirect block. + */ + last = howmany(remblks, blksperindir); + if (last > NINDIR(fs)) + last = NINDIR(fs); + MALLOC(bap, ufs2_daddr_t *, fs->fs_bsize, M_DEVBUF, M_WAITOK); + bcopy(bp->b_data, (caddr_t)bap, fs->fs_bsize); + bqrelse(bp); + error = (*acctfunc)(snapvp, &bap[0], &bap[last], fs, rlbn, expungetype); + if (error || level == 0) + goto out; + /* + * Account for the block pointers in each of the indirect blocks + * in the levels below us. + */ + subblksperindir = blksperindir / NINDIR(fs); + for (lbn++, level--, i = 0; i < last; i++) { + error = indiracct_ufs2(snapvp, cancelvp, level, bap[i], lbn, + rlbn, remblks, subblksperindir, fs, acctfunc, expungetype); + if (error) + goto out; + rlbn += blksperindir; + lbn -= blksperindir; + remblks -= blksperindir; + } +out: + FREE(bap, M_DEVBUF); + return (error); +} + +/* + * Do both snap accounting and map accounting. + */ +static int +fullacct_ufs2(vp, oldblkp, lastblkp, fs, lblkno, exptype) + struct vnode *vp; + ufs2_daddr_t *oldblkp, *lastblkp; + struct fs *fs; + ufs_lbn_t lblkno; + int exptype; /* BLK_SNAP or BLK_NOCOPY */ +{ int error; - if ((error = snapacct(vp, oldblkp, lastblkp, fs, lblkno, expungetype))) + if ((error = snapacct_ufs2(vp, oldblkp, lastblkp, fs, lblkno, exptype))) return (error); - return (mapacct(vp, oldblkp, lastblkp, fs, lblkno, expungetype)); + return (mapacct_ufs2(vp, oldblkp, lastblkp, fs, lblkno, exptype)); } /* * Identify a set of blocks allocated in a snapshot inode. */ static int -snapacct(vp, oldblkp, lastblkp, fs, lblkno, expungetype) +snapacct_ufs2(vp, oldblkp, lastblkp, fs, lblkno, expungetype) struct vnode *vp; - ufs_daddr_t *oldblkp, *lastblkp; + ufs2_daddr_t *oldblkp, *lastblkp; struct fs *fs; - ufs_daddr_t lblkno; + ufs_lbn_t lblkno; int expungetype; /* BLK_SNAP or BLK_NOCOPY */ { struct inode *ip = VTOI(vp); - ufs_daddr_t lbn, blkno, *blkp; + ufs2_daddr_t blkno, *blkp; + ufs_lbn_t lbn; struct buf *ibp; int error; @@ -794,14 +1102,14 @@ snapacct(vp, oldblkp, lastblkp, fs, lblkno, expungetype) continue; lbn = fragstoblks(fs, blkno); if (lbn < NDADDR) { - blkp = &ip->i_db[lbn]; + blkp = &ip->i_din2->di_db[lbn]; ip->i_flag |= IN_CHANGE | IN_UPDATE; } else { error = UFS_BALLOC(vp, lblktosize(fs, (off_t)lbn), fs->fs_bsize, KERNCRED, B_METAONLY, &ibp); if (error) return (error); - blkp = &((ufs_daddr_t *)(ibp->b_data)) + blkp = &((ufs2_daddr_t *)(ibp->b_data)) [(lbn - NDADDR) % NINDIR(fs)]; } /* @@ -828,14 +1136,14 @@ snapacct(vp, oldblkp, lastblkp, fs, lblkno, expungetype) * Account for a set of blocks allocated in a snapshot inode. */ static int -mapacct(vp, oldblkp, lastblkp, fs, lblkno, expungetype) +mapacct_ufs2(vp, oldblkp, lastblkp, fs, lblkno, expungetype) struct vnode *vp; - ufs_daddr_t *oldblkp, *lastblkp; + ufs2_daddr_t *oldblkp, *lastblkp; struct fs *fs; - ufs_daddr_t lblkno; + ufs_lbn_t lblkno; int expungetype; { - ufs_daddr_t blkno; + ufs2_daddr_t blkno; ino_t inum; inum = VTOI(vp)->i_number; @@ -901,8 +1209,8 @@ ffs_snapremove(vp) struct vnode *devvp; struct buf *ibp; struct fs *fs; - ufs_daddr_t blkno, dblk; - int error, numblks, loc, last; + ufs2_daddr_t numblks, blkno, dblk; + int error, loc, last; ip = VTOI(vp); fs = ip->i_fs; @@ -927,14 +1235,14 @@ ffs_snapremove(vp) * snapshots that want them (see ffs_snapblkfree below). */ for (blkno = 1; blkno < NDADDR; blkno++) { - dblk = ip->i_db[blkno]; + dblk = DIP(ip, i_db[blkno]); if (dblk == BLK_NOCOPY || dblk == BLK_SNAP) - ip->i_db[blkno] = 0; + DIP(ip, i_db[blkno]) = 0; else if ((dblk == blkstofrags(fs, blkno) && ffs_snapblkfree(fs, ip->i_devvp, dblk, fs->fs_bsize, ip->i_number))) { - ip->i_blocks -= btodb(fs->fs_bsize); - ip->i_db[blkno] = 0; + DIP(ip, i_blocks) -= btodb(fs->fs_bsize); + DIP(ip, i_db[blkno]) = 0; } } numblks = howmany(ip->i_size, fs->fs_bsize); @@ -943,17 +1251,32 @@ ffs_snapremove(vp) fs->fs_bsize, KERNCRED, B_METAONLY, &ibp); if (error) continue; - if ((last = fs->fs_size - blkno) > NINDIR(fs)) + if (fs->fs_size - blkno > NINDIR(fs)) last = NINDIR(fs); + else + last = fs->fs_size - blkno; for (loc = 0; loc < last; loc++) { - dblk = ((ufs_daddr_t *)(ibp->b_data))[loc]; + if (ip->i_ump->um_fstype == UFS1) { + dblk = ((ufs1_daddr_t *)(ibp->b_data))[loc]; + if (dblk == BLK_NOCOPY || dblk == BLK_SNAP) + ((ufs1_daddr_t *)(ibp->b_data))[loc]= 0; + else if ((dblk == blkstofrags(fs, blkno) && + ffs_snapblkfree(fs, ip->i_devvp, dblk, + fs->fs_bsize, ip->i_number))) { + ip->i_din1->di_blocks -= + btodb(fs->fs_bsize); + ((ufs1_daddr_t *)(ibp->b_data))[loc]= 0; + } + continue; + } + dblk = ((ufs2_daddr_t *)(ibp->b_data))[loc]; if (dblk == BLK_NOCOPY || dblk == BLK_SNAP) - ((ufs_daddr_t *)(ibp->b_data))[loc] = 0; + ((ufs2_daddr_t *)(ibp->b_data))[loc] = 0; else if ((dblk == blkstofrags(fs, blkno) && ffs_snapblkfree(fs, ip->i_devvp, dblk, fs->fs_bsize, ip->i_number))) { - ip->i_blocks -= btodb(fs->fs_bsize); - ((ufs_daddr_t *)(ibp->b_data))[loc] = 0; + ip->i_din2->di_blocks -= btodb(fs->fs_bsize); + ((ufs2_daddr_t *)(ibp->b_data))[loc] = 0; } } bawrite(ibp); @@ -962,6 +1285,7 @@ ffs_snapremove(vp) * Clear snapshot flag and drop reference. */ ip->i_flags &= ~SF_SNAPSHOT; + DIP(ip, i_flags) = ip->i_flags; ip->i_flag |= IN_CHANGE | IN_UPDATE; } @@ -987,7 +1311,7 @@ int ffs_snapblkfree(fs, devvp, bno, size, inum) struct fs *fs; struct vnode *devvp; - ufs_daddr_t bno; + ufs2_daddr_t bno; long size; ino_t inum; { @@ -995,7 +1319,8 @@ ffs_snapblkfree(fs, devvp, bno, size, inum) struct thread *td = curthread; struct inode *ip; struct vnode *vp; - ufs_daddr_t lbn, blkno; + ufs_lbn_t lbn; + ufs2_daddr_t blkno; int indiroff = 0, error = 0, claimedblk = 0; struct snaphead *snaphead; @@ -1007,7 +1332,7 @@ ffs_snapblkfree(fs, devvp, bno, size, inum) * Lookup block being written. */ if (lbn < NDADDR) { - blkno = ip->i_db[lbn]; + blkno = DIP(ip, i_db[lbn]); } else { vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); td->td_proc->p_flag |= P_COWINPROGRESS; @@ -1018,46 +1343,52 @@ ffs_snapblkfree(fs, devvp, bno, size, inum) if (error) break; indiroff = (lbn - NDADDR) % NINDIR(fs); - blkno = ((ufs_daddr_t *)(ibp->b_data))[indiroff]; + if (ip->i_ump->um_fstype == UFS1) + blkno=((ufs1_daddr_t *)(ibp->b_data))[indiroff]; + else + blkno=((ufs2_daddr_t *)(ibp->b_data))[indiroff]; } /* * Check to see if block needs to be copied. */ - switch (blkno) { - /* - * If the snapshot has already copied the block (default), - * or does not care about the block, it is not needed. - */ - default: - case BLK_NOCOPY: - if (lbn >= NDADDR) - bqrelse(ibp); - continue; - /* - * No previous snapshot claimed the block, so it will be - * freed and become a BLK_NOCOPY (don't care) for us. - */ - case BLK_SNAP: + if (blkno == 0) { + /* + * A block that we map is being freed. If it has not + * been claimed yet, we will claim or copy it (below). + */ + claimedblk = 1; + } else if (blkno == BLK_SNAP) { + /* + * No previous snapshot claimed the block, + * so it will be * freed and become a BLK_NOCOPY + * (don't care) for us. + */ if (claimedblk) panic("snapblkfree: inconsistent block type"); vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); if (lbn < NDADDR) { - ip->i_db[lbn] = BLK_NOCOPY; + DIP(ip, i_db[lbn]) = BLK_NOCOPY; ip->i_flag |= IN_CHANGE | IN_UPDATE; + } else if (ip->i_ump->um_fstype == UFS1) { + ((ufs1_daddr_t *)(ibp->b_data))[indiroff] = + BLK_NOCOPY; + bdwrite(ibp); } else { - ((ufs_daddr_t *)(ibp->b_data))[indiroff] = + ((ufs2_daddr_t *)(ibp->b_data))[indiroff] = BLK_NOCOPY; bdwrite(ibp); } VOP_UNLOCK(vp, 0, td); continue; - /* - * A block that we map is being freed. If it has not been - * claimed yet, we will claim or copy it (below). - */ - case 0: - claimedblk = 1; - break; + } else /* BLK_NOCOPY or default */ { + /* + * If the snapshot has already copied the block + * (default), or does not care about the block, + * it is not needed. + */ + if (lbn >= NDADDR) + bqrelse(ibp); + continue; } /* * If this is a full size block, we will just grab it @@ -1069,18 +1400,21 @@ ffs_snapblkfree(fs, devvp, bno, size, inum) if (size == fs->fs_bsize) { #ifdef DEBUG if (snapdebug) - printf("%s %d lbn %d from inum %d\n", - "Grabonremove: snapino", ip->i_number, lbn, - inum); + printf("%s %d lbn %lld from inum %d\n", + "Grabonremove: snapino", ip->i_number, + (intmax_t)lbn, inum); #endif vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); if (lbn < NDADDR) { - ip->i_db[lbn] = bno; + DIP(ip, i_db[lbn]) = bno; + } else if (ip->i_ump->um_fstype == UFS1) { + ((ufs1_daddr_t *)(ibp->b_data))[indiroff] = bno; + bdwrite(ibp); } else { - ((ufs_daddr_t *)(ibp->b_data))[indiroff] = bno; + ((ufs2_daddr_t *)(ibp->b_data))[indiroff] = bno; bdwrite(ibp); } - ip->i_blocks += btodb(size); + DIP(ip, i_blocks) += btodb(size); ip->i_flag |= IN_CHANGE | IN_UPDATE; VOP_UNLOCK(vp, 0, td); return (1); @@ -1103,10 +1437,10 @@ ffs_snapblkfree(fs, devvp, bno, size, inum) } #ifdef DEBUG if (snapdebug) - printf( -"Copyonremove: snapino %lu lbn %ld for inum %lu size %ld to blkno %lld\n", - (unsigned long)ip->i_number, (long)lbn, - (unsigned long)inum, size, (long long)cbp->b_blkno); + printf("%s%d lbn %lld %s %d size %ld to blkno %lld\n", + "Copyonremove: snapino ", ip->i_number, + (intmax_t)lbn, "for inum", inum, size, + (intmax_t)cbp->b_blkno); #endif /* * If we have already read the old block contents, then @@ -1245,7 +1579,7 @@ ffs_copyonwrite(devvp, bp) struct fs *fs; struct inode *ip; struct vnode *vp; - ufs_daddr_t lbn, blkno; + ufs2_daddr_t lbn, blkno; int indiroff, error = 0; fs = TAILQ_FIRST(&devvp->v_rdev->si_snapshots)->i_fs; @@ -1273,7 +1607,7 @@ ffs_copyonwrite(devvp, bp) retry: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); if (lbn < NDADDR) { - blkno = ip->i_db[lbn]; + blkno = DIP(ip, i_db[lbn]); } else { td->td_proc->p_flag |= P_COWINPROGRESS; error = UFS_BALLOC(vp, lblktosize(fs, (off_t)lbn), @@ -1287,7 +1621,10 @@ retry: goto retry; } indiroff = (lbn - NDADDR) % NINDIR(fs); - blkno = ((ufs_daddr_t *)(ibp->b_data))[indiroff]; + if (ip->i_ump->um_fstype == UFS1) + blkno=((ufs1_daddr_t *)(ibp->b_data))[indiroff]; + else + blkno=((ufs2_daddr_t *)(ibp->b_data))[indiroff]; bqrelse(ibp); } #ifdef DIAGNOSTIC @@ -1316,14 +1653,14 @@ retry: } #ifdef DEBUG if (snapdebug) { - printf("Copyonwrite: snapino %d lbn %d for ", - ip->i_number, lbn); + printf("Copyonwrite: snapino %d lbn %lld for ", + ip->i_number, (intmax_t)lbn); if (bp->b_vp == devvp) printf("fs metadata"); else printf("inum %d", VTOI(bp->b_vp)->i_number); printf(" lblkno %lld to blkno %lld\n", - (long long)bp->b_lblkno, (long long)cbp->b_blkno); + (intmax_t)bp->b_lblkno, (intmax_t)cbp->b_blkno); } #endif /* @@ -1379,7 +1716,7 @@ retry: static int readblock(bp, lbn) struct buf *bp; - daddr_t lbn; + ufs2_daddr_t lbn; { struct uio auio; struct iovec aiov; diff --git a/sys/ufs/ffs/ffs_softdep.c b/sys/ufs/ffs/ffs_softdep.c index a1422ac..345bfde 100644 --- a/sys/ufs/ffs/ffs_softdep.c +++ b/sys/ufs/ffs/ffs_softdep.c @@ -54,6 +54,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/kernel.h> #include <sys/systm.h> +#include <sys/stdint.h> #include <sys/bio.h> #include <sys/buf.h> #include <sys/malloc.h> @@ -163,7 +164,8 @@ static void handle_allocdirect_partdone(struct allocdirect *); static void handle_allocindir_partdone(struct allocindir *); static void initiate_write_filepage(struct pagedep *, struct buf *); static void handle_written_mkdir(struct mkdir *, int); -static void initiate_write_inodeblock(struct inodedep *, struct buf *); +static void initiate_write_inodeblock_ufs1(struct inodedep *, struct buf *); +static void initiate_write_inodeblock_ufs2(struct inodedep *, struct buf *); static void handle_workitem_freefile(struct freefile *); static void handle_workitem_remove(struct dirrem *, struct vnode *); static struct dirrem *newdirrem(struct buf *, struct inode *, @@ -171,7 +173,8 @@ static struct dirrem *newdirrem(struct buf *, struct inode *, static void free_diradd(struct diradd *); static void free_allocindir(struct allocindir *, struct inodedep *); static void free_newdirblk(struct newdirblk *); -static int indir_trunc(struct freeblks *, ufs_daddr_t, int, ufs_lbn_t, long *); +static int indir_trunc(struct freeblks *, ufs2_daddr_t, int, ufs_lbn_t, + ufs2_daddr_t *); static void deallocate_dependencies(struct buf *, struct inodedep *); static void free_allocdirect(struct allocdirectlst *, struct allocdirect *, int); @@ -181,14 +184,14 @@ static void handle_workitem_freeblocks(struct freeblks *, int); static void merge_inode_lists(struct inodedep *); static void setup_allocindir_phase2(struct buf *, struct inode *, struct allocindir *); -static struct allocindir *newallocindir(struct inode *, int, ufs_daddr_t, - ufs_daddr_t); +static struct allocindir *newallocindir(struct inode *, int, ufs2_daddr_t, + ufs2_daddr_t); static void handle_workitem_freefrag(struct freefrag *); -static struct freefrag *newfreefrag(struct inode *, ufs_daddr_t, long); +static struct freefrag *newfreefrag(struct inode *, ufs2_daddr_t, long); static void allocdirect_merge(struct allocdirectlst *, struct allocdirect *, struct allocdirect *); static struct bmsafemap *bmsafemap_lookup(struct buf *); -static int newblk_lookup(struct fs *, ufs_daddr_t, int, struct newblk **); +static int newblk_lookup(struct fs *, ufs2_daddr_t, int, struct newblk **); static int inodedep_lookup(struct fs *, ino_t, int, struct inodedep **); static int pagedep_lookup(struct inode *, ufs_lbn_t, int, struct pagedep **); static void pause_timer(void *); @@ -1036,7 +1039,7 @@ top: inodedep->id_ino = inum; inodedep->id_state = ALLCOMPLETE; inodedep->id_nlinkdelta = 0; - inodedep->id_savedino = NULL; + inodedep->id_savedino1 = NULL; inodedep->id_savedsize = -1; inodedep->id_buf = NULL; LIST_INIT(&inodedep->id_pendinghd); @@ -1068,7 +1071,7 @@ static struct sema newblk_in_progress; static int newblk_lookup(fs, newblkno, flags, newblkpp) struct fs *fs; - ufs_daddr_t newblkno; + ufs2_daddr_t newblkno; int flags; struct newblk **newblkpp; { @@ -1139,7 +1142,7 @@ softdep_mount(devvp, mp, fs, cred) struct fs *fs; struct ucred *cred; { - struct csum cstotal; + struct csum_total cstotal; struct cg *cgp; struct buf *bp; int error, cyl; @@ -1246,7 +1249,7 @@ void softdep_setup_blkmapdep(bp, fs, newblkno) struct buf *bp; /* buffer for cylgroup block with block map */ struct fs *fs; /* filesystem doing allocation */ - ufs_daddr_t newblkno; /* number of newly allocated block */ + ufs2_daddr_t newblkno; /* number of newly allocated block */ { struct newblk *newblk; struct bmsafemap *bmsafemap; @@ -1332,8 +1335,8 @@ void softdep_setup_allocdirect(ip, lbn, newblkno, oldblkno, newsize, oldsize, bp) struct inode *ip; /* inode to which block is being added */ ufs_lbn_t lbn; /* block pointer within inode */ - ufs_daddr_t newblkno; /* disk block number being added */ - ufs_daddr_t oldblkno; /* previous block number, 0 unless frag */ + ufs2_daddr_t newblkno; /* disk block number being added */ + ufs2_daddr_t oldblkno; /* previous block number, 0 unless frag */ long newsize; /* size of new block */ long oldsize; /* size of new block */ struct buf *bp; /* bp for allocated block */ @@ -1457,9 +1460,11 @@ allocdirect_merge(adphead, newadp, oldadp) newadp->ad_oldsize != oldadp->ad_newsize || newadp->ad_lbn >= NDADDR) { FREE_LOCK(&lk); - panic("allocdirect_merge: old %d != new %d || lbn %ld >= %d", - newadp->ad_oldblkno, oldadp->ad_newblkno, newadp->ad_lbn, - NDADDR); + panic("%s %lld != new %lld || old size %ld != new %ld", + "allocdirect_merge: old blkno", + (intmax_t)newadp->ad_oldblkno, + (intmax_t)oldadp->ad_newblkno, + newadp->ad_oldsize, oldadp->ad_newsize); } newadp->ad_oldblkno = oldadp->ad_oldblkno; newadp->ad_oldsize = oldadp->ad_oldsize; @@ -1504,7 +1509,7 @@ allocdirect_merge(adphead, newadp, oldadp) static struct freefrag * newfreefrag(ip, blkno, size) struct inode *ip; - ufs_daddr_t blkno; + ufs2_daddr_t blkno; long size; { struct freefrag *freefrag; @@ -1521,7 +1526,6 @@ newfreefrag(ip, blkno, size) freefrag->ff_state = 0; freefrag->ff_inum = ip->i_number; freefrag->ff_mnt = ITOV(ip)->v_mount; - freefrag->ff_devvp = ip->i_devvp; freefrag->ff_blkno = blkno; freefrag->ff_fragsize = size; return (freefrag); @@ -1535,9 +1539,10 @@ static void handle_workitem_freefrag(freefrag) struct freefrag *freefrag; { + struct ufsmount *ump = VFSTOUFS(freefrag->ff_mnt); - ffs_blkfree(VFSTOUFS(freefrag->ff_mnt)->um_fs, freefrag->ff_devvp, - freefrag->ff_blkno, freefrag->ff_fragsize, freefrag->ff_inum); + ffs_blkfree(ump->um_fs, ump->um_devvp, freefrag->ff_blkno, + freefrag->ff_fragsize, freefrag->ff_inum); FREE(freefrag, M_FREEFRAG); } @@ -1573,8 +1578,8 @@ static struct allocindir * newallocindir(ip, ptrno, newblkno, oldblkno) struct inode *ip; /* inode for file being extended */ int ptrno; /* offset of pointer in indirect block */ - ufs_daddr_t newblkno; /* disk block number being added */ - ufs_daddr_t oldblkno; /* previous block number, 0 if none */ + ufs2_daddr_t newblkno; /* disk block number being added */ + ufs2_daddr_t oldblkno; /* previous block number, 0 if none */ { struct allocindir *aip; @@ -1599,8 +1604,8 @@ softdep_setup_allocindir_page(ip, lbn, bp, ptrno, newblkno, oldblkno, nbp) ufs_lbn_t lbn; /* allocated block number within file */ struct buf *bp; /* buffer with indirect blk referencing page */ int ptrno; /* offset of pointer in indirect block */ - ufs_daddr_t newblkno; /* disk block number being added */ - ufs_daddr_t oldblkno; /* previous block number, 0 if none */ + ufs2_daddr_t newblkno; /* disk block number being added */ + ufs2_daddr_t oldblkno; /* previous block number, 0 if none */ struct buf *nbp; /* buffer holding allocated page */ { struct allocindir *aip; @@ -1631,7 +1636,7 @@ softdep_setup_allocindir_meta(nbp, ip, bp, ptrno, newblkno) struct inode *ip; /* inode for file being extended */ struct buf *bp; /* indirect block referencing allocated block */ int ptrno; /* offset of pointer in indirect block */ - ufs_daddr_t newblkno; /* disk block number being added */ + ufs2_daddr_t newblkno; /* disk block number being added */ { struct allocindir *aip; @@ -1658,7 +1663,7 @@ setup_allocindir_phase2(bp, ip, aip) struct allocindir *oldaip; struct freefrag *freefrag; struct newblk *newblk; - ufs_daddr_t blkno; + ufs2_daddr_t blkno; if (bp->b_lblkno >= 0) panic("setup_allocindir_phase2: not indir blk"); @@ -1719,8 +1724,12 @@ setup_allocindir_phase2(bp, ip, aip) free_allocindir(oldaip, NULL); } LIST_INSERT_HEAD(&indirdep->ir_deplisthd, aip, ai_next); - ((ufs_daddr_t *)indirdep->ir_savebp->b_data) - [aip->ai_offset] = aip->ai_oldblkno; + if (ip->i_ump->um_fstype == UFS1) + ((ufs1_daddr_t *)indirdep->ir_savebp->b_data) + [aip->ai_offset] = aip->ai_oldblkno; + else + ((ufs2_daddr_t *)indirdep->ir_savebp->b_data) + [aip->ai_offset] = aip->ai_oldblkno; FREE_LOCK(&lk); if (freefrag != NULL) handle_workitem_freefrag(freefrag); @@ -1736,6 +1745,8 @@ setup_allocindir_phase2(bp, ip, aip) M_INDIRDEP, M_SOFTDEP_FLAGS); newindirdep->ir_list.wk_type = D_INDIRDEP; newindirdep->ir_state = ATTACHED; + if (ip->i_ump->um_fstype == UFS1) + newindirdep->ir_state |= UFS1FMT; LIST_INIT(&newindirdep->ir_deplisthd); LIST_INIT(&newindirdep->ir_donehd); if (bp->b_blkno == bp->b_lblkno) { @@ -1803,17 +1814,18 @@ softdep_setup_freeblocks(ip, length) freeblks->fb_mnt = ITOV(ip)->v_mount; freeblks->fb_oldsize = ip->i_size; freeblks->fb_newsize = length; - freeblks->fb_chkcnt = ip->i_blocks; + freeblks->fb_chkcnt = DIP(ip, i_blocks); for (i = 0; i < NDADDR; i++) { - freeblks->fb_dblks[i] = ip->i_db[i]; - ip->i_db[i] = 0; + freeblks->fb_dblks[i] = DIP(ip, i_db[i]); + DIP(ip, i_db[i]) = 0; } for (i = 0; i < NIADDR; i++) { - freeblks->fb_iblks[i] = ip->i_ib[i]; - ip->i_ib[i] = 0; + freeblks->fb_iblks[i] = DIP(ip, i_ib[i]); + DIP(ip, i_ib[i]) = 0; } - ip->i_blocks = 0; + DIP(ip, i_blocks) = 0; ip->i_size = 0; + DIP(ip, i_size) = 0; /* * If the file was removed, then the space being freed was * accounted for then (see softdep_filereleased()). If the @@ -1832,8 +1844,12 @@ softdep_setup_freeblocks(ip, length) brelse(bp); softdep_error("softdep_setup_freeblocks", error); } - *((struct dinode *)bp->b_data + ino_to_fsbo(fs, ip->i_number)) = - ip->i_din; + if (ip->i_ump->um_fstype == UFS1) + *((struct ufs1_dinode *)bp->b_data + + ino_to_fsbo(fs, ip->i_number)) = *ip->i_din1; + else + *((struct ufs2_dinode *)bp->b_data + + ino_to_fsbo(fs, ip->i_number)) = *ip->i_din2; /* * Find and eliminate any inode dependencies. */ @@ -2116,9 +2132,9 @@ free_newdirblk(newdirblk) */ void softdep_freefile(pvp, ino, mode) - struct vnode *pvp; - ino_t ino; - int mode; + struct vnode *pvp; + ino_t ino; + int mode; { struct inode *ip = VTOI(pvp); struct inodedep *inodedep; @@ -2188,9 +2204,9 @@ check_inode_unwritten(inodedep) inodedep->id_buf = NULL; if (inodedep->id_state & ONWORKLIST) WORKLIST_REMOVE(&inodedep->id_list); - if (inodedep->id_savedino != NULL) { - FREE(inodedep->id_savedino, M_INODEDEP); - inodedep->id_savedino = NULL; + if (inodedep->id_savedino1 != NULL) { + FREE(inodedep->id_savedino1, M_INODEDEP); + inodedep->id_savedino1 = NULL; } if (free_inodedep(inodedep) == 0) { FREE_LOCK(&lk); @@ -2214,7 +2230,7 @@ free_inodedep(inodedep) LIST_FIRST(&inodedep->id_inowait) != NULL || TAILQ_FIRST(&inodedep->id_inoupdt) != NULL || TAILQ_FIRST(&inodedep->id_newinoupdt) != NULL || - inodedep->id_nlinkdelta != 0 || inodedep->id_savedino != NULL) + inodedep->id_nlinkdelta != 0 || inodedep->id_savedino1 != NULL) return (0); LIST_REMOVE(inodedep, id_hash); WORKITEM_FREE(inodedep, D_INODEDEP); @@ -2237,10 +2253,9 @@ handle_workitem_freeblocks(freeblks, flags) { struct inode *ip; struct vnode *vp; - ufs_daddr_t bn; struct fs *fs; - int i, level, bsize; - long nblocks, blocksreleased = 0; + int i, nblocks, level, bsize; + ufs2_daddr_t bn, blocksreleased = 0; int error, allerror = 0; ufs_lbn_t baselbns[NIADDR], tmpval; @@ -2288,7 +2303,7 @@ handle_workitem_freeblocks(freeblks, flags) VFS_VGET(freeblks->fb_mnt, freeblks->fb_previousinum, (flags & LK_NOWAIT) | LK_EXCLUSIVE, &vp) == 0) { ip = VTOI(vp); - ip->i_blocks += freeblks->fb_chkcnt - blocksreleased; + DIP(ip, i_blocks) += freeblks->fb_chkcnt - blocksreleased; ip->i_flag |= IN_CHANGE; vput(vp); } @@ -2313,18 +2328,19 @@ handle_workitem_freeblocks(freeblks, flags) static int indir_trunc(freeblks, dbn, level, lbn, countp) struct freeblks *freeblks; - ufs_daddr_t dbn; + ufs2_daddr_t dbn; int level; ufs_lbn_t lbn; - long *countp; + ufs2_daddr_t *countp; { struct buf *bp; - ufs_daddr_t *bap; - ufs_daddr_t nb; struct fs *fs; struct worklist *wk; struct indirdep *indirdep; - int i, lbnadd, nblocks; + ufs1_daddr_t *bap1 = 0; + ufs2_daddr_t nb, *bap2 = 0; + ufs_lbn_t lbnadd; + int i, nblocks, ufs1fmt; int error, allerror = 0; fs = VFSTOUFS(freeblks->fb_mnt)->um_fs; @@ -2371,10 +2387,20 @@ indir_trunc(freeblks, dbn, level, lbn, countp) /* * Recursively free indirect blocks. */ - bap = (ufs_daddr_t *)bp->b_data; + if (VFSTOUFS(freeblks->fb_mnt)->um_fstype == UFS1) { + ufs1fmt = 1; + bap1 = (ufs1_daddr_t *)bp->b_data; + } else { + ufs1fmt = 0; + bap2 = (ufs2_daddr_t *)bp->b_data; + } nblocks = btodb(fs->fs_bsize); for (i = NINDIR(fs) - 1; i >= 0; i--) { - if ((nb = bap[i]) == 0) + if (ufs1fmt) + nb = bap1[i]; + else + nb = bap2[i]; + if (nb == 0) continue; if (level != 0) { if ((error = indir_trunc(freeblks, fsbtodb(fs, nb), @@ -2449,7 +2475,7 @@ softdep_setup_directory_add(bp, dp, diroffset, newinum, newdirbp, isnewblk) struct buf *bp; /* buffer containing directory block */ struct inode *dp; /* inode for directory */ off_t diroffset; /* offset of new entry in directory */ - long newinum; /* inode referenced by new directory entry */ + ino_t newinum; /* inode referenced by new directory entry */ struct buf *newdirbp; /* non-NULL => contents of new mkdir */ int isnewblk; /* entry is in a newly allocated block */ { @@ -2868,7 +2894,7 @@ softdep_setup_directory_change(bp, dp, ip, newinum, isrmdir) struct buf *bp; /* buffer containing directory block */ struct inode *dp; /* inode for the directory being modified */ struct inode *ip; /* inode for directory entry being removed */ - long newinum; /* new inode number for changed entry */ + ino_t newinum; /* new inode number for changed entry */ int isrmdir; /* indicates if doing RMDIR */ { int offset; @@ -3028,7 +3054,7 @@ softdep_releasefile(ip) if ((inodedep_lookup(ip->i_fs, ip->i_number, 0, &inodedep))) inodedep->id_state |= SPACECOUNTED; FREE_LOCK(&lk); - ip->i_fs->fs_pendingblocks += ip->i_blocks; + ip->i_fs->fs_pendingblocks += DIP(ip, i_blocks); ip->i_fs->fs_pendinginodes += 1; ip->i_flag |= IN_SPACECOUNTED; } @@ -3066,6 +3092,7 @@ handle_workitem_remove(dirrem, xp) */ if ((dirrem->dm_state & RMDIR) == 0) { ip->i_nlink--; + DIP(ip, i_nlink) = ip->i_nlink; ip->i_flag |= IN_CHANGE; if (ip->i_nlink < ip->i_effnlink) { FREE_LOCK(&lk); @@ -3086,6 +3113,7 @@ handle_workitem_remove(dirrem, xp) * the parent decremented to account for the loss of "..". */ ip->i_nlink -= 2; + DIP(ip, i_nlink) = ip->i_nlink; ip->i_flag |= IN_CHANGE; if (ip->i_nlink < ip->i_effnlink) { FREE_LOCK(&lk); @@ -3193,6 +3221,7 @@ softdep_disk_io_initiation(bp) { struct worklist *wk, *nextwk; struct indirdep *indirdep; + struct inodedep *inodedep; /* * We only care about write operations. There should never @@ -3212,7 +3241,11 @@ softdep_disk_io_initiation(bp) continue; case D_INODEDEP: - initiate_write_inodeblock(WK_INODEDEP(wk), bp); + inodedep = WK_INODEDEP(wk); + if (inodedep->id_fs->fs_magic == FS_UFS1_MAGIC) + initiate_write_inodeblock_ufs1(inodedep, bp); + else + initiate_write_inodeblock_ufs2(inodedep, bp); continue; case D_INDIRDEP: @@ -3309,39 +3342,43 @@ initiate_write_filepage(pagedep, bp) } /* + * Version of initiate_write_inodeblock that handles UFS1 dinodes. + * Note that any bug fixes made to this routine must be done in the + * version found below. + * * Called from within the procedure above to deal with unsatisfied * allocation dependencies in an inodeblock. The buffer must be * locked, thus, no I/O completion operations can occur while we * are manipulating its associated dependencies. */ static void -initiate_write_inodeblock(inodedep, bp) +initiate_write_inodeblock_ufs1(inodedep, bp) struct inodedep *inodedep; struct buf *bp; /* The inode block */ { struct allocdirect *adp, *lastadp; - struct dinode *dp; + struct ufs1_dinode *dp; struct fs *fs; - ufs_lbn_t prevlbn = 0; - int i, deplist; + ufs_lbn_t i, prevlbn = 0; + int deplist; if (inodedep->id_state & IOSTARTED) - panic("initiate_write_inodeblock: already started"); + panic("initiate_write_inodeblock_ufs1: already started"); inodedep->id_state |= IOSTARTED; fs = inodedep->id_fs; - dp = (struct dinode *)bp->b_data + + dp = (struct ufs1_dinode *)bp->b_data + ino_to_fsbo(fs, inodedep->id_ino); /* * If the bitmap is not yet written, then the allocated * inode cannot be written to disk. */ if ((inodedep->id_state & DEPCOMPLETE) == 0) { - if (inodedep->id_savedino != NULL) - panic("initiate_write_inodeblock: already doing I/O"); - MALLOC(inodedep->id_savedino, struct dinode *, - sizeof(struct dinode), M_INODEDEP, M_SOFTDEP_FLAGS); - *inodedep->id_savedino = *dp; - bzero((caddr_t)dp, sizeof(struct dinode)); + if (inodedep->id_savedino1 != NULL) + panic("initiate_write_inodeblock_ufs1: I/O underway"); + MALLOC(inodedep->id_savedino1, struct ufs1_dinode *, + sizeof(struct ufs1_dinode), M_INODEDEP, M_SOFTDEP_FLAGS); + *inodedep->id_savedino1 = *dp; + bzero((caddr_t)dp, sizeof(struct ufs1_dinode)); return; } /* @@ -3365,16 +3402,172 @@ initiate_write_inodeblock(inodedep, bp) if (adp->ad_lbn < NDADDR && dp->di_db[adp->ad_lbn] != adp->ad_newblkno) { FREE_LOCK(&lk); - panic("%s: direct pointer #%ld mismatch %d != %d", - "softdep_write_inodeblock", adp->ad_lbn, - dp->di_db[adp->ad_lbn], adp->ad_newblkno); + panic("%s: direct pointer #%lld mismatch %d != %lld", + "softdep_write_inodeblock", + (intmax_t)adp->ad_lbn, + dp->di_db[adp->ad_lbn], + (intmax_t)adp->ad_newblkno); } if (adp->ad_lbn >= NDADDR && dp->di_ib[adp->ad_lbn - NDADDR] != adp->ad_newblkno) { FREE_LOCK(&lk); - panic("%s: indirect pointer #%ld mismatch %d != %d", - "softdep_write_inodeblock", adp->ad_lbn - NDADDR, - dp->di_ib[adp->ad_lbn - NDADDR], adp->ad_newblkno); + panic("%s: indirect pointer #%lld mismatch %d != %lld", + "softdep_write_inodeblock", + (intmax_t)adp->ad_lbn - NDADDR, + dp->di_ib[adp->ad_lbn - NDADDR], + (intmax_t)adp->ad_newblkno); + } + deplist |= 1 << adp->ad_lbn; + if ((adp->ad_state & ATTACHED) == 0) { + FREE_LOCK(&lk); + panic("softdep_write_inodeblock: Unknown state 0x%x", + adp->ad_state); + } +#endif /* DIAGNOSTIC */ + adp->ad_state &= ~ATTACHED; + adp->ad_state |= UNDONE; + } + /* + * The on-disk inode cannot claim to be any larger than the last + * fragment that has been written. Otherwise, the on-disk inode + * might have fragments that were not the last block in the file + * which would corrupt the filesystem. + */ + for (lastadp = NULL, adp = TAILQ_FIRST(&inodedep->id_inoupdt); adp; + lastadp = adp, adp = TAILQ_NEXT(adp, ad_next)) { + if (adp->ad_lbn >= NDADDR) + break; + dp->di_db[adp->ad_lbn] = adp->ad_oldblkno; + /* keep going until hitting a rollback to a frag */ + if (adp->ad_oldsize == 0 || adp->ad_oldsize == fs->fs_bsize) + continue; + dp->di_size = fs->fs_bsize * adp->ad_lbn + adp->ad_oldsize; + for (i = adp->ad_lbn + 1; i < NDADDR; i++) { +#ifdef DIAGNOSTIC + if (dp->di_db[i] != 0 && (deplist & (1 << i)) == 0) { + FREE_LOCK(&lk); + panic("softdep_write_inodeblock: lost dep1"); + } +#endif /* DIAGNOSTIC */ + dp->di_db[i] = 0; + } + for (i = 0; i < NIADDR; i++) { +#ifdef DIAGNOSTIC + if (dp->di_ib[i] != 0 && + (deplist & ((1 << NDADDR) << i)) == 0) { + FREE_LOCK(&lk); + panic("softdep_write_inodeblock: lost dep2"); + } +#endif /* DIAGNOSTIC */ + dp->di_ib[i] = 0; + } + FREE_LOCK(&lk); + return; + } + /* + * If we have zero'ed out the last allocated block of the file, + * roll back the size to the last currently allocated block. + * We know that this last allocated block is a full-sized as + * we already checked for fragments in the loop above. + */ + if (lastadp != NULL && + dp->di_size <= (lastadp->ad_lbn + 1) * fs->fs_bsize) { + for (i = lastadp->ad_lbn; i >= 0; i--) + if (dp->di_db[i] != 0) + break; + dp->di_size = (i + 1) * fs->fs_bsize; + } + /* + * The only dependencies are for indirect blocks. + * + * The file size for indirect block additions is not guaranteed. + * Such a guarantee would be non-trivial to achieve. The conventional + * synchronous write implementation also does not make this guarantee. + * Fsck should catch and fix discrepancies. Arguably, the file size + * can be over-estimated without destroying integrity when the file + * moves into the indirect blocks (i.e., is large). If we want to + * postpone fsck, we are stuck with this argument. + */ + for (; adp; adp = TAILQ_NEXT(adp, ad_next)) + dp->di_ib[adp->ad_lbn - NDADDR] = 0; + FREE_LOCK(&lk); +} + +/* + * Version of initiate_write_inodeblock that handles UFS2 dinodes. + * Note that any bug fixes made to this routine must be done in the + * version found above. + * + * Called from within the procedure above to deal with unsatisfied + * allocation dependencies in an inodeblock. The buffer must be + * locked, thus, no I/O completion operations can occur while we + * are manipulating its associated dependencies. + */ +static void +initiate_write_inodeblock_ufs2(inodedep, bp) + struct inodedep *inodedep; + struct buf *bp; /* The inode block */ +{ + struct allocdirect *adp, *lastadp; + struct ufs2_dinode *dp; + struct fs *fs; + ufs_lbn_t i, prevlbn = 0; + int deplist; + + if (inodedep->id_state & IOSTARTED) + panic("initiate_write_inodeblock_ufs2: already started"); + inodedep->id_state |= IOSTARTED; + fs = inodedep->id_fs; + dp = (struct ufs2_dinode *)bp->b_data + + ino_to_fsbo(fs, inodedep->id_ino); + /* + * If the bitmap is not yet written, then the allocated + * inode cannot be written to disk. + */ + if ((inodedep->id_state & DEPCOMPLETE) == 0) { + if (inodedep->id_savedino2 != NULL) + panic("initiate_write_inodeblock_ufs2: I/O underway"); + MALLOC(inodedep->id_savedino2, struct ufs2_dinode *, + sizeof(struct ufs2_dinode), M_INODEDEP, M_SOFTDEP_FLAGS); + *inodedep->id_savedino2 = *dp; + bzero((caddr_t)dp, sizeof(struct ufs2_dinode)); + return; + } + /* + * If no dependencies, then there is nothing to roll back. + */ + inodedep->id_savedsize = dp->di_size; + if (TAILQ_FIRST(&inodedep->id_inoupdt) == NULL) + return; + /* + * Set the dependencies to busy. + */ + ACQUIRE_LOCK(&lk); + for (deplist = 0, adp = TAILQ_FIRST(&inodedep->id_inoupdt); adp; + adp = TAILQ_NEXT(adp, ad_next)) { +#ifdef DIAGNOSTIC + if (deplist != 0 && prevlbn >= adp->ad_lbn) { + FREE_LOCK(&lk); + panic("softdep_write_inodeblock: lbn order"); + } + prevlbn = adp->ad_lbn; + if (adp->ad_lbn < NDADDR && + dp->di_db[adp->ad_lbn] != adp->ad_newblkno) { + FREE_LOCK(&lk); + panic("%s: direct pointer #%lld mismatch %lld != %lld", + "softdep_write_inodeblock", + (intmax_t)adp->ad_lbn, + (intmax_t)dp->di_db[adp->ad_lbn], + (intmax_t)adp->ad_newblkno); + } + if (adp->ad_lbn >= NDADDR && + dp->di_ib[adp->ad_lbn - NDADDR] != adp->ad_newblkno) { + FREE_LOCK(&lk); + panic("%s indirect pointer #%lld mismatch %lld != %lld", + "softdep_write_inodeblock:", + (intmax_t)adp->ad_lbn - NDADDR, + (intmax_t)dp->di_ib[adp->ad_lbn - NDADDR], + (intmax_t)adp->ad_newblkno); } deplist |= 1 << adp->ad_lbn; if ((adp->ad_state & ATTACHED) == 0) { @@ -3683,8 +3876,12 @@ handle_allocindir_partdone(aip) LIST_INSERT_HEAD(&indirdep->ir_donehd, aip, ai_next); return; } - ((ufs_daddr_t *)indirdep->ir_savebp->b_data)[aip->ai_offset] = - aip->ai_newblkno; + if (indirdep->ir_state & UFS1FMT) + ((ufs1_daddr_t *)indirdep->ir_savebp->b_data)[aip->ai_offset] = + aip->ai_newblkno; + else + ((ufs2_daddr_t *)indirdep->ir_savebp->b_data)[aip->ai_offset] = + aip->ai_newblkno; LIST_REMOVE(aip, ai_next); if (aip->ai_freefrag != NULL) add_to_worklist(&aip->ai_freefrag->ff_list); @@ -3704,8 +3901,9 @@ handle_written_inodeblock(inodedep, bp) { struct worklist *wk, *filefree; struct allocdirect *adp, *nextadp; - struct dinode *dp; - int hadchanges; + struct ufs1_dinode *dp1 = NULL; + struct ufs2_dinode *dp2 = NULL; + int hadchanges, fstype; if ((inodedep->id_state & IOSTARTED) == 0) { lk.lkt_held = NOHOLDER; @@ -3713,8 +3911,15 @@ handle_written_inodeblock(inodedep, bp) } inodedep->id_state &= ~IOSTARTED; inodedep->id_state |= COMPLETE; - dp = (struct dinode *)bp->b_data + - ino_to_fsbo(inodedep->id_fs, inodedep->id_ino); + if (inodedep->id_fs->fs_magic == FS_UFS1_MAGIC) { + fstype = UFS1; + dp1 = (struct ufs1_dinode *)bp->b_data + + ino_to_fsbo(inodedep->id_fs, inodedep->id_ino); + } else { + fstype = UFS2; + dp2 = (struct ufs2_dinode *)bp->b_data + + ino_to_fsbo(inodedep->id_fs, inodedep->id_ino); + } /* * If we had to rollback the inode allocation because of * bitmaps being incomplete, then simply restore it. @@ -3722,10 +3927,13 @@ handle_written_inodeblock(inodedep, bp) * all associated dependencies have been cleared and the * corresponding updates written to disk. */ - if (inodedep->id_savedino != NULL) { - *dp = *inodedep->id_savedino; - FREE(inodedep->id_savedino, M_INODEDEP); - inodedep->id_savedino = NULL; + if (inodedep->id_savedino1 != NULL) { + if (fstype == UFS1) + *dp1 = *inodedep->id_savedino1; + else + *dp2 = *inodedep->id_savedino2; + FREE(inodedep->id_savedino1, M_INODEDEP); + inodedep->id_savedino1 = NULL; if ((bp->b_flags & B_DELWRI) == 0) stat_inode_bitmap++; bdirty(bp); @@ -3742,24 +3950,55 @@ handle_written_inodeblock(inodedep, bp) lk.lkt_held = NOHOLDER; panic("handle_written_inodeblock: new entry"); } - if (adp->ad_lbn < NDADDR) { - if (dp->di_db[adp->ad_lbn] != adp->ad_oldblkno) { - lk.lkt_held = NOHOLDER; - panic("%s: %s #%ld mismatch %d != %d", - "handle_written_inodeblock", - "direct pointer", adp->ad_lbn, - dp->di_db[adp->ad_lbn], adp->ad_oldblkno); + if (fstype == UFS1) { + if (adp->ad_lbn < NDADDR) { + if (dp1->di_db[adp->ad_lbn]!=adp->ad_oldblkno) { + lk.lkt_held = NOHOLDER; + panic("%s %s #%lld mismatch %d != %lld", + "handle_written_inodeblock:", + "direct pointer", + (intmax_t)adp->ad_lbn, + dp1->di_db[adp->ad_lbn], + (intmax_t)adp->ad_oldblkno); + } + dp1->di_db[adp->ad_lbn] = adp->ad_newblkno; + } else { + if (dp1->di_ib[adp->ad_lbn - NDADDR] != 0) { + lk.lkt_held = NOHOLDER; + panic("%s: %s #%lld allocated as %d", + "handle_written_inodeblock", + "indirect pointer", + (intmax_t)adp->ad_lbn - NDADDR, + dp1->di_ib[adp->ad_lbn - NDADDR]); + } + dp1->di_ib[adp->ad_lbn - NDADDR] = + adp->ad_newblkno; } - dp->di_db[adp->ad_lbn] = adp->ad_newblkno; } else { - if (dp->di_ib[adp->ad_lbn - NDADDR] != 0) { - lk.lkt_held = NOHOLDER; - panic("%s: %s #%ld allocated as %d", - "handle_written_inodeblock", - "indirect pointer", adp->ad_lbn - NDADDR, - dp->di_ib[adp->ad_lbn - NDADDR]); + if (adp->ad_lbn < NDADDR) { + if (dp2->di_db[adp->ad_lbn]!=adp->ad_oldblkno) { + lk.lkt_held = NOHOLDER; + panic("%s: %s #%lld %s %lld != %lld", + "handle_written_inodeblock", + "direct pointer", + (intmax_t)adp->ad_lbn, "mismatch", + (intmax_t)dp2->di_db[adp->ad_lbn], + (intmax_t)adp->ad_oldblkno); + } + dp2->di_db[adp->ad_lbn] = adp->ad_newblkno; + } else { + if (dp2->di_ib[adp->ad_lbn - NDADDR] != 0) { + lk.lkt_held = NOHOLDER; + panic("%s: %s #%lld allocated as %lld", + "handle_written_inodeblock", + "indirect pointer", + (intmax_t)adp->ad_lbn - NDADDR, + (intmax_t) + dp2->di_ib[adp->ad_lbn - NDADDR]); + } + dp2->di_ib[adp->ad_lbn - NDADDR] = + adp->ad_newblkno; } - dp->di_ib[adp->ad_lbn - NDADDR] = adp->ad_newblkno; } adp->ad_state &= ~UNDONE; adp->ad_state |= ATTACHED; @@ -3774,9 +4013,16 @@ handle_written_inodeblock(inodedep, bp) lk.lkt_held = NOHOLDER; panic("handle_written_inodeblock: bad size"); } - if (dp->di_size != inodedep->id_savedsize) { - dp->di_size = inodedep->id_savedsize; - hadchanges = 1; + if (fstype == UFS1) { + if (dp1->di_size != inodedep->id_savedsize) { + dp1->di_size = inodedep->id_savedsize; + hadchanges = 1; + } + } else { + if (dp2->di_size != inodedep->id_savedsize) { + dp2->di_size = inodedep->id_savedsize; + hadchanges = 1; + } } inodedep->id_savedsize = -1; /* @@ -4859,7 +5105,8 @@ softdep_request_cleanup(fs, vp) struct fs *fs; struct vnode *vp; { - long starttime, needed; + long starttime; + ufs2_daddr_t needed; needed = fs->fs_cstotal.cs_nbfree + fs->fs_contigsumsize; starttime = time_second + tickdelay; diff --git a/sys/ufs/ffs/ffs_softdep_stub.c b/sys/ufs/ffs/ffs_softdep_stub.c index 36585f8..4bf0189 100644 --- a/sys/ufs/ffs/ffs_softdep_stub.c +++ b/sys/ufs/ffs/ffs_softdep_stub.c @@ -96,7 +96,7 @@ void softdep_setup_blkmapdep(bp, fs, newblkno) struct buf *bp; struct fs *fs; - ufs_daddr_t newblkno; + ufs2_daddr_t newblkno; { panic("softdep_setup_blkmapdep called"); @@ -106,8 +106,8 @@ void softdep_setup_allocdirect(ip, lbn, newblkno, oldblkno, newsize, oldsize, bp) struct inode *ip; ufs_lbn_t lbn; - ufs_daddr_t newblkno; - ufs_daddr_t oldblkno; + ufs2_daddr_t newblkno; + ufs2_daddr_t oldblkno; long newsize; long oldsize; struct buf *bp; @@ -122,8 +122,8 @@ softdep_setup_allocindir_page(ip, lbn, bp, ptrno, newblkno, oldblkno, nbp) ufs_lbn_t lbn; struct buf *bp; int ptrno; - ufs_daddr_t newblkno; - ufs_daddr_t oldblkno; + ufs2_daddr_t newblkno; + ufs2_daddr_t oldblkno; struct buf *nbp; { @@ -136,7 +136,7 @@ softdep_setup_allocindir_meta(nbp, ip, bp, ptrno, newblkno) struct inode *ip; struct buf *bp; int ptrno; - ufs_daddr_t newblkno; + ufs2_daddr_t newblkno; { panic("softdep_setup_allocindir_meta called"); diff --git a/sys/ufs/ffs/ffs_subr.c b/sys/ufs/ffs/ffs_subr.c index f484090..773a8d3 100644 --- a/sys/ufs/ffs/ffs_subr.c +++ b/sys/ufs/ffs/ffs_subr.c @@ -35,15 +35,18 @@ */ #include <sys/param.h> -#include <ufs/ffs/fs.h> #ifndef _KERNEL #include <ufs/ufs/dinode.h> +#include <ufs/ffs/fs.h> #else #include "opt_ddb.h" #include <sys/systm.h> +#include <sys/stdint.h> #include <sys/lock.h> +#include <sys/malloc.h> +#include <sys/mount.h> #include <sys/vnode.h> #include <sys/bio.h> #include <sys/buf.h> @@ -51,7 +54,11 @@ #include <ufs/ufs/quota.h> #include <ufs/ufs/inode.h> +#include <ufs/ufs/extattr.h> +#include <ufs/ufs/ufsmount.h> +#include <ufs/ufs/ufs_extern.h> #include <ufs/ffs/ffs_extern.h> +#include <ufs/ffs/fs.h> #ifdef DDB void ffs_checkoverlap(struct buf *, struct inode *); @@ -72,7 +79,7 @@ ffs_blkatoff(vp, offset, res, bpp) struct inode *ip; struct fs *fs; struct buf *bp; - ufs_daddr_t lbn; + ufs_lbn_t lbn; int bsize, error; ip = VTOI(vp); @@ -91,7 +98,49 @@ ffs_blkatoff(vp, offset, res, bpp) *bpp = bp; return (0); } -#endif + +/* + * Load up the contents of an inode and copy the appropriate pieces + * to the incore copy. + */ +void +ffs_load_inode(bp, ip, mtype, fs, ino) + struct buf *bp; + struct inode *ip; + struct malloc_type *mtype; + struct fs *fs; + ino_t ino; +{ + + if (ip->i_ump->um_fstype == UFS1) { + if (mtype != NULL) + MALLOC(ip->i_din1, struct ufs1_dinode *, + sizeof(struct ufs1_dinode), mtype, M_WAITOK); + *ip->i_din1 = + *((struct ufs1_dinode *)bp->b_data + ino_to_fsbo(fs, ino)); + ip->i_mode = ip->i_din1->di_mode; + ip->i_nlink = ip->i_din1->di_nlink; + ip->i_size = ip->i_din1->di_size; + ip->i_flags = ip->i_din1->di_flags; + ip->i_gen = ip->i_din1->di_gen; + ip->i_uid = ip->i_din1->di_uid; + ip->i_gid = ip->i_din1->di_gid; + } else { + if (mtype != NULL) + MALLOC(ip->i_din2, struct ufs2_dinode *, + sizeof(struct ufs2_dinode), mtype, M_WAITOK); + *ip->i_din2 = + *((struct ufs2_dinode *)bp->b_data + ino_to_fsbo(fs, ino)); + ip->i_mode = ip->i_din2->di_mode; + ip->i_nlink = ip->i_din2->di_nlink; + ip->i_size = ip->i_din2->di_size; + ip->i_flags = ip->i_din2->di_flags; + ip->i_gen = ip->i_din2->di_gen; + ip->i_uid = ip->i_din2->di_uid; + ip->i_gid = ip->i_din2->di_gid; + } +} +#endif /* KERNEL */ /* * Update the frsum fields to reflect addition or deletion @@ -135,7 +184,7 @@ ffs_checkoverlap(bp, ip) struct inode *ip; { struct buf *ebp, *ep; - ufs_daddr_t start, last; + ufs2_daddr_t start, last; struct vnode *vp; ebp = &buf[nbuf]; @@ -151,9 +200,9 @@ ffs_checkoverlap(bp, ip) ep->b_blkno + btodb(ep->b_bcount) <= start) continue; vprint("Disk overlap", vp); - (void)printf("\tstart %lu, end %lu overlap start %lu, end %lu\n", - (u_long)start, (u_long)last, (u_long)ep->b_blkno, - (u_long)(ep->b_blkno + btodb(ep->b_bcount) - 1)); + printf("\tstart %llu, end %llu overlap start %llu, end %llu\n", + (intmax_t)start, (intmax_t)last, (intmax_t)ep->b_blkno, + (intmax_t)(ep->b_blkno + btodb(ep->b_bcount) - 1)); panic("ffs_checkoverlap: Disk buffer overlap"); } } @@ -168,7 +217,7 @@ int ffs_isblock(fs, cp, h) struct fs *fs; unsigned char *cp; - ufs_daddr_t h; + ufs1_daddr_t h; { unsigned char mask; @@ -197,7 +246,7 @@ int ffs_isfreeblock(fs, cp, h) struct fs *fs; unsigned char *cp; - ufs_daddr_t h; + ufs1_daddr_t h; { switch ((int)fs->fs_frag) { @@ -222,7 +271,7 @@ void ffs_clrblock(fs, cp, h) struct fs *fs; u_char *cp; - ufs_daddr_t h; + ufs1_daddr_t h; { switch ((int)fs->fs_frag) { @@ -250,7 +299,7 @@ void ffs_setblock(fs, cp, h) struct fs *fs; unsigned char *cp; - ufs_daddr_t h; + ufs1_daddr_t h; { switch ((int)fs->fs_frag) { diff --git a/sys/ufs/ffs/ffs_tables.c b/sys/ufs/ffs/ffs_tables.c index 1ffae90..b86a9ac 100644 --- a/sys/ufs/ffs/ffs_tables.c +++ b/sys/ufs/ffs/ffs_tables.c @@ -35,6 +35,7 @@ */ #include <sys/param.h> +#include <ufs/ufs/dinode.h> #include <ufs/ffs/fs.h> /* diff --git a/sys/ufs/ffs/ffs_vfsops.c b/sys/ufs/ffs/ffs_vfsops.c index ed52815..53a1ea5 100644 --- a/sys/ufs/ffs/ffs_vfsops.c +++ b/sys/ufs/ffs/ffs_vfsops.c @@ -39,6 +39,7 @@ #include <sys/param.h> #include <sys/systm.h> +#include <sys/stdint.h> #include <sys/namei.h> #include <sys/proc.h> #include <sys/kernel.h> @@ -67,8 +68,10 @@ static MALLOC_DEFINE(M_FFSNODE, "FFS node", "FFS vnode private part"); static int ffs_sbupdate(struct ufsmount *, int); -int ffs_reload(struct mount *,struct ucred *,struct thread *); -static int ffs_oldfscompat(struct fs *); + int ffs_reload(struct mount *,struct ucred *,struct thread *); +static void ffs_oldfscompat_read(struct fs *, struct ufsmount *, + ufs2_daddr_t); +static void ffs_oldfscompat_write(struct fs *, struct ufsmount *); static int ffs_init(struct vfsconf *); static struct vfsops ufs_vfsops = { @@ -139,8 +142,8 @@ ffs_mount(mp, path, data, ndp, td) struct nameidata *ndp; /* mount point credentials*/ struct thread *td; /* process requesting mount*/ { - size_t size; - struct vnode *devvp; + size_t size; + struct vnode *devvp; struct ufs_args args; struct ufsmount *ump = 0; struct fs *fs; @@ -201,8 +204,9 @@ ffs_mount(mp, path, data, ndp, td) } if (fs->fs_pendingblocks != 0 || fs->fs_pendinginodes != 0) { - printf("%s: update error: blocks %d files %d\n", - fs->fs_fsmnt, fs->fs_pendingblocks, + printf("%s: %s: blocks %lld files %d\n", + fs->fs_fsmnt, "update error", + (intmax_t)fs->fs_pendingblocks, fs->fs_pendinginodes); fs->fs_pendingblocks = 0; fs->fs_pendinginodes = 0; @@ -384,9 +388,9 @@ ffs_reload(mp, cred, td) struct buf *bp; struct fs *fs, *newfs; dev_t dev; + ufs2_daddr_t sblockloc; int i, blks, size, error; int32_t *lp; - u_int sectorsize; if ((mp->mnt_flag & MNT_RDONLY) == 0) return (EINVAL); @@ -416,20 +420,18 @@ ffs_reload(mp, cred, td) /* * Step 2: re-read superblock from disk. */ - if (VOP_IOCTL(devvp, DIOCGSECTORSIZE, (caddr_t)§orsize, - FREAD, NOCRED, td) != 0) - size = DEV_BSIZE; - else - size = sectorsize; - if ((error = bread(devvp, (ufs_daddr_t)(SBOFF/size), SBSIZE, NOCRED,&bp)) != 0) + fs = VFSTOUFS(mp)->um_fs; + if ((error = bread(devvp, fsbtodb(fs, fs->fs_sblockloc), fs->fs_sbsize, + NOCRED, &bp)) != 0) return (error); newfs = (struct fs *)bp->b_data; - if (newfs->fs_magic != FS_MAGIC || newfs->fs_bsize > MAXBSIZE || - newfs->fs_bsize < sizeof(struct fs)) { + if ((newfs->fs_magic != FS_UFS1_MAGIC && + newfs->fs_magic != FS_UFS2_MAGIC) || + newfs->fs_bsize > MAXBSIZE || + newfs->fs_bsize < sizeof(struct fs)) { brelse(bp); return (EIO); /* XXX needs translation */ } - fs = VFSTOUFS(mp)->um_fs; /* * Copy pointer fields back into superblock before copying in XXX * new superblock. These should really be in the ufsmount. XXX @@ -439,20 +441,15 @@ ffs_reload(mp, cred, td) newfs->fs_maxcluster = fs->fs_maxcluster; newfs->fs_contigdirs = fs->fs_contigdirs; newfs->fs_active = fs->fs_active; + sblockloc = fs->fs_sblockloc; bcopy(newfs, fs, (u_int)fs->fs_sbsize); - if (fs->fs_sbsize < SBSIZE) - bp->b_flags |= B_INVAL | B_NOCACHE; brelse(bp); mp->mnt_maxsymlinklen = fs->fs_maxsymlinklen; - ffs_oldfscompat(fs); - /* An old fsck may have zeroed these fields, so recheck them. */ - if (fs->fs_avgfilesize <= 0) /* XXX */ - fs->fs_avgfilesize = AVFILESIZ; /* XXX */ - if (fs->fs_avgfpdir <= 0) /* XXX */ - fs->fs_avgfpdir = AFPDIR; /* XXX */ + ffs_oldfscompat_read(fs, VFSTOUFS(mp), sblockloc); if (fs->fs_pendingblocks != 0 || fs->fs_pendinginodes != 0) { - printf("%s: reload pending error: blocks %d files %d\n", - fs->fs_fsmnt, fs->fs_pendingblocks, fs->fs_pendinginodes); + printf("%s: reload pending error: blocks %lld files %d\n", + fs->fs_fsmnt, (intmax_t)fs->fs_pendingblocks, + fs->fs_pendinginodes); fs->fs_pendingblocks = 0; fs->fs_pendinginodes = 0; } @@ -517,8 +514,7 @@ loop: vput(vp); return (error); } - ip->i_din = *((struct dinode *)bp->b_data + - ino_to_fsbo(fs, ip->i_number)); + ffs_load_inode(bp, ip, NULL, fs, ip->i_number); ip->i_effnlink = ip->i_nlink; brelse(bp); vput(vp); @@ -528,9 +524,10 @@ loop: return (0); } -#include <sys/sysctl.h> -int bigcgs = 0; -SYSCTL_INT(_debug, OID_AUTO, bigcgs, CTLFLAG_RW, &bigcgs, 0, ""); +/* + * Possible superblock locations ordered from most to least likely. + */ +static int sblock_try[] = SBLOCKSEARCH; /* * Common code for mount and mountroot @@ -547,10 +544,10 @@ ffs_mountfs(devvp, mp, td, malloctype) struct fs *fs; dev_t dev; void *space; + ufs2_daddr_t sblockloc; int error, i, blks, size, ronly; int32_t *lp; struct ucred *cred; - u_int64_t maxfilesize; /* XXX */ size_t strsize; int ncount; u_int sectorsize; @@ -617,15 +614,32 @@ ffs_mountfs(devvp, mp, td, malloctype) bp = NULL; ump = NULL; - if ((error = bread(devvp, SBLOCK, SBSIZE, cred, &bp)) != 0) - goto out; - fs = (struct fs *)bp->b_data; - if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE || - fs->fs_bsize < sizeof(struct fs)) { + fs = NULL; + sblockloc = 0; + /* + * Try reading the superblock in each of its possible locations. + */ + for (i = 0; sblock_try[i] != -1; i++) { + if ((error = bread(devvp, sblock_try[i] / size, SBLOCKSIZE, + cred, &bp)) != 0) + goto out; + fs = (struct fs *)bp->b_data; + sblockloc = numfrags(fs, sblock_try[i]); + if ((fs->fs_magic == FS_UFS1_MAGIC || + (fs->fs_magic == FS_UFS2_MAGIC && + fs->fs_sblockloc == sblockloc)) && + fs->fs_bsize <= MAXBSIZE && + fs->fs_bsize >= sizeof(struct fs)) + break; + brelse(bp); + bp = NULL; + } + if (sblock_try[i] == -1) { error = EINVAL; /* XXX needs translation */ goto out; } fs->fs_fmod = 0; + fs->fs_flags &= ~FS_INDEXDIRS; /* no support for directory indicies */ fs->fs_flags &= ~FS_UNCLEAN; if (fs->fs_clean == 0) { fs->fs_flags |= FS_UNCLEAN; @@ -642,40 +656,45 @@ ffs_mountfs(devvp, mp, td, malloctype) error = EPERM; goto out; } - if (fs->fs_pendingblocks != 0 || fs->fs_pendinginodes != 0) { - printf("%s: lost blocks %d files %d\n", fs->fs_fsmnt, - fs->fs_pendingblocks, fs->fs_pendinginodes); + if ((fs->fs_pendingblocks != 0 || fs->fs_pendinginodes != 0) && + (mp->mnt_flag & MNT_FORCE)) { + printf("%s: lost blocks %lld files %d\n", fs->fs_fsmnt, + (intmax_t)fs->fs_pendingblocks, + fs->fs_pendinginodes); fs->fs_pendingblocks = 0; fs->fs_pendinginodes = 0; } } if (fs->fs_pendingblocks != 0 || fs->fs_pendinginodes != 0) { - printf("%s: mount pending error: blocks %d files %d\n", - fs->fs_fsmnt, fs->fs_pendingblocks, fs->fs_pendinginodes); + printf("%s: mount pending error: blocks %lld files %d\n", + fs->fs_fsmnt, (intmax_t)fs->fs_pendingblocks, + fs->fs_pendinginodes); fs->fs_pendingblocks = 0; fs->fs_pendinginodes = 0; } - /* XXX updating 4.2 FFS superblocks trashes rotational layout tables */ - if (fs->fs_postblformat == FS_42POSTBLFMT && !ronly) { - error = EROFS; /* needs translation */ - goto out; - } ump = malloc(sizeof *ump, M_UFSMNT, M_WAITOK | M_ZERO); ump->um_malloctype = malloctype; ump->um_fs = malloc((u_long)fs->fs_sbsize, M_UFSMNT, M_WAITOK); + if (fs->fs_magic == FS_UFS1_MAGIC) { + ump->um_fstype = UFS1; + ump->um_balloc = ffs_balloc_ufs1; + } else { + ump->um_fstype = UFS2; + ump->um_balloc = ffs_balloc_ufs2; + } ump->um_blkatoff = ffs_blkatoff; ump->um_truncate = ffs_truncate; ump->um_update = ffs_update; ump->um_valloc = ffs_valloc; ump->um_vfree = ffs_vfree; - ump->um_balloc = ffs_balloc; bcopy(bp->b_data, ump->um_fs, (u_int)fs->fs_sbsize); - if (fs->fs_sbsize < SBSIZE) + if (fs->fs_sbsize < SBLOCKSIZE) bp->b_flags |= B_INVAL | B_NOCACHE; brelse(bp); bp = NULL; fs = ump->um_fs; + ffs_oldfscompat_read(fs, ump, sblockloc); fs->fs_ronly = ronly; size = fs->fs_cssize; blks = howmany(size, fs->fs_fsize); @@ -708,11 +727,6 @@ ffs_mountfs(devvp, mp, td, malloctype) fs->fs_contigdirs = (u_int8_t *)space; bzero(fs->fs_contigdirs, size); fs->fs_active = NULL; - /* Compatibility for old filesystems XXX */ - if (fs->fs_avgfilesize <= 0) /* XXX */ - fs->fs_avgfilesize = AVFILESIZ; /* XXX */ - if (fs->fs_avgfpdir <= 0) /* XXX */ - fs->fs_avgfpdir = AFPDIR; /* XXX */ mp->mnt_data = (qaddr_t)ump; mp->mnt_stat.f_fsid.val[0] = fs->fs_id[0]; mp->mnt_stat.f_fsid.val[1] = fs->fs_id[1]; @@ -733,7 +747,6 @@ ffs_mountfs(devvp, mp, td, malloctype) ufs_extattr_uepm_init(&ump->um_extattr); #endif devvp->v_rdev->si_mountpoint = mp; - ffs_oldfscompat(fs); /* * Set FS local "last mounted on" information (NULL pad) @@ -753,15 +766,6 @@ ffs_mountfs(devvp, mp, td, malloctype) mp->mnt_time = fs->fs_time; } - ump->um_savedmaxfilesize = fs->fs_maxfilesize; /* XXX */ - maxfilesize = (u_int64_t)0x40000000 * fs->fs_bsize - 1; /* XXX */ - if (fs->fs_maxfilesize > maxfilesize) /* XXX */ - fs->fs_maxfilesize = maxfilesize; /* XXX */ - if (bigcgs) { - if (fs->fs_sparecon[0] <= 0) - fs->fs_sparecon[0] = fs->fs_cgsize; - fs->fs_cgsize = fs->fs_bsize; - } if (ronly == 0) { if ((fs->fs_flags & FS_DOSOFTDEP) && (error = softdep_mount(devvp, mp, fs, cred)) != 0) { @@ -808,36 +812,90 @@ out: return (error); } +#include <sys/sysctl.h> +int bigcgs = 0; +SYSCTL_INT(_debug, OID_AUTO, bigcgs, CTLFLAG_RW, &bigcgs, 0, ""); + /* - * Sanity checks for old filesystems. + * Sanity checks for loading old filesystem superblocks. + * See ffs_oldfscompat_write below for unwound actions. * - * XXX - goes away some day. + * XXX - Parts get retired eventually. + * Unfortunately new bits get added. */ -static int -ffs_oldfscompat(fs) +static void +ffs_oldfscompat_read(fs, ump, sblockloc) struct fs *fs; + struct ufsmount *ump; + ufs2_daddr_t sblockloc; { + off_t maxfilesize; - fs->fs_npsect = max(fs->fs_npsect, fs->fs_nsect); /* XXX */ - fs->fs_interleave = max(fs->fs_interleave, 1); /* XXX */ - if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */ - fs->fs_nrpos = 8; /* XXX */ - if (fs->fs_inodefmt < FS_44INODEFMT) { /* XXX */ -#if 0 - int i; /* XXX */ - u_int64_t sizepb = fs->fs_bsize; /* XXX */ - /* XXX */ - fs->fs_maxfilesize = fs->fs_bsize * NDADDR - 1; /* XXX */ - for (i = 0; i < NIADDR; i++) { /* XXX */ - sizepb *= NINDIR(fs); /* XXX */ - fs->fs_maxfilesize += sizepb; /* XXX */ - } /* XXX */ -#endif + /* + * If not yet done, update UFS1 superblock with new wider fields. + */ + if (fs->fs_magic == FS_UFS1_MAGIC && + fs->fs_sblockloc != sblockloc) { + fs->fs_maxbsize = fs->fs_bsize; + fs->fs_sblockloc = sblockloc; + fs->fs_time = fs->fs_old_time; + fs->fs_size = fs->fs_old_size; + fs->fs_dsize = fs->fs_old_dsize; + fs->fs_csaddr = fs->fs_old_csaddr; + fs->fs_cstotal.cs_ndir = fs->fs_old_cstotal.cs_ndir; + fs->fs_cstotal.cs_nbfree = fs->fs_old_cstotal.cs_nbfree; + fs->fs_cstotal.cs_nifree = fs->fs_old_cstotal.cs_nifree; + fs->fs_cstotal.cs_nffree = fs->fs_old_cstotal.cs_nffree; + } + if (fs->fs_magic == FS_UFS1_MAGIC && + fs->fs_old_inodefmt < FS_44INODEFMT) { fs->fs_maxfilesize = (u_quad_t) 1LL << 39; - fs->fs_qbmask = ~fs->fs_bmask; /* XXX */ - fs->fs_qfmask = ~fs->fs_fmask; /* XXX */ - } /* XXX */ - return (0); + fs->fs_qbmask = ~fs->fs_bmask; + fs->fs_qfmask = ~fs->fs_fmask; + } + ump->um_savedmaxfilesize = fs->fs_maxfilesize; + maxfilesize = (u_int64_t)0x40000000 * fs->fs_bsize - 1; + if (fs->fs_maxfilesize > maxfilesize) + fs->fs_maxfilesize = maxfilesize; + /* Compatibility for old filesystems */ + if (fs->fs_avgfilesize <= 0) + fs->fs_avgfilesize = AVFILESIZ; + if (fs->fs_avgfpdir <= 0) + fs->fs_avgfpdir = AFPDIR; + if (bigcgs) { + fs->fs_save_cgsize = fs->fs_cgsize; + fs->fs_cgsize = fs->fs_bsize; + } +} + +/* + * Unwinding superblock updates for old filesystems. + * See ffs_oldfscompat_read above for details. + * + * XXX - Parts get retired eventually. + * Unfortunately new bits get added. + */ +static void +ffs_oldfscompat_write(fs, ump) + struct fs *fs; + struct ufsmount *ump; +{ + + /* + * Copy back UFS2 updated fields that UFS1 inspects. + */ + if (fs->fs_magic == FS_UFS1_MAGIC) { + fs->fs_old_time = fs->fs_time; + fs->fs_old_cstotal.cs_ndir = fs->fs_cstotal.cs_ndir; + fs->fs_old_cstotal.cs_nbfree = fs->fs_cstotal.cs_nbfree; + fs->fs_old_cstotal.cs_nifree = fs->fs_cstotal.cs_nifree; + fs->fs_old_cstotal.cs_nffree = fs->fs_cstotal.cs_nffree; + } + fs->fs_maxfilesize = ump->um_savedmaxfilesize; + if (bigcgs) { + fs->fs_cgsize = fs->fs_save_cgsize; + fs->fs_save_cgsize = 0; + } } /* @@ -874,13 +932,10 @@ ffs_unmount(mp, mntflags, td) return (error); } fs = ump->um_fs; - if (bigcgs) { - fs->fs_cgsize = fs->fs_sparecon[0]; - fs->fs_sparecon[0] = 0; - } if (fs->fs_pendingblocks != 0 || fs->fs_pendinginodes != 0) { - printf("%s: unmount pending error: blocks %d files %d\n", - fs->fs_fsmnt, fs->fs_pendingblocks, fs->fs_pendinginodes); + printf("%s: unmount pending error: blocks %lld files %d\n", + fs->fs_fsmnt, (intmax_t)fs->fs_pendingblocks, + fs->fs_pendinginodes); fs->fs_pendingblocks = 0; fs->fs_pendinginodes = 0; } @@ -980,7 +1035,7 @@ ffs_statfs(mp, sbp, td) ump = VFSTOUFS(mp); fs = ump->um_fs; - if (fs->fs_magic != FS_MAGIC) + if (fs->fs_magic != FS_UFS1_MAGIC && fs->fs_magic != FS_UFS2_MAGIC) panic("ffs_statfs"); sbp->f_bsize = fs->fs_fsize; sbp->f_iosize = fs->fs_bsize; @@ -1173,6 +1228,7 @@ ffs_vget(mp, ino, flags, vpp) lockinit(vp->v_vnlock, PINOD, "inode", VLKTIMEOUT, LK_CANRECURSE); vp->v_data = ip; ip->i_vnode = vp; + ip->i_ump = ump; ip->i_fs = fs = ump->um_fs; ip->i_dev = dev; ip->i_number = ino; @@ -1222,7 +1278,7 @@ ffs_vget(mp, ino, flags, vpp) *vpp = NULL; return (error); } - ip->i_din = *((struct dinode *)bp->b_data + ino_to_fsbo(fs, ino)); + ffs_load_inode(bp, ip, ump->um_malloctype, fs, ino); if (DOINGSOFTDEP(vp)) softdep_load_inodeblock(ip); else @@ -1250,16 +1306,19 @@ ffs_vget(mp, ino, flags, vpp) */ if (ip->i_gen == 0) { ip->i_gen = random() / 2 + 1; - if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0) + if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0) { ip->i_flag |= IN_MODIFIED; + DIP(ip, i_gen) = ip->i_gen; + } } /* * Ensure that uid and gid are correct. This is a temporary * fix until fsck has been changed to do the update. */ - if (fs->fs_inodefmt < FS_44INODEFMT) { /* XXX */ - ip->i_uid = ip->i_din.di_ouid; /* XXX */ - ip->i_gid = ip->i_din.di_ogid; /* XXX */ + if (fs->fs_magic == FS_UFS1_MAGIC && /* XXX */ + fs->fs_old_inodefmt < FS_44INODEFMT) { /* XXX */ + ip->i_uid = ip->i_din1->di_ouid; /* XXX */ + ip->i_gid = ip->i_din1->di_ogid; /* XXX */ } /* XXX */ *vpp = vp; @@ -1333,7 +1392,7 @@ ffs_sbupdate(mp, waitfor) struct ufsmount *mp; int waitfor; { - struct fs *dfs, *fs = mp->um_fs; + struct fs *fs = mp->um_fs; struct buf *bp; int blks; void *space; @@ -1364,24 +1423,12 @@ ffs_sbupdate(mp, waitfor) */ if (allerror) return (allerror); - bp = getblk(mp->um_devvp, SBLOCK, (int)fs->fs_sbsize, 0, 0); + bp = getblk(mp->um_devvp, fsbtodb(fs, fs->fs_sblockloc), + (int)fs->fs_sbsize, 0, 0); fs->fs_fmod = 0; fs->fs_time = time_second; bcopy((caddr_t)fs, bp->b_data, (u_int)fs->fs_sbsize); - /* Restore compatibility to old filesystems. XXX */ - dfs = (struct fs *)bp->b_data; /* XXX */ - if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */ - dfs->fs_nrpos = -1; /* XXX */ - if (fs->fs_inodefmt < FS_44INODEFMT) { /* XXX */ - int32_t *lp, tmp; /* XXX */ - /* XXX */ - lp = (int32_t *)&dfs->fs_qbmask; /* XXX */ - tmp = lp[4]; /* XXX */ - for (i = 4; i > 0; i--) /* XXX */ - lp[i] = lp[i-1]; /* XXX */ - lp[0] = tmp; /* XXX */ - } /* XXX */ - dfs->fs_maxfilesize = mp->um_savedmaxfilesize; /* XXX */ + ffs_oldfscompat_write((struct fs *)bp->b_data, mp); if (waitfor != MNT_WAIT) bawrite(bp); else if ((error = bwrite(bp)) != 0) diff --git a/sys/ufs/ffs/ffs_vnops.c b/sys/ufs/ffs/ffs_vnops.c index 6615222..0c5e8c4 100644 --- a/sys/ufs/ffs/ffs_vnops.c +++ b/sys/ufs/ffs/ffs_vnops.c @@ -126,7 +126,7 @@ ffs_fsync(ap) struct buf *bp; struct buf *nbp; int s, error, wait, passes, skipmeta; - daddr_t lbn; + ufs_lbn_t lbn; wait = (ap->a_waitfor == MNT_WAIT); if (vn_isdisk(vp, NULL)) { diff --git a/sys/ufs/ffs/fs.h b/sys/ufs/ffs/fs.h index 837f902..822f4eb 100644 --- a/sys/ufs/ffs/fs.h +++ b/sys/ufs/ffs/fs.h @@ -58,14 +58,30 @@ * The beginning of cylinder group cg in fs, is given by * the ``cgbase(fs, cg)'' macro. * - * The size and offset of the super-block in sector-size neutral bytes. + * Depending on the architecture and the media, the superblock may + * reside in any one of four places. For tiny media where every block + * counts, it is placed at the very front of the partition. Historically, + * UFS1 placed it 8K from the front to leave room for the disk label and + * a small bootstrap. For UFS2 it got moved to 64K from the front to leave + * room for the disk label and a bigger bootstrap, and for really piggy + * systems we check at 256K from the front if the first three fail. In + * all cases the size of the superblock will be SBLOCKSIZE. All values are + * given in byte-offset form, so they do not imply a sector size. The + * SBLOCKSEARCH specifies the order in which the locations should be searched. + */ +#define SBLOCK_FLOPPY 0 +#define SBLOCK_UFS1 8192 +#define SBLOCK_UFS2 65536 +#define SBLOCK_PIGGY 262144 +#define SBLOCKSIZE 8192 +#define SBLOCKSEARCH \ + { SBLOCK_UFS2, SBLOCK_UFS1, SBLOCK_FLOPPY, SBLOCK_PIGGY, -1 } + +/* + * Max number of fragments per block. This value is NOT tweakable. */ -#define SBSIZE 8192 -#define SBOFF ((off_t)(BBSIZE)) -#define SBLOCK ((ufs_daddr_t)(SBOFF / DEV_BSIZE)) - -/* Max number of fragments per block, this is not tweakable */ #define MAXFRAG 8 + /* * Addresses stored in inodes are capable of addressing fragments * of `blocks'. File system blocks of at most size MAXBSIZE can @@ -176,8 +192,8 @@ * identify blocks that are in use by other snapshots (which are * expunged from this snapshot). */ -#define BLK_NOCOPY ((ufs_daddr_t)(1)) -#define BLK_SNAP ((ufs_daddr_t)(2)) +#define BLK_NOCOPY ((ufs2_daddr_t)(1)) +#define BLK_SNAP ((ufs2_daddr_t)(2)) /* * Sysctl values for the fast filesystem. @@ -193,12 +209,13 @@ /* * Command structure passed in to the filesystem to adjust filesystem values. */ -#define FFS_CMD_VERSION 0x05181979 /* version ID */ +#define FFS_CMD_VERSION 0x19790518 /* version ID */ struct fsck_cmd { - int version; /* version of command structure */ - int handle; /* reference to filesystem to be changed */ - off_t value; /* inode or block number to be affected */ - long size; /* amount or range to be adjusted */ + int32_t version; /* version of command structure */ + int32_t handle; /* reference to filesystem to be changed */ + int64_t value; /* inode or block number to be affected */ + int64_t size; /* amount or range to be adjusted */ + int64_t spare; /* reserved for future use */ }; /* @@ -213,6 +230,14 @@ struct csum { int32_t cs_nifree; /* number of free inodes */ int32_t cs_nffree; /* number of free frags */ }; +struct csum_total { + int64_t cs_ndir; /* number of directories */ + int64_t cs_nbfree; /* number of free blocks */ + int64_t cs_nifree; /* number of free inodes */ + int64_t cs_nffree; /* number of free frags */ + int64_t cs_numclusters; /* number of free clusters */ + int64_t cs_spare[3]; /* future expansion */ +}; /* * Super block for an FFS filesystem. @@ -220,23 +245,23 @@ struct csum { struct fs { int32_t fs_firstfield; /* historic filesystem linked list, */ int32_t fs_unused_1; /* used for incore super blocks */ - ufs_daddr_t fs_sblkno; /* addr of super-block in filesys */ - ufs_daddr_t fs_cblkno; /* offset of cyl-block in filesys */ - ufs_daddr_t fs_iblkno; /* offset of inode-blocks in filesys */ - ufs_daddr_t fs_dblkno; /* offset of first data after cg */ - int32_t fs_cgoffset; /* cylinder group offset in cylinder */ - int32_t fs_cgmask; /* used to calc mod fs_ntrak */ - ufs_time_t fs_time; /* last time written */ - int32_t fs_size; /* number of blocks in fs */ - int32_t fs_dsize; /* number of data blocks in fs */ + int32_t fs_sblkno; /* offset of super-block in filesys */ + int32_t fs_cblkno; /* offset of cyl-block in filesys */ + int32_t fs_iblkno; /* offset of inode-blocks in filesys */ + int32_t fs_dblkno; /* offset of first data after cg */ + int32_t fs_old_cgoffset; /* cylinder group offset in cylinder */ + int32_t fs_old_cgmask; /* used to calc mod fs_ntrak */ + int32_t fs_old_time; /* last time written */ + int32_t fs_old_size; /* number of blocks in fs */ + int32_t fs_old_dsize; /* number of data blocks in fs */ int32_t fs_ncg; /* number of cylinder groups */ int32_t fs_bsize; /* size of basic blocks in fs */ int32_t fs_fsize; /* size of frag blocks in fs */ int32_t fs_frag; /* number of frags in a block in fs */ /* these are configuration parameters */ int32_t fs_minfree; /* minimum percentage of free blocks */ - int32_t fs_rotdelay; /* num of ms for optimal next block */ - int32_t fs_rps; /* disk revolutions per second */ + int32_t fs_old_rotdelay; /* num of ms for optimal next block */ + int32_t fs_old_rps; /* disk revolutions per second */ /* these fields can be computed from the others */ int32_t fs_bmask; /* ``blkoff'' calc of blk offsets */ int32_t fs_fmask; /* ``fragoff'' calc of frag offsets */ @@ -249,35 +274,30 @@ struct fs { int32_t fs_fragshift; /* block to frag shift */ int32_t fs_fsbtodb; /* fsbtodb and dbtofsb shift constant */ int32_t fs_sbsize; /* actual size of super block */ - int32_t fs_csmask; /* csum block offset (now unused) */ - int32_t fs_csshift; /* csum block number (now unused) */ + int32_t fs_spare1[2]; /* old fs_csmask */ + /* old fs_csshift */ int32_t fs_nindir; /* value of NINDIR */ int32_t fs_inopb; /* value of INOPB */ - int32_t fs_nspf; /* value of NSPF */ + int32_t fs_old_nspf; /* value of NSPF */ /* yet another configuration parameter */ int32_t fs_optim; /* optimization preference, see below */ -/* these fields are derived from the hardware */ - int32_t fs_npsect; /* # sectors/track including spares */ - int32_t fs_interleave; /* hardware sector interleave */ - int32_t fs_trackskew; /* sector 0 skew, per track */ -/* fs_id takes the space of the unused fs_headswitch and fs_trkseek fields */ + int32_t fs_old_npsect; /* # sectors/track including spares */ + int32_t fs_old_interleave; /* hardware sector interleave */ + int32_t fs_old_trackskew; /* sector 0 skew, per track */ int32_t fs_id[2]; /* unique filesystem id */ /* sizes determined by number of cylinder groups and their sizes */ - ufs_daddr_t fs_csaddr; /* blk addr of cyl grp summary area */ + int32_t fs_old_csaddr; /* blk addr of cyl grp summary area */ int32_t fs_cssize; /* size of cyl grp summary area */ int32_t fs_cgsize; /* cylinder group size */ -/* these fields are derived from the hardware */ - int32_t fs_ntrak; /* tracks per cylinder */ - int32_t fs_nsect; /* sectors per track */ - int32_t fs_spc; /* sectors per cylinder */ -/* this comes from the disk driver partitioning */ - int32_t fs_ncyl; /* cylinders in filesystem */ -/* these fields can be computed from the others */ - int32_t fs_cpg; /* cylinders per group */ - int32_t fs_ipg; /* inodes per group */ - int32_t fs_fpg; /* blocks per group * fs_frag */ + int32_t fs_spare2; /* old fs_ntrak */ + int32_t fs_old_nsect; /* sectors per track */ + int32_t fs_old_spc; /* sectors per cylinder */ + int32_t fs_old_ncyl; /* cylinders in filesystem */ + int32_t fs_old_cpg; /* cylinders per group */ + int32_t fs_ipg; /* inodes per group */ + int32_t fs_fpg; /* blocks per group * fs_frag */ /* this data must be re-computed after crashes */ - struct csum fs_cstotal; /* cylinder summary information */ + struct csum fs_old_cstotal; /* cylinder summary information */ /* these fields are cleared at mount time */ int8_t fs_fmod; /* super block modified flag */ int8_t fs_clean; /* filesystem is clean flag */ @@ -288,37 +308,44 @@ struct fs { int32_t fs_cgrotor; /* last cg searched */ void *fs_ocsp[NOCSPTRS]; /* padding; was list of fs_cs buffers */ u_int8_t *fs_contigdirs; /* # of contiguously allocated dirs */ - struct csum *fs_csp; /* cg summary info buffer for fs_cs */ + struct csum *fs_csp; /* cg summary info buffer for fs_cs */ int32_t *fs_maxcluster; /* max cluster in each cyl group */ u_int *fs_active; /* used by snapshots to track fs */ - int32_t fs_cpc; /* cyl per cycle in postbl */ - int16_t fs_opostbl[16][8]; /* old rotation block list head */ + int32_t fs_old_cpc; /* cyl per cycle in postbl */ + int32_t fs_maxbsize; /* maximum blocking factor permitted */ + int64_t fs_sparecon64[17]; /* old rotation block list head */ + int64_t fs_sblockloc; /* location of standard superblock */ + struct csum_total fs_cstotal; /* cylinder summary information */ + ufs_time_t fs_time; /* last time written */ + int64_t fs_size; /* number of blocks in fs */ + int64_t fs_dsize; /* number of data blocks in fs */ + ufs2_daddr_t fs_csaddr; /* blk addr of cyl grp summary area */ + int64_t fs_pendingblocks; /* blocks in process of being freed */ + int32_t fs_pendinginodes; /* inodes in process of being freed */ int32_t fs_snapinum[FSMAXSNAP];/* list of snapshot inode numbers */ int32_t fs_avgfilesize; /* expected average file size */ int32_t fs_avgfpdir; /* expected # of files per directory */ - int32_t fs_sparecon[26]; /* reserved for future constants */ - int32_t fs_pendingblocks; /* blocks in process of being freed */ - int32_t fs_pendinginodes; /* inodes in process of being freed */ + int32_t fs_save_cgsize; /* save real cg size to use fs_bsize */ + int32_t fs_sparecon32[27]; /* reserved for future constants */ int32_t fs_contigsumsize; /* size of cluster summary array */ int32_t fs_maxsymlinklen; /* max length of an internal symlink */ - int32_t fs_inodefmt; /* format of on-disk inodes */ + int32_t fs_old_inodefmt; /* format of on-disk inodes */ u_int64_t fs_maxfilesize; /* maximum representable file size */ int64_t fs_qbmask; /* ~fs_bmask for use with 64-bit size */ int64_t fs_qfmask; /* ~fs_fmask for use with 64-bit size */ int32_t fs_state; /* validate fs_clean field */ - int32_t fs_postblformat; /* format of positional layout tables */ - int32_t fs_nrpos; /* number of rotational positions */ - int32_t fs_postbloff; /* (u_int16) rotation block list head */ - int32_t fs_rotbloff; /* (u_int8) blocks for each rotation */ + int32_t fs_old_postblformat; /* format of positional layout tables */ + int32_t fs_old_nrpos; /* number of rotational positions */ + int32_t fs_spare5[2]; /* old fs_postbloff */ + /* old fs_rotbloff */ int32_t fs_magic; /* magic number */ - u_int8_t fs_space[1]; /* list of blocks for each rotation */ -/* actually longer */ }; /* * Filesystem identification */ -#define FS_MAGIC 0x011954 /* the fast filesystem magic number */ +#define FS_UFS1_MAGIC 0x011954 /* UFS1 fast filesystem magic number */ +#define FS_UFS2_MAGIC 0x19540119 /* UFS2 fast filesystem magic number */ #define FS_OKAY 0x7c269d38 /* superblock checksum */ #define FS_42INODEFMT -1 /* 4.2BSD inode format */ #define FS_44INODEFMT 2 /* 4.4BSD inode format */ @@ -332,6 +359,9 @@ struct fs { /* * Filesystem flags. * + * The FS_UNCLEAN flag is set by the kernel when the filesystem was + * mounted with fs_clean set to zero. The FS_DOSOFTDEP flag indicates + * that the filesystem should be managed by the soft updates code. * Note that the FS_NEEDSFSCK flag is set and cleared only by the * fsck utility. It is set when background fsck finds an unexpected * inconsistency which requires a traditional foreground fsck to be @@ -339,28 +369,16 @@ struct fs { * disk error. A foreground fsck will clear the FS_NEEDSFSCK flag when * it has successfully cleaned up the filesystem. The kernel uses this * flag to enforce that inconsistent filesystems be mounted read-only. + * The FS_INDEXDIRS flag when set indicates that the kernel maintains + * on-disk auxiliary indexes (such as B-trees) for speeding directory + * accesses. Kernels that do not support auxiliary indicies clear the + * flag to indicate that the indicies need to be rebuilt (by fsck) before + * they can be used. */ #define FS_UNCLEAN 0x01 /* filesystem not clean at mount */ #define FS_DOSOFTDEP 0x02 /* filesystem using soft dependencies */ #define FS_NEEDSFSCK 0x04 /* filesystem needs sync fsck before mount */ - -/* - * Rotational layout table format types - */ -#define FS_42POSTBLFMT -1 /* 4.2BSD rotational table format */ -#define FS_DYNAMICPOSTBLFMT 1 /* dynamic rotational table format */ -/* - * Macros for access to superblock array structures - */ -#define fs_postbl(fs, cylno) \ - (((fs)->fs_postblformat == FS_42POSTBLFMT) \ - ? ((fs)->fs_opostbl[cylno]) \ - : ((int16_t *)((u_int8_t *)(fs) + \ - (fs)->fs_postbloff) + (cylno) * (fs)->fs_nrpos)) -#define fs_rotbl(fs) \ - (((fs)->fs_postblformat == FS_42POSTBLFMT) \ - ? ((fs)->fs_space) \ - : ((u_int8_t *)((u_int8_t *)(fs) + (fs)->fs_rotbloff))) +#define FS_INDEXDIRS 0x08 /* kernel supports indexed directories */ /* * Macros to access bits in the fs_active array. @@ -376,13 +394,18 @@ struct fs { */ #define CGSIZE(fs) \ /* base cg */ (sizeof(struct cg) + sizeof(int32_t) + \ - /* blktot size */ (fs)->fs_cpg * sizeof(int32_t) + \ - /* blks size */ (fs)->fs_cpg * (fs)->fs_nrpos * sizeof(int16_t) + \ + /* old btotoff */ (fs)->fs_old_cpg * sizeof(int32_t) + \ + /* old boff */ (fs)->fs_old_cpg * sizeof(u_int16_t) + \ /* inode map */ howmany((fs)->fs_ipg, NBBY) + \ - /* block map */ howmany((fs)->fs_cpg * (fs)->fs_spc / NSPF(fs), NBBY) +\ + /* block map */ howmany((fs)->fs_fpg, NBBY) +\ /* if present */ ((fs)->fs_contigsumsize <= 0 ? 0 : \ /* cluster sum */ (fs)->fs_contigsumsize * sizeof(int32_t) + \ - /* cluster map */ howmany((fs)->fs_cpg * (fs)->fs_spc / NSPB(fs), NBBY))) + /* cluster map */ howmany(fragstoblks(fs, (fs)->fs_fpg), NBBY))) + +/* + * The minimal number of cylinder groups that should be created. + */ +#define MINCYLGRPS 4 /* * Convert cylinder group to base address of its global summary info. @@ -396,25 +419,29 @@ struct fs { struct cg { int32_t cg_firstfield; /* historic cyl groups linked list */ int32_t cg_magic; /* magic number */ - ufs_time_t cg_time; /* time last written */ + int32_t cg_old_time; /* time last written */ int32_t cg_cgx; /* we are the cgx'th cylinder group */ - int16_t cg_ncyl; /* number of cyl's this cg */ - int16_t cg_niblk; /* number of inode blocks this cg */ + int16_t cg_old_ncyl; /* number of cyl's this cg */ + int16_t cg_old_niblk; /* number of inode blocks this cg */ int32_t cg_ndblk; /* number of data blocks this cg */ struct csum cg_cs; /* cylinder summary information */ int32_t cg_rotor; /* position of last used block */ int32_t cg_frotor; /* position of last used frag */ int32_t cg_irotor; /* position of last used inode */ int32_t cg_frsum[MAXFRAG]; /* counts of available frags */ - int32_t cg_btotoff; /* (int32) block totals per cylinder */ - int32_t cg_boff; /* (u_int16) free block positions */ + int32_t cg_old_btotoff; /* (int32) block totals per cylinder */ + int32_t cg_old_boff; /* (u_int16) free block positions */ int32_t cg_iusedoff; /* (u_int8) used inode map */ int32_t cg_freeoff; /* (u_int8) free block map */ int32_t cg_nextfreeoff; /* (u_int8) next available space */ int32_t cg_clustersumoff; /* (u_int32) counts of avail clusters */ int32_t cg_clusteroff; /* (u_int8) free cluster map */ int32_t cg_nclusterblks; /* number of clusters this cg */ - int32_t cg_sparecon[13]; /* reserved for future use */ + int32_t cg_niblk; /* number of inode blocks this cg */ + int32_t cg_initediblk; /* last initialized inode */ + int32_t cg_sparecon32[3]; /* reserved for future use */ + ufs_time_t cg_time; /* time last written */ + int64_t cg_sparecon64[3]; /* reserved for future use */ u_int8_t cg_space[1]; /* space for cylinder group maps */ /* actually longer */ }; @@ -422,56 +449,17 @@ struct cg { /* * Macros for access to cylinder group array structures */ -#define cg_blktot(cgp) \ - (((cgp)->cg_magic != CG_MAGIC) \ - ? (((struct ocg *)(cgp))->cg_btot) \ - : ((int32_t *)((u_int8_t *)(cgp) + (cgp)->cg_btotoff))) -#define cg_blks(fs, cgp, cylno) \ - (((cgp)->cg_magic != CG_MAGIC) \ - ? (((struct ocg *)(cgp))->cg_b[cylno]) \ - : ((int16_t *)((u_int8_t *)(cgp) + \ - (cgp)->cg_boff) + (cylno) * (fs)->fs_nrpos)) +#define cg_chkmagic(cgp) ((cgp)->cg_magic == CG_MAGIC) #define cg_inosused(cgp) \ - (((cgp)->cg_magic != CG_MAGIC) \ - ? (((struct ocg *)(cgp))->cg_iused) \ - : ((u_int8_t *)((u_int8_t *)(cgp) + (cgp)->cg_iusedoff))) + ((u_int8_t *)((u_int8_t *)(cgp) + (cgp)->cg_iusedoff)) #define cg_blksfree(cgp) \ - (((cgp)->cg_magic != CG_MAGIC) \ - ? (((struct ocg *)(cgp))->cg_free) \ - : ((u_int8_t *)((u_int8_t *)(cgp) + (cgp)->cg_freeoff))) -#define cg_chkmagic(cgp) \ - ((cgp)->cg_magic == CG_MAGIC || ((struct ocg *)(cgp))->cg_magic == CG_MAGIC) + ((u_int8_t *)((u_int8_t *)(cgp) + (cgp)->cg_freeoff)) #define cg_clustersfree(cgp) \ ((u_int8_t *)((u_int8_t *)(cgp) + (cgp)->cg_clusteroff)) #define cg_clustersum(cgp) \ ((int32_t *)((u_int8_t *)(cgp) + (cgp)->cg_clustersumoff)) /* - * The following structure is defined - * for compatibility with old filesystems. - */ -struct ocg { - int32_t cg_firstfield; /* historic linked list of cyl groups */ - int32_t cg_unused_1; /* used for incore cyl groups */ - ufs_time_t cg_time; /* time last written */ - int32_t cg_cgx; /* we are the cgx'th cylinder group */ - int16_t cg_ncyl; /* number of cyl's this cg */ - int16_t cg_niblk; /* number of inode blocks this cg */ - int32_t cg_ndblk; /* number of data blocks this cg */ - struct csum cg_cs; /* cylinder summary information */ - int32_t cg_rotor; /* position of last used block */ - int32_t cg_frotor; /* position of last used frag */ - int32_t cg_irotor; /* position of last used inode */ - int32_t cg_frsum[8]; /* counts of available frags */ - int32_t cg_btot[32]; /* block totals per cylinder */ - int16_t cg_b[32][8]; /* positions of free blocks */ - u_int8_t cg_iused[256]; /* used inode map */ - int32_t cg_magic; /* magic number */ - u_int8_t cg_free[1]; /* free block map */ -/* actually longer */ -}; - -/* * Turn filesystem block numbers into disk block addresses. * This maps filesystem blocks to device size blocks. */ @@ -482,13 +470,14 @@ struct ocg { * Cylinder group macros to locate things in cylinder groups. * They calc filesystem addresses of cylinder group data structures. */ -#define cgbase(fs, c) ((ufs_daddr_t)((fs)->fs_fpg * (c))) +#define cgbase(fs, c) ((ufs2_daddr_t)((fs)->fs_fpg * (c))) #define cgdmin(fs, c) (cgstart(fs, c) + (fs)->fs_dblkno) /* 1st data */ #define cgimin(fs, c) (cgstart(fs, c) + (fs)->fs_iblkno) /* inode blk */ #define cgsblock(fs, c) (cgstart(fs, c) + (fs)->fs_sblkno) /* super blk */ #define cgtod(fs, c) (cgstart(fs, c) + (fs)->fs_cblkno) /* cg block */ #define cgstart(fs, c) \ - (cgbase(fs, c) + (fs)->fs_cgoffset * ((c) & ~((fs)->fs_cgmask))) + ((fs)->fs_magic == FS_UFS2_MAGIC ? cgbase(fs, c) : \ + (cgbase(fs, c) + (fs)->fs_old_cgoffset * ((c) & ~((fs)->fs_old_cgmask)))) /* * Macros for handling inode numbers: @@ -498,7 +487,7 @@ struct ocg { */ #define ino_to_cg(fs, x) ((x) / (fs)->fs_ipg) #define ino_to_fsba(fs, x) \ - ((ufs_daddr_t)(cgimin(fs, ino_to_cg(fs, x)) + \ + ((ufs2_daddr_t)(cgimin(fs, ino_to_cg(fs, x)) + \ (blkstofrags((fs), (((x) % (fs)->fs_ipg) / INOPB(fs)))))) #define ino_to_fsbo(fs, x) ((x) % INOPB(fs)) @@ -515,12 +504,6 @@ struct ocg { */ #define blkmap(fs, map, loc) \ (((map)[(loc) / NBBY] >> ((loc) % NBBY)) & (0xff >> (NBBY - (fs)->fs_frag))) -#define cbtocylno(fs, bno) \ - ((bno) * NSPF(fs) / (fs)->fs_spc) -#define cbtorpos(fs, bno) \ - (((bno) * NSPF(fs) % (fs)->fs_spc / (fs)->fs_nsect * (fs)->fs_trackskew + \ - (bno) * NSPF(fs) % (fs)->fs_spc % (fs)->fs_nsect * (fs)->fs_interleave) % \ - (fs)->fs_nsect * (fs)->fs_nrpos / (fs)->fs_npsect) /* * The following macros optimize certain frequently calculated @@ -531,6 +514,8 @@ struct ocg { ((loc) & (fs)->fs_qbmask) #define fragoff(fs, loc) /* calculates (loc % fs->fs_fsize) */ \ ((loc) & (fs)->fs_qfmask) +#define lfragtosize(fs, frag) /* calculates ((off_t)frag * fs->fs_fsize) */ \ + ((off_t)(frag) << (fs)->fs_fshift) #define lblktosize(fs, blk) /* calculates ((off_t)blk * fs->fs_bsize) */ \ ((off_t)(blk) << (fs)->fs_bshift) /* Use this only when `blk' is known to be small, e.g., < NDADDR. */ @@ -569,11 +554,6 @@ struct ocg { (((lbn) >= NDADDR || (ip)->i_size >= smalllblktosize(fs, (lbn) + 1)) \ ? (fs)->fs_bsize \ : (fragroundup(fs, blkoff(fs, (ip)->i_size)))) -#define dblksize(fs, dip, lbn) \ - (((lbn) >= NDADDR || \ - (dip)->di_size >= (u_int64_t)smalllblktosize(fs, (lbn) + 1)) \ - ? (fs)->fs_bsize \ - : (fragroundup(fs, blkoff(fs, (dip)->di_size)))) #define sblksize(fs, size, lbn) \ (((lbn) >= NDADDR || (size) >= ((lbn) + 1) << (fs)->fs_bshift) \ ? (fs)->fs_bsize \ @@ -581,13 +561,6 @@ struct ocg { /* - * Number of disk sectors per block/fragment; assumes DEV_BSIZE byte - * sector size. - */ -#define NSPB(fs) ((fs)->fs_nspf << (fs)->fs_fragshift) -#define NSPF(fs) ((fs)->fs_nspf) - -/* * Number of inodes in a secondary storage block/fragment. */ #define INOPB(fs) ((fs)->fs_inopb) diff --git a/sys/ufs/ffs/softdep.h b/sys/ufs/ffs/softdep.h index cdb1f68..cbee51b 100644 --- a/sys/ufs/ffs/softdep.h +++ b/sys/ufs/ffs/softdep.h @@ -86,8 +86,11 @@ * says that the files space has been accounted to the pending free * space count. The NEWBLOCK flag marks pagedep structures that have * just been allocated, so must be claimed by the inode before all - * dependencies are complete. The ONWORKLIST flag shows whether the - * structure is currently linked onto a worklist. + * dependencies are complete. The INPROGRESS flag marks worklist + * structures that are still on the worklist, but are being considered + * for action by some process. The UFS1FMT flag indicates that the + * inode being processed is a ufs1 format. The ONWORKLIST flag shows + * whether the structure is currently linked onto a worklist. */ #define ATTACHED 0x0001 #define UNDONE 0x0002 @@ -102,6 +105,7 @@ #define SPACECOUNTED 0x0400 /* inodedep only */ #define NEWBLOCK 0x0800 /* pagedep only */ #define INPROGRESS 0x1000 /* dirrem, freeblks, freefrag, freefile only */ +#define UFS1FMT 0x2000 /* indirdep only */ #define ONWORKLIST 0x8000 #define ALLCOMPLETE (ATTACHED | COMPLETE | DEPCOMPLETE) @@ -177,7 +181,7 @@ TAILQ_HEAD(allocdirectlst, allocdirect); * list, any removed operations are done, and the dependency structure * is freed. */ -#define DAHASHSZ 6 +#define DAHASHSZ 5 #define DIRADDHASH(offset) (((offset) >> 2) % DAHASHSZ) struct pagedep { struct worklist pd_list; /* page buffer */ @@ -245,7 +249,6 @@ struct inodedep { struct fs *id_fs; /* associated filesystem */ ino_t id_ino; /* dependent inode */ nlink_t id_nlinkdelta; /* saved effective link count */ - struct dinode *id_savedino; /* saved dinode contents */ LIST_ENTRY(inodedep) id_deps; /* bmsafemap's list of inodedep's */ struct buf *id_buf; /* related bmsafemap (if pending) */ off_t id_savedsize; /* file size saved during rollback */ @@ -254,7 +257,13 @@ struct inodedep { struct workhead id_inowait; /* operations waiting inode update */ struct allocdirectlst id_inoupdt; /* updates before inode written */ struct allocdirectlst id_newinoupdt; /* updates when inode written */ + union { + struct ufs1_dinode *idu_savedino1; /* saved ufs1_dinode contents */ + struct ufs2_dinode *idu_savedino2; /* saved ufs2_dinode contents */ + } id_un; }; +#define id_savedino1 id_un.idu_savedino1 +#define id_savedino2 id_un.idu_savedino2 /* * A "newblk" structure is attached to a bmsafemap structure when a block @@ -267,8 +276,8 @@ struct inodedep { struct newblk { LIST_ENTRY(newblk) nb_hash; /* hashed lookup */ struct fs *nb_fs; /* associated filesystem */ - ufs_daddr_t nb_newblkno; /* allocated block number */ int nb_state; /* state of bitmap dependency */ + ufs2_daddr_t nb_newblkno; /* allocated block number */ LIST_ENTRY(newblk) nb_deps; /* bmsafemap's list of newblk's */ struct bmsafemap *nb_bmsafemap; /* associated bmsafemap */ }; @@ -324,8 +333,8 @@ struct allocdirect { # define ad_state ad_list.wk_state /* block pointer state */ TAILQ_ENTRY(allocdirect) ad_next; /* inodedep's list of allocdirect's */ ufs_lbn_t ad_lbn; /* block within file */ - ufs_daddr_t ad_newblkno; /* new value of block pointer */ - ufs_daddr_t ad_oldblkno; /* old value of block pointer */ + ufs2_daddr_t ad_newblkno; /* new value of block pointer */ + ufs2_daddr_t ad_oldblkno; /* old value of block pointer */ long ad_newsize; /* size of new block */ long ad_oldsize; /* size of old block */ LIST_ENTRY(allocdirect) ad_deps; /* bmsafemap's list of allocdirect's */ @@ -379,8 +388,8 @@ struct allocindir { # define ai_state ai_list.wk_state /* indirect block pointer state */ LIST_ENTRY(allocindir) ai_next; /* indirdep's list of allocindir's */ int ai_offset; /* pointer offset in indirect block */ - ufs_daddr_t ai_newblkno; /* new block pointer value */ - ufs_daddr_t ai_oldblkno; /* old block pointer value */ + ufs2_daddr_t ai_newblkno; /* new block pointer value */ + ufs2_daddr_t ai_oldblkno; /* old block pointer value */ struct freefrag *ai_freefrag; /* block to be freed when complete */ struct indirdep *ai_indirdep; /* address of associated indirdep */ LIST_ENTRY(allocindir) ai_deps; /* bmsafemap's list of allocindir's */ @@ -400,9 +409,8 @@ struct allocindir { struct freefrag { struct worklist ff_list; /* id_inowait or delayed worklist */ # define ff_state ff_list.wk_state /* owning user; should be uid_t */ - struct vnode *ff_devvp; /* filesystem device vnode */ struct mount *ff_mnt; /* associated mount point */ - ufs_daddr_t ff_blkno; /* fragment physical block number */ + ufs2_daddr_t ff_blkno; /* fragment physical block number */ long ff_fragsize; /* size of fragment being deleted */ ino_t ff_inum; /* owning inode number */ }; @@ -416,14 +424,14 @@ struct freefrag { struct freeblks { struct worklist fb_list; /* id_inowait or delayed worklist */ ino_t fb_previousinum; /* inode of previous owner of blocks */ + uid_t fb_uid; /* uid of previous owner of blocks */ struct vnode *fb_devvp; /* filesystem device vnode */ struct mount *fb_mnt; /* associated mount point */ off_t fb_oldsize; /* previous file size */ off_t fb_newsize; /* new file size */ - int fb_chkcnt; /* used to check cnt of blks released */ - uid_t fb_uid; /* uid of previous owner of blocks */ - ufs_daddr_t fb_dblks[NDADDR]; /* direct blk ptrs to deallocate */ - ufs_daddr_t fb_iblks[NIADDR]; /* indirect blk ptrs to deallocate */ + ufs2_daddr_t fb_chkcnt; /* used to check cnt of blks released */ + ufs2_daddr_t fb_dblks[NDADDR]; /* direct blk ptrs to deallocate */ + ufs2_daddr_t fb_iblks[NIADDR]; /* indirect blk ptrs to deallocate */ }; /* diff --git a/sys/ufs/ufs/dinode.h b/sys/ufs/ufs/dinode.h index 0168797..5caea85 100644 --- a/sys/ufs/ufs/dinode.h +++ b/sys/ufs/ufs/dinode.h @@ -1,4 +1,13 @@ /* + * Copyright (c) 2002 Networks Associates Technology, Inc. + * All rights reserved. + * + * This software was developed for the FreeBSD Project by Marshall + * Kirk McKusick and Network Associates Laboratories, the Security + * Research Division of Network Associates, Inc. under DARPA/SPAWAR + * contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS + * research program + * * Copyright (c) 1982, 1989, 1993 * The Regents of the University of California. All rights reserved. * (c) UNIX System Laboratories, Inc. @@ -15,18 +24,14 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. + * 3. The names of the authors may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) @@ -40,7 +45,7 @@ */ #ifndef _UFS_UFS_DINODE_H_ -#define _UFS_UFS_DINODE_H_ +#define _UFS_UFS_DINODE_H_ /* * The root inode is the root of the filesystem. Inode 0 can't be used for @@ -59,17 +64,85 @@ #define WINO ((ino_t)1) /* - * A dinode contains all the meta-data associated with a UFS file. + * The size of physical and logical block numbers and time fields in UFS. + */ +typedef int32_t ufs1_daddr_t; +typedef int64_t ufs2_daddr_t; +typedef int64_t ufs_lbn_t; +typedef int64_t ufs_time_t; + +/* File permissions. */ +#define IEXEC 0000100 /* Executable. */ +#define IWRITE 0000200 /* Writeable. */ +#define IREAD 0000400 /* Readable. */ +#define ISVTX 0001000 /* Sticky bit. */ +#define ISGID 0002000 /* Set-gid. */ +#define ISUID 0004000 /* Set-uid. */ + +/* File types. */ +#define IFMT 0170000 /* Mask of file type. */ +#define IFIFO 0010000 /* Named pipe (fifo). */ +#define IFCHR 0020000 /* Character device. */ +#define IFDIR 0040000 /* Directory file. */ +#define IFBLK 0060000 /* Block device. */ +#define IFREG 0100000 /* Regular file. */ +#define IFLNK 0120000 /* Symbolic link. */ +#define IFSOCK 0140000 /* UNIX domain socket. */ +#define IFWHT 0160000 /* Whiteout. */ + +/* + * A dinode contains all the meta-data associated with a UFS2 file. * This structure defines the on-disk format of a dinode. Since * this structure describes an on-disk structure, all its fields * are defined by types with precise widths. */ -/* typedef int32_t ufs_daddr_t; */ +#define NXADDR 2 /* External addresses in inode. */ #define NDADDR 12 /* Direct addresses in inode. */ #define NIADDR 3 /* Indirect addresses in inode. */ -struct dinode { +struct ufs2_dinode { + u_int16_t di_mode; /* 0: IFMT, permissions; see below. */ + int16_t di_nlink; /* 2: File link count. */ + u_int32_t di_uid; /* 4: File owner. */ + u_int32_t di_gid; /* 8: File group. */ + u_int32_t di_blksize; /* 12: Inode blocksize. */ + u_int64_t di_size; /* 16: File byte count. */ + u_int64_t di_blocks; /* 24: Bytes actually held. */ + ufs_time_t di_atime; /* 32: Last access time. */ + ufs_time_t di_mtime; /* 40: Last modified time. */ + ufs_time_t di_ctime; /* 48: Last inode change time. */ + ufs_time_t di_createtime; /* 56: Last inode change time. */ + int32_t di_mtimensec; /* 64: Last modified time. */ + int32_t di_atimensec; /* 68: Last access time. */ + int32_t di_ctimensec; /* 72: Last inode change time. */ + int32_t di_creatensec; /* 76: Last inode change time. */ + int32_t di_gen; /* 80: Generation number. */ + u_int32_t di_kernflags; /* 84: Kernel flags. */ + u_int32_t di_flags; /* 88: Status flags (chflags). */ + int32_t di_extsize; /* 92: External attributes block. */ + ufs2_daddr_t di_extb[NXADDR];/* 96: External attributes block. */ + ufs2_daddr_t di_db[NDADDR]; /* 112: Direct disk blocks. */ + ufs2_daddr_t di_ib[NIADDR]; /* 208: Indirect disk blocks. */ + int64_t di_spare[3]; /* 232: Reserved; currently unused */ +}; + +/* + * The di_db fields may be overlaid with other information for + * file types that do not have associated disk storage. Block + * and character devices overlay the first data block with their + * dev_t value. Short symbolic links place their path in the + * di_db area. + */ +#define di_rdev di_db[0] + +/* + * A UFS1 dinode contains all the meta-data associated with a UFS1 file. + * This structure defines the on-disk format of a UFS1 dinode. Since + * this structure describes an on-disk structure, all its fields + * are defined by types with precise widths. + */ +struct ufs1_dinode { u_int16_t di_mode; /* 0: IFMT, permissions; see below. */ int16_t di_nlink; /* 2: File link count. */ union { @@ -82,8 +155,8 @@ struct dinode { int32_t di_mtimensec; /* 28: Last modified time. */ int32_t di_ctime; /* 32: Last inode change time. */ int32_t di_ctimensec; /* 36: Last inode change time. */ - ufs_daddr_t di_db[NDADDR]; /* 40: Direct disk blocks. */ - ufs_daddr_t di_ib[NIADDR]; /* 88: Indirect disk blocks. */ + ufs1_daddr_t di_db[NDADDR]; /* 40: Direct disk blocks. */ + ufs1_daddr_t di_ib[NIADDR]; /* 88: Indirect disk blocks. */ u_int32_t di_flags; /* 100: Status flags (chflags). */ int32_t di_blocks; /* 104: Blocks actually held. */ int32_t di_gen; /* 108: Generation number. */ @@ -91,37 +164,7 @@ struct dinode { u_int32_t di_gid; /* 116: File group. */ int32_t di_spare[2]; /* 120: Reserved; currently unused */ }; - -/* - * The di_db fields may be overlaid with other information for - * file types that do not have associated disk storage. Block - * and character devices overlay the first data block with their - * dev_t value. Short symbolic links place their path in the - * di_db area. - */ #define di_ogid di_u.oldids[1] #define di_ouid di_u.oldids[0] -#define di_rdev di_db[0] -#define di_shortlink di_db -#define MAXSYMLINKLEN ((NDADDR + NIADDR) * sizeof(ufs_daddr_t)) - -/* File permissions. */ -#define IEXEC 0000100 /* Executable. */ -#define IWRITE 0000200 /* Writeable. */ -#define IREAD 0000400 /* Readable. */ -#define ISVTX 0001000 /* Sticky bit. */ -#define ISGID 0002000 /* Set-gid. */ -#define ISUID 0004000 /* Set-uid. */ - -/* File types. */ -#define IFMT 0170000 /* Mask of file type. */ -#define IFIFO 0010000 /* Named pipe (fifo). */ -#define IFCHR 0020000 /* Character device. */ -#define IFDIR 0040000 /* Directory file. */ -#define IFBLK 0060000 /* Block device. */ -#define IFREG 0100000 /* Regular file. */ -#define IFLNK 0120000 /* Symbolic link. */ -#define IFSOCK 0140000 /* UNIX domain socket. */ -#define IFWHT 0160000 /* Whiteout. */ -#endif +#endif /* _UFS_UFS_DINODE_H_ */ diff --git a/sys/ufs/ufs/inode.h b/sys/ufs/ufs/inode.h index 5a327c8..02fa951 100644 --- a/sys/ufs/ufs/inode.h +++ b/sys/ufs/ufs/inode.h @@ -47,11 +47,6 @@ #include <ufs/ufs/dinode.h> /* - * The size of a logical block number. - */ -typedef long ufs_lbn_t; - -/* * This must agree with the definition in <ufs/ufs/dir.h>. */ #define doff_t int32_t @@ -69,6 +64,7 @@ struct inode { LIST_ENTRY(inode) i_hash;/* Hash chain. */ TAILQ_ENTRY(inode) i_nextsnap; /* snapshot file list */ struct vnode *i_vnode;/* Vnode associated with this inode. */ + struct ufsmount *i_ump;/* Ufsmount point associated with this inode. */ struct vnode *i_devvp;/* Vnode for block I/O. */ u_int32_t i_flag; /* flags, see below */ dev_t i_dev; /* Device associated with the inode. */ @@ -91,31 +87,26 @@ struct inode { struct dirhash *i_dirhash; /* Hashing for large directories */ /* - * The on-disk dinode itself. + * Copies from the on-disk dinode itself. */ - struct dinode i_din; /* 128 bytes of the on-disk dinode. */ + u_int16_t i_mode; /* IFMT, permissions; see below. */ + int16_t i_nlink; /* File link count. */ + u_int64_t i_size; /* File byte count. */ + u_int32_t i_flags; /* Status flags (chflags). */ + int64_t i_gen; /* Generation number. */ + u_int32_t i_uid; /* File owner. */ + u_int32_t i_gid; /* File group. */ + /* + * The real copy of the on-disk inode. + */ + union { + struct ufs1_dinode *din1; /* UFS1 on-disk dinode. */ + struct ufs2_dinode *din2; /* UFS2 on-disk dinode. */ + } dinode_u; }; - -#define i_atime i_din.di_atime -#define i_atimensec i_din.di_atimensec -#define i_blocks i_din.di_blocks -#define i_ctime i_din.di_ctime -#define i_ctimensec i_din.di_ctimensec -#define i_db i_din.di_db -#define i_flags i_din.di_flags -#define i_gen i_din.di_gen -#define i_gid i_din.di_gid -#define i_ib i_din.di_ib -#define i_mode i_din.di_mode -#define i_mtime i_din.di_mtime -#define i_mtimensec i_din.di_mtimensec -#define i_nlink i_din.di_nlink -#define i_rdev i_din.di_rdev -#define i_shortlink i_din.di_shortlink -#define i_size i_din.di_size -#define i_uid i_din.di_uid - -/* These flags are kept in i_flag. */ +/* + * These flags are kept in i_flag. + */ #define IN_ACCESS 0x0001 /* Access time update request. */ #define IN_CHANGE 0x0002 /* Inode change time update request. */ #define IN_UPDATE 0x0004 /* Modification time update request. */ @@ -125,13 +116,32 @@ struct inode { #define IN_LAZYMOD 0x0040 /* Modified, but don't write yet. */ #define IN_SPACECOUNTED 0x0080 /* Blocks to be freed in free count. */ +#define i_din1 dinode_u.din1 +#define i_din2 dinode_u.din2 + #ifdef _KERNEL /* + * The DIP macro is used to access fields in the dinode that are + * not cached in the inode itself. + */ +#define DIP(ip, field) \ + (((ip)->i_ump->um_fstype == UFS1) ? \ + (ip)->i_din1->d##field : (ip)->i_din2->d##field) + +#define MAXSYMLINKLEN(ip) \ + ((ip)->i_ump->um_fstype == UFS1) ? \ + ((NDADDR + NIADDR) * sizeof(ufs1_daddr_t)) : \ + ((NDADDR + NIADDR) * sizeof(ufs2_daddr_t)) +#define SHORTLINK(ip) \ + (((ip)->i_ump->um_fstype == UFS1) ? \ + (caddr_t)(ip)->i_din1->di_db : (caddr_t)(ip)->i_din2->di_db) + +/* * Structure used to pass around logical block paths generated by * ufs_getlbns and used by truncate and bmap code. */ struct indir { - ufs_daddr_t in_lbn; /* Logical block number. */ + ufs2_daddr_t in_lbn; /* Logical block number. */ int in_off; /* Offset in buffer. */ int in_exists; /* Flag if the block exists. */ }; diff --git a/sys/ufs/ufs/quota.h b/sys/ufs/ufs/quota.h index 5737088..15f512c 100644 --- a/sys/ufs/ufs/quota.h +++ b/sys/ufs/ufs/quota.h @@ -104,8 +104,8 @@ struct dqblk { u_int32_t dqb_ihardlimit; /* maximum # allocated inodes + 1 */ u_int32_t dqb_isoftlimit; /* preferred inode limit */ u_int32_t dqb_curinodes; /* current # allocated inodes */ - ufs_time_t dqb_btime; /* time limit for excessive disk use */ - ufs_time_t dqb_itime; /* time limit for excessive files */ + int32_t dqb_btime; /* time limit for excessive disk use */ + int32_t dqb_itime; /* time limit for excessive files */ }; #ifdef _KERNEL @@ -178,8 +178,8 @@ struct thread; struct ucred; struct vnode; -int chkdq(struct inode *, long, struct ucred *, int); -int chkiq(struct inode *, long, struct ucred *, int); +int chkdq(struct inode *, int64_t, struct ucred *, int); +int chkiq(struct inode *, ino_t, struct ucred *, int); void dqinit(void); void dqrele(struct vnode *, struct dquot *); int getinoquota(struct inode *); diff --git a/sys/ufs/ufs/ufs_acl.c b/sys/ufs/ufs/ufs_acl.c index 5869caf..390e0db 100644 --- a/sys/ufs/ufs/ufs_acl.c +++ b/sys/ufs/ufs/ufs_acl.c @@ -191,6 +191,7 @@ ufs_sync_inode_from_acl(struct acl *acl, struct inode *ip, ip->i_mode &= ~(S_IRWXU|S_IRWXG|S_IRWXO); ip->i_mode |= acl_posix1e_perms_to_mode(acl_user_obj, acl_group_obj, acl_other); + DIP(ip, i_mode) = ip->i_mode; } else { /* * Use the ACL_MASK entry. @@ -198,8 +199,10 @@ ufs_sync_inode_from_acl(struct acl *acl, struct inode *ip, ip->i_mode &= ~(S_IRWXU|S_IRWXG|S_IRWXO); ip->i_mode |= acl_posix1e_perms_to_mode(acl_user_obj, acl_mask, acl_other); + DIP(ip, i_mode) = ip->i_mode; } ip->i_mode |= preserve_mode; + DIP(ip, i_mode) = ip->i_mode; } /* diff --git a/sys/ufs/ufs/ufs_bmap.c b/sys/ufs/ufs/ufs_bmap.c index 2bd312f..abe2bea 100644 --- a/sys/ufs/ufs/ufs_bmap.c +++ b/sys/ufs/ufs/ufs_bmap.c @@ -71,7 +71,7 @@ ufs_bmap(ap) int *a_runb; } */ *ap; { - ufs_daddr_t blkno; + ufs2_daddr_t blkno; int error; /* @@ -106,8 +106,8 @@ ufs_bmap(ap) int ufs_bmaparray(vp, bn, bnp, runp, runb) struct vnode *vp; - ufs_daddr_t bn; - ufs_daddr_t *bnp; + ufs2_daddr_t bn; + ufs2_daddr_t *bnp; int *runp; int *runb; { @@ -117,8 +117,8 @@ ufs_bmaparray(vp, bn, bnp, runp, runb) struct mount *mp; struct vnode *devvp; struct indir a[NIADDR+1], *ap; - ufs_daddr_t daddr; - long metalbn; + ufs2_daddr_t daddr; + ufs_lbn_t metalbn; int error, num, maxrun = 0; int *nump; @@ -146,7 +146,7 @@ ufs_bmaparray(vp, bn, bnp, runp, runb) num = *nump; if (num == 0) { - *bnp = blkptrtodb(ump, ip->i_db[bn]); + *bnp = blkptrtodb(ump, DIP(ip, i_db[bn])); /* * Since this is FFS independent code, we are out of * scope for the definitions of BLK_NOCOPY and @@ -155,8 +155,8 @@ ufs_bmaparray(vp, bn, bnp, runp, runb) * return a request for a zeroed out buffer if attempts * are made to read a BLK_NOCOPY or BLK_SNAP block. */ - if ((ip->i_flags & SF_SNAPSHOT) && - ip->i_db[bn] > 0 && ip->i_db[bn] < ump->um_seqinc) { + if ((ip->i_flags & SF_SNAPSHOT) && DIP(ip, i_db[bn]) > 0 && + DIP(ip, i_db[bn]) < ump->um_seqinc) { *bnp = -1; } else if (*bnp == 0) { if (ip->i_flags & SF_SNAPSHOT) @@ -164,15 +164,16 @@ ufs_bmaparray(vp, bn, bnp, runp, runb) else *bnp = -1; } else if (runp) { - daddr_t bnb = bn; + ufs2_daddr_t bnb = bn; for (++bn; bn < NDADDR && *runp < maxrun && - is_sequential(ump, ip->i_db[bn - 1], ip->i_db[bn]); + is_sequential(ump, DIP(ip, i_db[bn - 1]), + DIP(ip, i_db[bn])); ++bn, ++*runp); bn = bnb; if (runb && (bn > 0)) { for (--bn; (bn >= 0) && (*runb < maxrun) && - is_sequential(ump, ip->i_db[bn], - ip->i_db[bn+1]); + is_sequential(ump, DIP(ip, i_db[bn]), + DIP(ip, i_db[bn+1])); --bn, ++*runb); } } @@ -181,7 +182,7 @@ ufs_bmaparray(vp, bn, bnp, runp, runb) /* Get disk address out of indirect block array */ - daddr = ip->i_ib[ap->in_off]; + daddr = DIP(ip, i_ib[ap->in_off]); for (bp = NULL, ++ap; --num; ++ap) { /* @@ -221,21 +222,41 @@ ufs_bmaparray(vp, bn, bnp, runp, runb) } } - daddr = ((ufs_daddr_t *)bp->b_data)[ap->in_off]; + if (ip->i_ump->um_fstype == UFS1) { + daddr = ((ufs1_daddr_t *)bp->b_data)[ap->in_off]; + if (num == 1 && daddr && runp) { + for (bn = ap->in_off + 1; + bn < MNINDIR(ump) && *runp < maxrun && + is_sequential(ump, + ((ufs1_daddr_t *)bp->b_data)[bn - 1], + ((ufs1_daddr_t *)bp->b_data)[bn]); + ++bn, ++*runp); + bn = ap->in_off; + if (runb && bn) { + for (--bn; bn >= 0 && *runb < maxrun && + is_sequential(ump, + ((ufs1_daddr_t *)bp->b_data)[bn], + ((ufs1_daddr_t *)bp->b_data)[bn+1]); + --bn, ++*runb); + } + } + continue; + } + daddr = ((ufs2_daddr_t *)bp->b_data)[ap->in_off]; if (num == 1 && daddr && runp) { for (bn = ap->in_off + 1; bn < MNINDIR(ump) && *runp < maxrun && is_sequential(ump, - ((ufs_daddr_t *)bp->b_data)[bn - 1], - ((ufs_daddr_t *)bp->b_data)[bn]); + ((ufs2_daddr_t *)bp->b_data)[bn - 1], + ((ufs2_daddr_t *)bp->b_data)[bn]); ++bn, ++*runp); bn = ap->in_off; if (runb && bn) { - for(--bn; bn >= 0 && *runb < maxrun && - is_sequential(ump, - ((ufs_daddr_t *)bp->b_data)[bn], - ((ufs_daddr_t *)bp->b_data)[bn+1]); - --bn, ++*runb); + for (--bn; bn >= 0 && *runb < maxrun && + is_sequential(ump, + ((ufs2_daddr_t *)bp->b_data)[bn], + ((ufs2_daddr_t *)bp->b_data)[bn + 1]); + --bn, ++*runb); } } } @@ -275,22 +296,22 @@ ufs_bmaparray(vp, bn, bnp, runp, runb) int ufs_getlbns(vp, bn, ap, nump) struct vnode *vp; - ufs_daddr_t bn; + ufs2_daddr_t bn; struct indir *ap; int *nump; { - long blockcnt, metalbn, realbn; + ufs2_daddr_t blockcnt; + ufs_lbn_t metalbn, realbn; struct ufsmount *ump; int i, numlevels, off; - int64_t qblockcnt; ump = VFSTOUFS(vp->v_mount); if (nump) *nump = 0; numlevels = 0; realbn = bn; - if ((long)bn < 0) - bn = -(long)bn; + if (bn < 0) + bn = -bn; /* The first NDADDR blocks are direct blocks. */ if (bn < NDADDR) @@ -305,15 +326,9 @@ ufs_getlbns(vp, bn, ap, nump) for (blockcnt = 1, i = NIADDR, bn -= NDADDR;; i--, bn -= blockcnt) { if (i == 0) return (EFBIG); - /* - * Use int64_t's here to avoid overflow for triple indirect - * blocks when longs have 32 bits and the block size is more - * than 4K. - */ - qblockcnt = (int64_t)blockcnt * MNINDIR(ump); - if (bn < qblockcnt) + blockcnt *= MNINDIR(ump); + if (bn < blockcnt) break; - blockcnt = qblockcnt; } /* Calculate the address of the first meta-block. */ @@ -337,6 +352,7 @@ ufs_getlbns(vp, bn, ap, nump) if (metalbn == realbn) break; + blockcnt /= MNINDIR(ump); off = (bn / blockcnt) % MNINDIR(ump); ++numlevels; @@ -346,7 +362,6 @@ ufs_getlbns(vp, bn, ap, nump) ++ap; metalbn -= -1 + off * blockcnt; - blockcnt /= MNINDIR(ump); } if (nump) *nump = numlevels; diff --git a/sys/ufs/ufs/ufs_extattr.c b/sys/ufs/ufs/ufs_extattr.c index 69df5ad..486263a 100644 --- a/sys/ufs/ufs/ufs_extattr.c +++ b/sys/ufs/ufs/ufs_extattr.c @@ -947,7 +947,7 @@ ufs_extattr_get(struct vnode *vp, int attrnamespace, const char *name, * is to coerce this to undefined, and let it get cleaned * up by the next write or extattrctl clean. */ - printf("ufs_extattr_get (%s): inode number inconsistency (%d, %d)\n", + printf("ufs_extattr_get (%s): inode number inconsistency (%d, %lld)\n", mp->mnt_stat.f_mntonname, ueh.ueh_i_gen, ip->i_gen); error = ENOATTR; goto vopunlock_exit; @@ -1226,7 +1226,7 @@ ufs_extattr_rm(struct vnode *vp, int attrnamespace, const char *name, * coerce this to undefined, and let it get cleaned up by * the next write or extattrctl clean. */ - printf("ufs_extattr_rm (%s): inode number inconsistency (%d, %d)\n", + printf("ufs_extattr_rm (%s): inode number inconsistency (%d, %lld)\n", mp->mnt_stat.f_mntonname, ueh.ueh_i_gen, ip->i_gen); error = ENOATTR; goto vopunlock_exit; diff --git a/sys/ufs/ufs/ufs_extern.h b/sys/ufs/ufs/ufs_extern.h index 49e25db..b961df3 100644 --- a/sys/ufs/ufs/ufs_extern.h +++ b/sys/ufs/ufs/ufs_extern.h @@ -60,7 +60,8 @@ int ufs_vnoperatefifo(struct vop_generic_args *); int ufs_vnoperatespec(struct vop_generic_args *); int ufs_bmap(struct vop_bmap_args *); -int ufs_bmaparray(struct vnode *, ufs_daddr_t, ufs_daddr_t *, int *, int *); +int ufs_bmaparray(struct vnode *, ufs2_daddr_t, ufs2_daddr_t *, int *, + int *); int ufs_fhtovp(struct mount *, struct ufid *, struct vnode **); int ufs_checkpath(struct inode *, struct inode *, struct ucred *); void ufs_dirbad(struct inode *, doff_t, char *); @@ -72,7 +73,7 @@ int ufs_direnter(struct vnode *, struct vnode *, struct direct *, struct componentname *, struct buf *); int ufs_dirremove(struct vnode *, struct inode *, int, int); int ufs_dirrewrite(struct inode *, struct inode *, ino_t, int, int); -int ufs_getlbns(struct vnode *, ufs_daddr_t, struct indir *, int *); +int ufs_getlbns(struct vnode *, ufs2_daddr_t, struct indir *, int *); int ufs_ihashget(dev_t, ino_t, int, struct vnode **); void ufs_ihashinit(void); int ufs_ihashins(struct inode *, int, struct vnode **); @@ -94,12 +95,12 @@ int ufs_vinit(struct mount *, vop_t **, vop_t **, struct vnode **); * Soft update function prototypes. */ int softdep_setup_directory_add(struct buf *, struct inode *, off_t, - long, struct buf *, int); + ino_t, struct buf *, int); void softdep_change_directoryentry_offset(struct inode *, caddr_t, caddr_t, caddr_t, int); void softdep_setup_remove(struct buf *,struct inode *, struct inode *, int); void softdep_setup_directory_change(struct buf *, struct inode *, - struct inode *, long, int); + struct inode *, ino_t, int); void softdep_change_linkcnt(struct inode *); void softdep_releasefile(struct inode *); int softdep_slowdown(struct vnode *); diff --git a/sys/ufs/ufs/ufs_inode.c b/sys/ufs/ufs/ufs_inode.c index 55f9128..b9bbe9e 100644 --- a/sys/ufs/ufs/ufs_inode.c +++ b/sys/ufs/ufs/ufs_inode.c @@ -73,7 +73,8 @@ ufs_inactive(ap) struct vnode *vp = ap->a_vp; struct inode *ip = VTOI(vp); struct thread *td = ap->a_td; - int mode, error = 0; + mode_t mode; + int error = 0; if (prtactive && vp->v_usecount != 0) vprint("ufs_inactive: pushing active", vp); @@ -101,9 +102,10 @@ ufs_inactive(ap) * So, rather than creating a new entry point to do the * same thing, we just use softdep_change_linkcnt(). */ - ip->i_rdev = 0; + DIP(ip, i_rdev) = 0; mode = ip->i_mode; ip->i_mode = 0; + DIP(ip, i_mode) = 0; ip->i_flag |= IN_CHANGE | IN_UPDATE; if (DOINGSOFTDEP(vp)) softdep_change_linkcnt(ip); @@ -139,15 +141,15 @@ ufs_reclaim(ap) struct thread *a_td; } */ *ap; { - struct inode *ip; struct vnode *vp = ap->a_vp; + struct inode *ip = VTOI(vp); + struct ufsmount *ump = ip->i_ump; #ifdef QUOTA int i; #endif if (prtactive && vp->v_usecount != 0) vprint("ufs_reclaim: pushing active", vp); - ip = VTOI(vp); if (ip->i_flag & IN_LAZYMOD) { ip->i_flag |= IN_MODIFIED; UFS_UPDATE(vp, 0); @@ -177,7 +179,11 @@ ufs_reclaim(ap) if (ip->i_dirhash != NULL) ufsdirhash_free(ip); #endif - FREE(vp->v_data, VFSTOUFS(vp->v_mount)->um_malloctype); + if (ump->um_fstype == UFS1) + FREE(ip->i_din1, ump->um_malloctype); + else + FREE(ip->i_din2, ump->um_malloctype); + FREE(vp->v_data, ump->um_malloctype); vp->v_data = 0; return (0); } diff --git a/sys/ufs/ufs/ufs_lookup.c b/sys/ufs/ufs/ufs_lookup.c index 7b37f54..16089fa 100644 --- a/sys/ufs/ufs/ufs_lookup.c +++ b/sys/ufs/ufs/ufs_lookup.c @@ -131,8 +131,8 @@ ufs_lookup(ap) struct componentname *a_cnp; } */ *ap; { - struct vnode *vdp; /* vnode for directory being searched */ - struct inode *dp; /* inode for directory being searched */ + struct vnode *vdp; /* vnode for directory being searched */ + struct inode *dp; /* inode for directory being searched */ struct buf *bp; /* a buffer of directory entries */ struct direct *ep; /* the current directory entry */ int entryoffsetinblock; /* offset of ep in bp's buffer */ @@ -467,6 +467,7 @@ found: if (dp->i_offset + DIRSIZ(OFSFMT(vdp), ep) > dp->i_size) { ufs_dirbad(dp, dp->i_offset, "i_size too small"); dp->i_size = dp->i_offset + DIRSIZ(OFSFMT(vdp), ep); + DIP(dp, i_size) = dp->i_size; dp->i_flag |= IN_CHANGE | IN_UPDATE; } brelse(bp); @@ -644,8 +645,7 @@ ufs_dirbadentry(dp, ep, entryoffsetinblock) struct direct *ep; int entryoffsetinblock; { - int i; - int namlen; + int i, namlen; # if (BYTE_ORDER == LITTLE_ENDIAN) if (OFSFMT(dp)) @@ -760,6 +760,7 @@ ufs_direnter(dvp, tvp, dirp, cnp, newdirbp) return (error); } dp->i_size = dp->i_offset + DIRBLKSIZ; + DIP(dp, i_size) = dp->i_size; dp->i_flag |= IN_CHANGE | IN_UPDATE; vnode_pager_setsize(dvp, (u_long)dp->i_size); dirp->d_reclen = DIRBLKSIZ; @@ -838,8 +839,10 @@ ufs_direnter(dvp, tvp, dirp, cnp, newdirbp) * * N.B. - THIS IS AN ARTIFACT OF 4.2 AND SHOULD NEVER HAPPEN. */ - if (dp->i_offset + dp->i_count > dp->i_size) + if (dp->i_offset + dp->i_count > dp->i_size) { dp->i_size = dp->i_offset + dp->i_count; + DIP(dp, i_size) = dp->i_size; + } /* * Get the block containing the space for the new directory entry. */ @@ -1049,6 +1052,7 @@ out: if (ip) { ip->i_effnlink--; ip->i_nlink--; + DIP(ip, i_nlink) = ip->i_nlink; ip->i_flag |= IN_CHANGE; } if (flags & DOWHITEOUT) @@ -1102,6 +1106,7 @@ ufs_dirrewrite(dp, oip, newinum, newtype, isrmdir) bdwrite(bp); } else { oip->i_nlink--; + DIP(oip, i_nlink) = oip->i_nlink; oip->i_flag |= IN_CHANGE; if (DOINGASYNC(vdp)) { bdwrite(bp); @@ -1138,7 +1143,7 @@ ufs_dirempty(ip, parentino, cred) ino_t parentino; struct ucred *cred; { - off_t off; + doff_t off; struct dirtemplate dbuf; struct direct *dp = (struct direct *)&dbuf; int error, count, namlen; @@ -1197,7 +1202,8 @@ ufs_checkpath(source, target, cred) struct ucred *cred; { struct vnode *vp; - int error, rootino, namlen; + int error, namlen; + ino_t rootino; struct dirtemplate dirbuf; vp = ITOV(target); diff --git a/sys/ufs/ufs/ufs_quota.c b/sys/ufs/ufs/ufs_quota.c index ab4a0af..3bc4287 100644 --- a/sys/ufs/ufs/ufs_quota.c +++ b/sys/ufs/ufs/ufs_quota.c @@ -54,6 +54,7 @@ #include <ufs/ufs/quota.h> #include <ufs/ufs/inode.h> #include <ufs/ufs/ufsmount.h> +#include <ufs/ufs/ufs_extern.h> static MALLOC_DEFINE(M_DQUOT, "UFS quota", "UFS quota entries"); @@ -62,8 +63,8 @@ static MALLOC_DEFINE(M_DQUOT, "UFS quota", "UFS quota entries"); */ static char *quotatypes[] = INITQFNAMES; -static int chkdqchg(struct inode *, long, struct ucred *, int); -static int chkiqchg(struct inode *, long, struct ucred *, int); +static int chkdqchg(struct inode *, ufs2_daddr_t, struct ucred *, int); +static int chkiqchg(struct inode *, ino_t, struct ucred *, int); static int dqget(struct vnode *, u_long, struct ufsmount *, int, struct dquot **); static int dqsync(struct vnode *, struct dquot *); @@ -118,13 +119,13 @@ getinoquota(ip) int chkdq(ip, change, cred, flags) struct inode *ip; - long change; + ufs2_daddr_t change; struct ucred *cred; int flags; { struct dquot *dq; - int i; - int ncurblocks, error; + ufs2_daddr_t ncurblocks; + int i, error; #ifdef DIAGNOSTIC if ((flags & CHOWN) == 0) @@ -184,12 +185,12 @@ chkdq(ip, change, cred, flags) static int chkdqchg(ip, change, cred, type) struct inode *ip; - long change; + ufs2_daddr_t change; struct ucred *cred; int type; { struct dquot *dq = ip->i_dquot[type]; - long ncurblocks = dq->dq_curblocks + change; + ufs2_daddr_t ncurblocks = dq->dq_curblocks + change; /* * If user would exceed their hard limit, disallow space allocation. @@ -239,13 +240,13 @@ chkdqchg(ip, change, cred, type) int chkiq(ip, change, cred, flags) struct inode *ip; - long change; + ino_t change; struct ucred *cred; int flags; { struct dquot *dq; - int i; - int ncurinodes, error; + ino_t ncurinodes; + int i, error; #ifdef DIAGNOSTIC if ((flags & CHOWN) == 0) @@ -305,12 +306,12 @@ chkiq(ip, change, cred, flags) static int chkiqchg(ip, change, cred, type) struct inode *ip; - long change; + ino_t change; struct ucred *cred; int type; { struct dquot *dq = ip->i_dquot[type]; - long ncurinodes = dq->dq_curinodes + change; + ino_t ncurinodes = dq->dq_curinodes + change; /* * If user would exceed their hard limit, disallow inode allocation. diff --git a/sys/ufs/ufs/ufs_readwrite.c b/sys/ufs/ufs/ufs_readwrite.c index c76081f..527b339 100644 --- a/sys/ufs/ufs/ufs_readwrite.c +++ b/sys/ufs/ufs/ufs_readwrite.c @@ -68,11 +68,11 @@ READ(ap) struct uio *uio; FS *fs; struct buf *bp; - daddr_t lbn, nextlbn; + ufs_lbn_t lbn, nextlbn; off_t bytesinfile; long size, xfersize, blkoffset; int error, orig_resid; - u_short mode; + mode_t mode; int seqcount; int ioflag; vm_object_t object; @@ -394,7 +394,7 @@ WRITE(ap) FS *fs; struct buf *bp; struct thread *td; - ufs_daddr_t lbn; + ufs_lbn_t lbn; off_t osize; int seqcount; int blkoffset, error, extended, flags, ioflag, resid, size, xfersize; @@ -519,6 +519,7 @@ WRITE(ap) if (uio->uio_offset + xfersize > ip->i_size) { ip->i_size = uio->uio_offset + xfersize; + DIP(ip, i_size) = ip->i_size; extended = 1; } @@ -571,8 +572,10 @@ WRITE(ap) * tampering. */ if (resid > uio->uio_resid && ap->a_cred && - suser_cred(ap->a_cred, PRISON_ROOT)) + suser_cred(ap->a_cred, PRISON_ROOT)) { ip->i_mode &= ~(ISUID | ISGID); + DIP(ip, i_mode) = ip->i_mode; + } if (resid > uio->uio_resid) VN_KNOTE(vp, NOTE_WRITE | (extended ? NOTE_EXTEND : 0)); if (error) { @@ -609,8 +612,7 @@ ffs_getpages(ap) int bbackwards, bforwards; int pbackwards, pforwards; int firstpage; - int reqlblkno; - ufs_daddr_t reqblkno; + ufs2_daddr_t reqblkno, reqlblkno; int poff; int pcount; int rtval; diff --git a/sys/ufs/ufs/ufs_vnops.c b/sys/ufs/ufs/ufs_vnops.c index 19d785a..45fa7f7 100644 --- a/sys/ufs/ufs/ufs_vnops.c +++ b/sys/ufs/ufs/ufs_vnops.c @@ -162,17 +162,17 @@ ufs_itimes(vp) if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0) { vfs_timestamp(&ts); if (ip->i_flag & IN_ACCESS) { - ip->i_atime = ts.tv_sec; - ip->i_atimensec = ts.tv_nsec; + DIP(ip, i_atime) = ts.tv_sec; + DIP(ip, i_atimensec) = ts.tv_nsec; } if (ip->i_flag & IN_UPDATE) { - ip->i_mtime = ts.tv_sec; - ip->i_mtimensec = ts.tv_nsec; + DIP(ip, i_mtime) = ts.tv_sec; + DIP(ip, i_mtimensec) = ts.tv_nsec; ip->i_modrev++; } if (ip->i_flag & IN_CHANGE) { - ip->i_ctime = ts.tv_sec; - ip->i_ctimensec = ts.tv_nsec; + DIP(ip, i_ctime) = ts.tv_sec; + DIP(ip, i_ctimensec) = ts.tv_nsec; } } ip->i_flag &= ~(IN_ACCESS | IN_CHANGE | IN_UPDATE); @@ -232,7 +232,7 @@ ufs_mknod(ap) * Want to be able to use this to make badblock * inodes, so don't truncate the dev number. */ - ip->i_rdev = vap->va_rdev; + DIP(ip, i_rdev) = vap->va_rdev; } /* * Remove inode, then reload it through VFS_VGET so it is @@ -419,18 +419,34 @@ ufs_getattr(ap) vap->va_nlink = ip->i_effnlink; vap->va_uid = ip->i_uid; vap->va_gid = ip->i_gid; - vap->va_rdev = ip->i_rdev; - vap->va_size = ip->i_din.di_size; - vap->va_atime.tv_sec = ip->i_atime; - vap->va_atime.tv_nsec = ip->i_atimensec; - vap->va_mtime.tv_sec = ip->i_mtime; - vap->va_mtime.tv_nsec = ip->i_mtimensec; - vap->va_ctime.tv_sec = ip->i_ctime; - vap->va_ctime.tv_nsec = ip->i_ctimensec; + if (ip->i_ump->um_fstype == UFS1) { + vap->va_rdev = ip->i_din1->di_rdev; + vap->va_size = ip->i_din1->di_size; + vap->va_atime.tv_sec = ip->i_din1->di_atime; + vap->va_atime.tv_nsec = ip->i_din1->di_atimensec; + vap->va_mtime.tv_sec = ip->i_din1->di_mtime; + vap->va_mtime.tv_nsec = ip->i_din1->di_mtimensec; + vap->va_ctime.tv_sec = ip->i_din1->di_ctime; + vap->va_ctime.tv_nsec = ip->i_din1->di_ctimensec; + vap->va_createtime.tv_sec = 0; + vap->va_createtime.tv_nsec = 0; + vap->va_bytes = dbtob((u_quad_t)ip->i_din1->di_blocks); + } else { + vap->va_rdev = ip->i_din2->di_rdev; + vap->va_size = ip->i_din2->di_size; + vap->va_atime.tv_sec = ip->i_din2->di_atime; + vap->va_atime.tv_nsec = ip->i_din2->di_atimensec; + vap->va_mtime.tv_sec = ip->i_din2->di_mtime; + vap->va_mtime.tv_nsec = ip->i_din2->di_mtimensec; + vap->va_ctime.tv_sec = ip->i_din2->di_ctime; + vap->va_ctime.tv_nsec = ip->i_din2->di_ctimensec; + vap->va_createtime.tv_sec = ip->i_din2->di_createtime; + vap->va_createtime.tv_nsec = ip->i_din2->di_creatensec; + vap->va_bytes = dbtob((u_quad_t)ip->i_din2->di_blocks); + } vap->va_flags = ip->i_flags; vap->va_gen = ip->i_gen; vap->va_blocksize = vp->v_mount->mnt_stat.f_iosize; - vap->va_bytes = dbtob((u_quad_t)ip->i_blocks); vap->va_type = IFTOVT(ip->i_mode); vap->va_filerev = ip->i_modrev; return (0); @@ -494,6 +510,7 @@ ufs_setattr(ap) (ip->i_flags & SF_SNAPSHOT) != 0)) return (EPERM); ip->i_flags = vap->va_flags; + DIP(ip, i_flags) = vap->va_flags; } else { if (ip->i_flags & (SF_NOUNLINK | SF_IMMUTABLE | SF_APPEND) || @@ -501,6 +518,7 @@ ufs_setattr(ap) return (EPERM); ip->i_flags &= SF_SETTABLE; ip->i_flags |= (vap->va_flags & UF_SETTABLE); + DIP(ip, i_flags) = ip->i_flags; } ip->i_flag |= IN_CHANGE; if (vap->va_flags & (IMMUTABLE | APPEND)) @@ -563,12 +581,12 @@ ufs_setattr(ap) ip->i_flag |= IN_CHANGE | IN_UPDATE; ufs_itimes(vp); if (vap->va_atime.tv_sec != VNOVAL) { - ip->i_atime = vap->va_atime.tv_sec; - ip->i_atimensec = vap->va_atime.tv_nsec; + DIP(ip, i_atime) = vap->va_atime.tv_sec; + DIP(ip, i_atimensec) = vap->va_atime.tv_nsec; } if (vap->va_mtime.tv_sec != VNOVAL) { - ip->i_mtime = vap->va_mtime.tv_sec; - ip->i_mtimensec = vap->va_mtime.tv_nsec; + DIP(ip, i_mtime) = vap->va_mtime.tv_sec; + DIP(ip, i_mtimensec) = vap->va_mtime.tv_nsec; } error = UFS_UPDATE(vp, 0); if (error) @@ -620,6 +638,7 @@ ufs_chmod(vp, mode, cred, td) } ip->i_mode &= ~ALLPERMS; ip->i_mode |= (mode & ALLPERMS); + DIP(ip, i_mode) = ip->i_mode; ip->i_flag |= IN_CHANGE; return (0); } @@ -642,7 +661,7 @@ ufs_chown(vp, uid, gid, cred, td) int error = 0; #ifdef QUOTA int i; - long change; + ufs2_daddr_t change; #endif if (uid == (uid_t)VNOVAL) @@ -677,7 +696,7 @@ ufs_chown(vp, uid, gid, cred, td) dqrele(vp, ip->i_dquot[GRPQUOTA]); ip->i_dquot[GRPQUOTA] = NODQUOT; } - change = ip->i_blocks; + change = DIP(ip, i_blocks); (void) chkdq(ip, -change, cred, CHOWN); (void) chkiq(ip, -1, cred, CHOWN); for (i = 0; i < MAXQUOTAS; i++) { @@ -686,7 +705,9 @@ ufs_chown(vp, uid, gid, cred, td) } #endif ip->i_gid = gid; + DIP(ip, i_gid) = gid; ip->i_uid = uid; + DIP(ip, i_uid) = uid; #ifdef QUOTA if ((error = getinoquota(ip)) == 0) { if (ouid == uid) { @@ -709,7 +730,9 @@ ufs_chown(vp, uid, gid, cred, td) } } ip->i_gid = ogid; + DIP(ip, i_gid) = ogid; ip->i_uid = ouid; + DIP(ip, i_uid) = ouid; if (getinoquota(ip) == 0) { if (ouid == uid) { dqrele(vp, ip->i_dquot[USRQUOTA]); @@ -729,8 +752,10 @@ good: panic("ufs_chown: lost quota"); #endif /* QUOTA */ ip->i_flag |= IN_CHANGE; - if (suser_cred(cred, PRISON_ROOT) && (ouid != uid || ogid != gid)) + if (suser_cred(cred, PRISON_ROOT) && (ouid != uid || ogid != gid)) { ip->i_mode &= ~(ISUID | ISGID); + DIP(ip, i_mode) = ip->i_mode; + } return (0); } @@ -803,6 +828,7 @@ ufs_link(ap) } ip->i_effnlink++; ip->i_nlink++; + DIP(ip, i_nlink) = ip->i_nlink; ip->i_flag |= IN_CHANGE; if (DOINGSOFTDEP(vp)) softdep_change_linkcnt(ip); @@ -815,6 +841,7 @@ ufs_link(ap) if (error) { ip->i_effnlink--; ip->i_nlink--; + DIP(ip, i_nlink) = ip->i_nlink; ip->i_flag |= IN_CHANGE; if (DOINGSOFTDEP(vp)) softdep_change_linkcnt(ip); @@ -1065,6 +1092,7 @@ abortit: */ ip->i_effnlink++; ip->i_nlink++; + DIP(ip, i_nlink) = ip->i_nlink; ip->i_flag |= IN_CHANGE; if (DOINGSOFTDEP(fvp)) softdep_change_linkcnt(ip); @@ -1130,6 +1158,7 @@ abortit: } dp->i_effnlink++; dp->i_nlink++; + DIP(dp, i_nlink) = dp->i_nlink; dp->i_flag |= IN_CHANGE; if (DOINGSOFTDEP(tdvp)) softdep_change_linkcnt(dp); @@ -1144,6 +1173,7 @@ abortit: if (doingdirectory && newparent) { dp->i_effnlink--; dp->i_nlink--; + DIP(dp, i_nlink) = dp->i_nlink; dp->i_flag |= IN_CHANGE; if (DOINGSOFTDEP(tdvp)) softdep_change_linkcnt(dp); @@ -1222,9 +1252,11 @@ abortit: */ if (!newparent) { dp->i_nlink--; + DIP(dp, i_nlink) = dp->i_nlink; dp->i_flag |= IN_CHANGE; } xp->i_nlink--; + DIP(xp, i_nlink) = xp->i_nlink; xp->i_flag |= IN_CHANGE; ioflag = DOINGASYNC(tvp) ? 0 : IO_SYNC; if ((error = UFS_TRUNCATE(tvp, (off_t)0, ioflag, @@ -1321,6 +1353,7 @@ out: if (vn_lock(fvp, LK_EXCLUSIVE, td) == 0) { ip->i_effnlink--; ip->i_nlink--; + DIP(ip, i_nlink) = ip->i_nlink; ip->i_flag |= IN_CHANGE; ip->i_flag &= ~IN_RENAME; if (DOINGSOFTDEP(fvp)) @@ -1378,6 +1411,7 @@ ufs_mkdir(ap) goto out; ip = VTOI(tvp); ip->i_gid = dp->i_gid; + DIP(ip, i_gid) = dp->i_gid; #ifdef SUIDDIR { #ifdef QUOTA @@ -1396,6 +1430,7 @@ ufs_mkdir(ap) (dp->i_mode & ISUID) && dp->i_uid) { dmode |= ISUID; ip->i_uid = dp->i_uid; + DIP(ip, i_uid) = dp->i_uid; #ifdef QUOTA if (dp->i_uid != cnp->cn_cred->cr_uid) { /* @@ -1412,8 +1447,10 @@ ufs_mkdir(ap) ucp = &ucred; } #endif - } else + } else { ip->i_uid = cnp->cn_cred->cr_uid; + DIP(ip, i_uid) = ip->i_uid; + } #ifdef QUOTA if ((error = getinoquota(ip)) || (error = chkiq(ip, 1, ucp, 0))) { @@ -1425,6 +1462,7 @@ ufs_mkdir(ap) } #else /* !SUIDDIR */ ip->i_uid = cnp->cn_cred->cr_uid; + DIP(ip, i_uid) = ip->i_uid; #ifdef QUOTA if ((error = getinoquota(ip)) || (error = chkiq(ip, 1, cnp->cn_cred, 0))) { @@ -1459,6 +1497,7 @@ ufs_mkdir(ap) * not defined case. */ ip->i_mode = dmode; + DIP(ip, i_mode) = dmode; *dacl = *acl; ufs_sync_acl_from_inode(ip, acl); break; @@ -1470,6 +1509,7 @@ ufs_mkdir(ap) * Just use the mode as-is. */ ip->i_mode = dmode; + DIP(ip, i_mode) = dmode; FREE(acl, M_ACL); FREE(dacl, M_ACL); dacl = acl = NULL; @@ -1482,14 +1522,18 @@ ufs_mkdir(ap) } #else /* !UFS_ACL */ ip->i_mode = dmode; + DIP(ip, i_mode) = dmode; #endif /* !UFS_ACL */ tvp->v_type = VDIR; /* Rest init'd in getnewvnode(). */ ip->i_effnlink = 2; ip->i_nlink = 2; + DIP(ip, i_nlink) = 2; if (DOINGSOFTDEP(tvp)) softdep_change_linkcnt(ip); - if (cnp->cn_flags & ISWHITEOUT) + if (cnp->cn_flags & ISWHITEOUT) { ip->i_flags |= UF_OPAQUE; + DIP(ip, i_flags) = ip->i_flags; + } /* * Bump link count in parent directory to reflect work done below. @@ -1498,6 +1542,7 @@ ufs_mkdir(ap) */ dp->i_effnlink++; dp->i_nlink++; + DIP(dp, i_nlink) = dp->i_nlink; dp->i_flag |= IN_CHANGE; if (DOINGSOFTDEP(dvp)) softdep_change_linkcnt(dp); @@ -1555,6 +1600,7 @@ ufs_mkdir(ap) B_CLRBUF, &bp)) != 0) goto bad; ip->i_size = DIRBLKSIZ; + DIP(ip, i_size) = DIRBLKSIZ; ip->i_flag |= IN_CHANGE | IN_UPDATE; vnode_pager_setsize(tvp, (u_long)ip->i_size); bcopy((caddr_t)&dirtemplate, (caddr_t)bp->b_data, sizeof dirtemplate); @@ -1602,6 +1648,7 @@ bad: } else { dp->i_effnlink--; dp->i_nlink--; + DIP(dp, i_nlink) = dp->i_nlink; dp->i_flag |= IN_CHANGE; if (DOINGSOFTDEP(dvp)) softdep_change_linkcnt(dp); @@ -1611,6 +1658,7 @@ bad: */ ip->i_effnlink = 0; ip->i_nlink = 0; + DIP(ip, i_nlink) = 0; ip->i_flag |= IN_CHANGE; if (DOINGSOFTDEP(tvp)) softdep_change_linkcnt(ip); @@ -1699,8 +1747,10 @@ ufs_rmdir(ap) */ if (!DOINGSOFTDEP(vp)) { dp->i_nlink--; + DIP(dp, i_nlink) = dp->i_nlink; dp->i_flag |= IN_CHANGE; ip->i_nlink--; + DIP(ip, i_nlink) = ip->i_nlink; ip->i_flag |= IN_CHANGE; ioflag = DOINGASYNC(vp) ? 0 : IO_SYNC; error = UFS_TRUNCATE(vp, (off_t)0, ioflag, cnp->cn_cred, @@ -1743,8 +1793,9 @@ ufs_symlink(ap) len = strlen(ap->a_target); if (len < vp->v_mount->mnt_maxsymlinklen) { ip = VTOI(vp); - bcopy(ap->a_target, (char *)ip->i_shortlink, len); + bcopy(ap->a_target, SHORTLINK(ip), len); ip->i_size = len; + DIP(ip, i_size) = len; ip->i_flag |= IN_CHANGE | IN_UPDATE; } else error = vn_rdwr(UIO_WRITE, vp, ap->a_target, len, (off_t)0, @@ -1884,12 +1935,12 @@ ufs_readlink(ap) { struct vnode *vp = ap->a_vp; struct inode *ip = VTOI(vp); - int isize; + doff_t isize; isize = ip->i_size; if ((isize < vp->v_mount->mnt_maxsymlinklen) || - (ip->i_din.di_blocks == 0)) { /* XXX - for old fastlink support */ - uiomove((char *)ip->i_shortlink, isize, ap->a_uio); + DIP(ip, i_blocks) == 0) { /* XXX - for old fastlink support */ + uiomove(SHORTLINK(ip), isize, ap->a_uio); return (0); } return (VOP_READ(vp, ap->a_uio, 0, ap->a_cred)); @@ -1912,7 +1963,7 @@ ufs_strategy(ap) struct buf *bp = ap->a_bp; struct vnode *vp = ap->a_vp; struct inode *ip; - ufs_daddr_t blkno; + ufs2_daddr_t blkno; int error; ip = VTOI(vp); @@ -2206,7 +2257,7 @@ ufs_vinit(mntp, specops, fifoops, vpp) case VCHR: case VBLK: vp->v_op = specops; - vp = addaliasu(vp, ip->i_rdev); + vp = addaliasu(vp, DIP(ip, i_rdev)); ip->i_vnode = vp; break; case VFIFO: @@ -2261,6 +2312,7 @@ ufs_makeinode(mode, dvp, vpp, cnp) return (error); ip = VTOI(tvp); ip->i_gid = pdir->i_gid; + DIP(ip, i_gid) = pdir->i_gid; #ifdef SUIDDIR { #ifdef QUOTA @@ -2278,6 +2330,7 @@ ufs_makeinode(mode, dvp, vpp, cnp) (pdir->i_mode & ISUID) && (pdir->i_uid != cnp->cn_cred->cr_uid) && pdir->i_uid) { ip->i_uid = pdir->i_uid; + DIP(ip, i_uid) = ip->i_uid; mode &= ~07111; #ifdef QUOTA /* @@ -2293,8 +2346,10 @@ ufs_makeinode(mode, dvp, vpp, cnp) ucred.cr_groups[0] = pdir->i_gid; ucp = &ucred; #endif - } else + } else { ip->i_uid = cnp->cn_cred->cr_uid; + DIP(ip, i_uid) = ip->i_uid; + } #ifdef QUOTA if ((error = getinoquota(ip)) || @@ -2307,6 +2362,7 @@ ufs_makeinode(mode, dvp, vpp, cnp) } #else /* !SUIDDIR */ ip->i_uid = cnp->cn_cred->cr_uid; + DIP(ip, i_uid) = ip->i_uid; #ifdef QUOTA if ((error = getinoquota(ip)) || (error = chkiq(ip, 1, cnp->cn_cred, 0))) { @@ -2339,6 +2395,7 @@ ufs_makeinode(mode, dvp, vpp, cnp) * not defined case. */ ip->i_mode = mode; + DIP(ip, i_mode) = mode; ufs_sync_acl_from_inode(ip, acl); break; } @@ -2348,6 +2405,7 @@ ufs_makeinode(mode, dvp, vpp, cnp) * Just use the mode as-is. */ ip->i_mode = mode; + DIP(ip, i_mode) = mode; FREE(acl, M_ACL); acl = NULL; break; @@ -2359,18 +2417,24 @@ ufs_makeinode(mode, dvp, vpp, cnp) } #else /* !UFS_ACL */ ip->i_mode = mode; + DIP(ip, i_mode) = mode; #endif /* !UFS_ACL */ tvp->v_type = IFTOVT(mode); /* Rest init'd in getnewvnode(). */ ip->i_effnlink = 1; ip->i_nlink = 1; + DIP(ip, i_nlink) = 1; if (DOINGSOFTDEP(tvp)) softdep_change_linkcnt(ip); if ((ip->i_mode & ISGID) && !groupmember(ip->i_gid, cnp->cn_cred) && - suser_cred(cnp->cn_cred, PRISON_ROOT)) + suser_cred(cnp->cn_cred, PRISON_ROOT)) { ip->i_mode &= ~ISGID; + DIP(ip, i_mode) = ip->i_mode; + } - if (cnp->cn_flags & ISWHITEOUT) + if (cnp->cn_flags & ISWHITEOUT) { ip->i_flags |= UF_OPAQUE; + DIP(ip, i_flags) = ip->i_flags; + } /* * Make sure inode goes to disk before directory entry. @@ -2422,6 +2486,7 @@ bad: */ ip->i_effnlink = 0; ip->i_nlink = 0; + DIP(ip, i_nlink) = 0; ip->i_flag |= IN_CHANGE; if (DOINGSOFTDEP(tvp)) softdep_change_linkcnt(ip); diff --git a/sys/ufs/ufs/ufsmount.h b/sys/ufs/ufs/ufsmount.h index dc995b4..99d6078 100644 --- a/sys/ufs/ufs/ufsmount.h +++ b/sys/ufs/ufs/ufsmount.h @@ -65,9 +65,8 @@ struct ufsmount { struct mount *um_mountp; /* filesystem vfs structure */ dev_t um_dev; /* device mounted */ struct vnode *um_devvp; /* block device mounted vnode */ - + u_long um_fstype; /* type of filesystem */ struct fs *um_fs; /* pointer to superblock */ - struct vnode *um_quotas[MAXQUOTAS]; /* pointer to quota files */ struct ucred *um_cred[MAXQUOTAS]; /* quota file access cred */ struct ufs_extattr_per_mount um_extattr; /* extended attrs */ @@ -95,6 +94,12 @@ struct ufsmount { #define UFS_VFREE(aa, bb, cc) VFSTOUFS((aa)->v_mount)->um_vfree(aa, bb, cc) /* + * Filesystem types + */ +#define UFS1 1 +#define UFS2 2 + +/* * Flags describing the state of quotas. */ #define QTF_OPENING 0x01 /* Q_QUOTAON in progress */ |