svn commit: r185588 - head/sbin/newfs

Paul Saab ps at mu.org
Mon Dec 8 23:42:52 PST 2008


This requires all devices end in 'a' - 'h'.  This breaks newfsing zfs
volumes with arbitrary names,

On Wed, Dec 3, 2008 at 10:37 AM, Luigi Rizzo <luigi at freebsd.org> wrote:

> Author: luigi
> Date: Wed Dec  3 18:36:59 2008
> New Revision: 185588
> URL: http://svn.freebsd.org/changeset/base/185588
>
> Log:
>  Enable operation of newfs on plain files, which is useful when you
>  want to prepare disk images for emulators (though 'makefs' in port
>  can do something similar).
>
>  This relies on:
>  + minor changes to pass the consistency checks even when working on a
> file;
>
>  + an additional option, '-p partition' , to specify the disk partition to
>    initialize;
>
>  + some changes on the I/O routines to deal with partition offsets.
>
>  The latter was a bit tricky to implement, see the details in newfs.h:
>  in newfs, I/O is done through libufs which assumes that the file
>  descriptor refers to the whole partition. Introducing support for
>  the offset in libufs would require a non-backward compatible change
>  in the library, to be dealt with a version bump or with symbol
>  versioning.
>
>  I felt both approaches to be overkill for this specific application,
>  especially because there might be other changes to libufs that might
>  become necessary in the near future.
>
>  So I used the following trick:
>  - read access is always done by calling bread() directly, so we just add
>    the offset in the (few) places that call bread();
>  - write access is done through bwrite() and sbwrite(), which in turn
>    calls bwrite(). To avoid rewriting sbwrite(), we supply our own version
>    of bwrite() here, which takes precedence over the version in libufs.
>
>  MFC after:    4 weeks
>
> Modified:
>  head/sbin/newfs/Makefile
>  head/sbin/newfs/mkfs.c
>  head/sbin/newfs/newfs.8
>  head/sbin/newfs/newfs.c
>  head/sbin/newfs/newfs.h
>
> Modified: head/sbin/newfs/Makefile
>
> ==============================================================================
> --- head/sbin/newfs/Makefile    Wed Dec  3 18:22:36 2008        (r185587)
> +++ head/sbin/newfs/Makefile    Wed Dec  3 18:36:59 2008        (r185588)
> @@ -1,10 +1,13 @@
>  #      @(#)Makefile    8.2 (Berkeley) 3/27/94
>  # $FreeBSD$
>
> +.PATH: ${.CURDIR}/../../sys/geom
> +
>  PROG=  newfs
>  DPADD= ${LIBUFS}
>  LDADD= -lufs
> -SRCS=  newfs.c mkfs.c
> +SRCS=  newfs.c mkfs.c geom_bsd_enc.c
> +
>  WARNS?=        2
>  MAN=   newfs.8
>
>
> Modified: head/sbin/newfs/mkfs.c
>
> ==============================================================================
> --- head/sbin/newfs/mkfs.c      Wed Dec  3 18:22:36 2008        (r185587)
> +++ head/sbin/newfs/mkfs.c      Wed Dec  3 18:36:59 2008        (r185588)
> @@ -459,7 +459,7 @@ mkfs(struct partition *pp, char *fsys)
>         * Wipe out old UFS1 superblock(s) if necessary.
>         */
>        if (!Nflag && Oflag != 1) {
> -               i = bread(&disk, SBLOCK_UFS1 / disk.d_bsize, chdummy,
> SBLOCKSIZE);
> +               i = bread(&disk, part_ofs + SBLOCK_UFS1 / disk.d_bsize,
> chdummy, SBLOCKSIZE);
>                if (i == -1)
>                        err(1, "can't read old UFS1 superblock: %s",
> disk.d_error);
>
> @@ -872,7 +872,7 @@ alloc(int size, int mode)
>  {
>        int i, d, blkno, frag;
>
> -       bread(&disk, fsbtodb(&sblock, cgtod(&sblock, 0)), (char *)&acg,
> +       bread(&disk, part_ofs + fsbtodb(&sblock, cgtod(&sblock, 0)), (char
> *)&acg,
>            sblock.fs_cgsize);
>        if (acg.cg_magic != CG_MAGIC) {
>                printf("cg 0: bad magic number\n");
> @@ -925,7 +925,7 @@ iput(union dinode *ip, ino_t ino)
>        int c;
>
>        c = ino_to_cg(&sblock, ino);
> -       bread(&disk, fsbtodb(&sblock, cgtod(&sblock, 0)), (char *)&acg,
> +       bread(&disk, part_ofs + fsbtodb(&sblock, cgtod(&sblock, 0)), (char
> *)&acg,
>            sblock.fs_cgsize);
>        if (acg.cg_magic != CG_MAGIC) {
>                printf("cg 0: bad magic number\n");
> @@ -942,7 +942,7 @@ iput(union dinode *ip, ino_t ino)
>                exit(32);
>        }
>        d = fsbtodb(&sblock, ino_to_fsba(&sblock, ino));
> -       bread(&disk, d, (char *)iobuf, sblock.fs_bsize);
> +       bread(&disk, part_ofs + d, (char *)iobuf, sblock.fs_bsize);
>        if (sblock.fs_magic == FS_UFS1_MAGIC)
>                ((struct ufs1_dinode *)iobuf)[ino_to_fsbo(&sblock, ino)] =
>                    ip->dp1;
>
> Modified: head/sbin/newfs/newfs.8
>
> ==============================================================================
> --- head/sbin/newfs/newfs.8     Wed Dec  3 18:22:36 2008        (r185587)
> +++ head/sbin/newfs/newfs.8     Wed Dec  3 18:36:59 2008        (r185588)
> @@ -52,6 +52,7 @@
>  .Op Fl i Ar bytes
>  .Op Fl m Ar free-space
>  .Op Fl o Ar optimization
> +.Op Fl p Ar partition
>  .Op Fl r Ar reserved
>  .Op Fl s Ar size
>  .Ar special
> @@ -201,6 +202,17 @@ the default is to optimize for
>  See
>  .Xr tunefs 8
>  for more details on how to set this option.
> +.It Fl p Ar partition
> +The partition name (a..h) you want to use in case the underlying image
> +is a file, so you don't have access to individual partitions through the
> +filesystem.
> +Can also be used with a device, e.g.
> +.Nm
> +.Fl p Ar f
> +.Ar /dev/da1s3
> +is equivalent to
> +.Nm
> +.Ar /dev/da1s3f .
>  .It Fl r Ar reserved
>  The size, in sectors, of reserved space
>  at the end of the partition specified in
>
> Modified: head/sbin/newfs/newfs.c
>
> ==============================================================================
> --- head/sbin/newfs/newfs.c     Wed Dec  3 18:22:36 2008        (r185587)
> +++ head/sbin/newfs/newfs.c     Wed Dec  3 18:36:59 2008        (r185588)
> @@ -139,6 +139,9 @@ u_char      *volumelabel = NULL;    /* volume la
>  struct uufsd disk;             /* libufs disk structure */
>
>  static char    device[MAXPATHLEN];
> +static u_char   bootarea[BBSIZE];
> +static int     is_file;                /* work on a file, not a device */
> +static char    *dkname;
>  static char    *disktype;
>  static int     unlabeled;
>
> @@ -147,6 +150,18 @@ static struct disklabel *getdisklabel(ch
>  static void rewritelabel(char *s, struct disklabel *lp);
>  static void usage(void);
>
> +ufs2_daddr_t part_ofs; /* partition offset in blocks, used with files */
> +
> +/*
> + * need to replace the library's bwrite so that sbwrite uses this one
> + */
> +ssize_t
> +bwrite(struct uufsd *disk, ufs2_daddr_t blockno, const void *data, size_t
> size)
> +{
> +       return pwrite(disk->d_fd, data, size,
> +               (off_t)((part_ofs + blockno) * disk->d_bsize));
> +}
> +
>  int
>  main(int argc, char *argv[])
>  {
> @@ -158,7 +173,9 @@ main(int argc, char *argv[])
>        intmax_t reserved;
>        int ch, i;
>        off_t mediasize;
> +       char part_name;         /* partition name, default to full disk */
>
> +       part_name = 'c';
>        reserved = 0;
>        while ((ch = getopt(argc, argv,
>            "EJL:NO:RS:T:UXa:b:c:d:e:f:g:h:i:lm:no:r:s:")) != -1)
> @@ -276,6 +293,11 @@ main(int argc, char *argv[])
>                            *cp != '\0' || reserved < 0)
>                                errx(1, "%s: bad reserved size", optarg);
>                        break;
> +               case 'p':
> +                       is_file = 1;
> +                       part_name = optarg[0];
> +                       break;
> +
>                case 's':
>                        errno = 0;
>                        fssize = strtoimax(optarg, &cp, 0);
> @@ -294,6 +316,8 @@ main(int argc, char *argv[])
>                usage();
>
>        special = argv[0];
> +       if (!special[0])
> +               err(1, "empty file/special name");
>        cp = strrchr(special, '/');
>        if (cp == 0) {
>                /*
> @@ -303,7 +327,16 @@ main(int argc, char *argv[])
>                special = device;
>        }
>
> -       if (ufs_disk_fillout_blank(&disk, special) == -1 ||
> +       if (is_file) {
> +               /* bypass ufs_disk_fillout_blank */
> +               bzero( &disk, sizeof(disk));
> +               disk.d_bsize = 1;
> +               disk.d_name = special;
> +               disk.d_fd = open(special, O_RDONLY);
> +               if (disk.d_fd < 0 ||
> +                   (!Nflag && ufs_disk_write(&disk) == -1))
> +                       errx(1, "%s: ", special);
> +       } else if (ufs_disk_fillout_blank(&disk, special) == -1 ||
>            (!Nflag && ufs_disk_write(&disk) == -1)) {
>                if (disk.d_error != NULL)
>                        errx(1, "%s: %s", special, disk.d_error);
> @@ -312,22 +345,30 @@ main(int argc, char *argv[])
>        }
>        if (fstat(disk.d_fd, &st) < 0)
>                err(1, "%s", special);
> -       if ((st.st_mode & S_IFMT) != S_IFCHR)
> -               errx(1, "%s: not a character-special device", special);
> +       if ((st.st_mode & S_IFMT) != S_IFCHR) {
> +               warn("%s: not a character-special device", special);
> +               is_file = 1;    /* assume it is a file */
> +               dkname = special;
> +               if (sectorsize == 0)
> +                       sectorsize = 512;
> +               mediasize = st.st_size;
> +               /* set fssize from the partition */
> +       } else {
> +           part_name = special[strlen(special) - 1];
> +           if ((part_name < 'a' || part_name > 'h') &&
> !isdigit(part_name))
> +               errx(1, "%s: can't figure out file system partition",
> +                               special);
>
> -       if (sectorsize == 0)
> +           if (sectorsize == 0)
>                if (ioctl(disk.d_fd, DIOCGSECTORSIZE, &sectorsize) == -1)
> -                       sectorsize = 0; /* back out on error for safety */
> -       if (sectorsize && ioctl(disk.d_fd, DIOCGMEDIASIZE, &mediasize) !=
> -1)
> +                   sectorsize = 0;     /* back out on error for safety */
> +           if (sectorsize && ioctl(disk.d_fd, DIOCGMEDIASIZE, &mediasize)
> != -1)
>                getfssize(&fssize, special, mediasize / sectorsize,
> reserved);
> +       }
>        pp = NULL;
>        lp = getdisklabel(special);
>        if (lp != NULL) {
> -               cp = strchr(special, '\0');
> -               cp--;
> -               if ((*cp < 'a' || *cp > 'h') && !isdigit(*cp))
> -                       errx(1, "%s: can't figure out file system
> partition",
> -                           special);
> +               cp = &part_name;
>                if (isdigit(*cp))
>                        pp = &lp->d_partitions[RAW_PART];
>                else
> @@ -346,6 +387,8 @@ main(int argc, char *argv[])
>                        fsize = pp->p_fsize;
>                if (bsize == 0)
>                        bsize = pp->p_frag * pp->p_fsize;
> +               if (is_file)
> +                       part_ofs = pp->p_offset;
>        }
>        if (sectorsize <= 0)
>                errx(1, "%s: no default sector size", special);
> @@ -414,6 +457,19 @@ getdisklabel(char *s)
>        static struct disklabel lab;
>        struct disklabel *lp;
>
> +       if (is_file) {
> +               if (read(disk.d_fd, bootarea, BBSIZE) != BBSIZE)
> +                       err(4, "cannot read bootarea");
> +               if (bsd_disklabel_le_dec(
> +                   bootarea + (0 /* labeloffset */ +
> +                               1 /* labelsoffset */ * sectorsize),
> +                   &lab, MAXPARTITIONS))
> +                       errx(1, "no valid label found");
> +
> +               lp = &lab;
> +               return &lab;
> +       }
> +
>        if (ioctl(disk.d_fd, DIOCGDINFO, (char *)&lab) != -1)
>                return (&lab);
>        unlabeled++;
> @@ -432,6 +488,14 @@ rewritelabel(char *s, struct disklabel *
>                return;
>        lp->d_checksum = 0;
>        lp->d_checksum = dkcksum(lp);
> +       if (is_file) {
> +               bsd_disklabel_le_enc(bootarea + 0 /* labeloffset */ +
> +                       1 /* labelsoffset */ * sectorsize, lp);
> +               lseek(disk.d_fd, 0, SEEK_SET);
> +               if (write(disk.d_fd, bootarea, BBSIZE) != BBSIZE)
> +                       errx(1, "cannot write label");
> +               return;
> +       }
>        if (ioctl(disk.d_fd, DIOCWDINFO, (char *)lp) == -1)
>                warn("ioctl (WDINFO): %s: can't rewrite disk label", s);
>  }
> @@ -467,6 +531,7 @@ usage()
>        fprintf(stderr, "\t-n do not create .snap directory\n");
>        fprintf(stderr, "\t-m minimum free space %%\n");
>        fprintf(stderr, "\t-o optimization preference (`space' or
> `time')\n");
> +       fprintf(stderr, "\t-p partition name (a..h)\n");
>        fprintf(stderr, "\t-r reserved sectors at the end of device\n");
>        fprintf(stderr, "\t-s file system size (sectors)\n");
>        exit(1);
>
> Modified: head/sbin/newfs/newfs.h
>
> ==============================================================================
> --- head/sbin/newfs/newfs.h     Wed Dec  3 18:22:36 2008        (r185587)
> +++ head/sbin/newfs/newfs.h     Wed Dec  3 18:36:59 2008        (r185588)
> @@ -70,4 +70,20 @@ extern int   avgfilesperdir; /* expected n
>  extern u_char  *volumelabel;   /* volume label for filesystem */
>  extern struct uufsd disk;      /* libufs disk structure */
>
> +/*
> + * To override a limitation in libufs, export the offset (in sectors) of
> the
> + * partition on the underlying media (file or disk). The value is used as
> + * an offset for all accesses to the media through bread(), which is only
> + * invoked directly in this program.
> + * For bwrite() we need a different approach, namely override the library
> + * version with one defined here. This is because bwrite() is called also
> + * by the library function sbwrite() which we cannot intercept nor want to
> + * rewrite. As a consequence, the internal version of bwrite() adds the
> + * partition offset itself when calling the underlying function, pwrite().
> + *
> + * XXX This info really ought to go into the struct uufsd, at which point
> + * we can remove the above hack.
> + */
> +extern ufs2_daddr_t part_ofs;  /* partition offset in blocks */
> +
>  void mkfs (struct partition *, char *);
>


More information about the svn-src-all mailing list