svn commit: r237501 - stable/9/sbin/growfs

Edward Tomasz Napierala trasz at FreeBSD.org
Sat Jun 23 19:15:13 UTC 2012


Author: trasz
Date: Sat Jun 23 19:15:12 2012
New Revision: 237501
URL: http://svn.freebsd.org/changeset/base/237501

Log:
  MFC r234846:
  
  Improve growfs(8) in a few ways; unfortunately, it's somewhat hard to untangle
  them and commit separately.
  
  1. Rewrite the way growfs(8) finds the device and mount point.  This makes
     it possible to use e.g. "growfs /mnt"; it's also used to display more
     helpful messages.
  
  2. Be more user-friendly, using descriptive messages, like this:
  
     OK to grow filesystem on /dev/md0, mounted on /mnt, from 9.8GB to 20GB? [Yes/No]"
  
  3. Allow to specify the size (-s option) just like with mdconfig(8), i.e. with
     postfixes ("mdconfig -s 10g").4. Reload read-only filesystem after growing.
  
  Reviewed by:    kib, mckusick (earlier version)
  Sponsored by:   The FreeBSD Foundation
  
  MFC r235079:
  
  Fix offset calculation to actually rewrite the _last_ block.

Modified:
  stable/9/sbin/growfs/Makefile
  stable/9/sbin/growfs/growfs.8
  stable/9/sbin/growfs/growfs.c
Directory Properties:
  stable/9/sbin/growfs/   (props changed)

Modified: stable/9/sbin/growfs/Makefile
==============================================================================
--- stable/9/sbin/growfs/Makefile	Sat Jun 23 19:08:24 2012	(r237500)
+++ stable/9/sbin/growfs/Makefile	Sat Jun 23 19:15:12 2012	(r237501)
@@ -6,12 +6,18 @@
 
 #GFSDBG=
 
+.PATH:	${.CURDIR}/../mount
+
 PROG=   growfs
-SRCS=   growfs.c
+SRCS=   growfs.c getmntopts.c
 MAN=	growfs.8
+CFLAGS+=-I${.CURDIR}/../mount
 
 .if defined(GFSDBG)
 SRCS+=  debug.c
 .endif  
 
+DPADD=	${LIBUTIL}
+LDADD=	-lutil
+
 .include <bsd.prog.mk>      

Modified: stable/9/sbin/growfs/growfs.8
==============================================================================
--- stable/9/sbin/growfs/growfs.8	Sat Jun 23 19:08:24 2012	(r237500)
+++ stable/9/sbin/growfs/growfs.8	Sat Jun 23 19:15:12 2012	(r237501)
@@ -37,7 +37,7 @@
 .\" $TSHeader: src/sbin/growfs/growfs.8,v 1.3 2000/12/12 19:31:00 tomsoft Exp $
 .\" $FreeBSD$
 .\"
-.Dd June 29, 2011
+.Dd April 30, 2012
 .Dt GROWFS 8
 .Os
 .Sh NAME
@@ -47,41 +47,20 @@
 .Nm
 .Op Fl Ny
 .Op Fl s Ar size
-.Ar special
+.Ar special | filesystem
 .Sh DESCRIPTION
 The
 .Nm
-utility extends the
-.Xr newfs 8
-program.
-Before starting
-.Nm
-the disk must be labeled to a bigger size using
-.Xr bsdlabel 8 .
-If you wish to grow a file system beyond the boundary of
-the slice it resides in, you must re-size the slice using
-.Xr gpart 8
-before running
-.Nm .
+utility makes it possible to expand an UFS file system.
+Before running
+.Nm
+the partition or slice containing the file system must be extended using
+.Xr gpart 8 .
 If you are using volumes you must enlarge them by using
 .Xr gvinum 8 .
 The
 .Nm
 utility extends the size of the file system on the specified special file.
-Currently
-.Nm
-can only enlarge unmounted file systems.
-Do not try enlarging a mounted file system, your system may panic and you will
-not be able to use the file system any longer.
-Most of the
-.Xr newfs 8
-options cannot be changed by
-.Nm .
-In fact, you can only increase the size of the file system.
-Use
-.Xr tunefs 8
-for other changes.
-.Pp
 The following options are available:
 .Bl -tag -width indent
 .It Fl N
@@ -103,6 +82,13 @@ So use this option with great care!
 Determines the
 .Ar size
 of the file system after enlarging in sectors.
+.Ar Size
+is the number of 512 byte sectors unless suffixed with a
+.Cm b , k , m , g ,
+or
+.Cm t
+which
+denotes byte, kilobyte, megabyte, gigabyte and terabyte respectively.
 This value defaults to the size of the raw partition specified in
 .Ar special
 (in other words,
@@ -110,19 +96,18 @@ This value defaults to the size of the r
 will enlarge the file system to the size of the entire partition).
 .El
 .Sh EXAMPLES
-.Dl growfs -s 4194304 /dev/vinum/testvol
+.Dl growfs -s 2G /dev/ada0p1
 .Pp
 will enlarge
-.Pa /dev/vinum/testvol
+.Pa /dev/ada0p1
 up to 2GB if there is enough space in
-.Pa /dev/vinum/testvol .
+.Pa /dev/ada0p1 .
 .Sh SEE ALSO
-.Xr bsdlabel 8 ,
 .Xr dumpfs 8 ,
 .Xr ffsinfo 8 ,
 .Xr fsck 8 ,
+.Xr fsdb 8 ,
 .Xr gpart 8 ,
-.Xr gvinum 8 ,
 .Xr newfs 8 ,
 .Xr tunefs 8
 .Sh HISTORY
@@ -134,61 +119,12 @@ utility first appeared in
 .An Christoph Herrmann Aq chm at FreeBSD.org
 .An Thomas-Henning von Kamptz Aq tomsoft at FreeBSD.org
 .An The GROWFS team Aq growfs at Tomsoft.COM
+.An Edward Tomasz Napierala Aq trasz at FreeBSD.org
 .Sh BUGS
-The
-.Nm
-utility works starting with
-.Fx
-3.x.
-There may be cases on
-.Fx
-3.x only, when
-.Nm
-does not recognize properly whether or not the file system is mounted and
-exits with an error message.
-Then please use
-.Nm
-.Fl y
-if you are sure that the file system is not mounted.
-It is also recommended to always use
-.Xr fsck 8
-after enlarging (just to be on the safe side).
-.Pp
-For enlarging beyond certain limits, it is essential to have some free blocks
-available in the first cylinder group.
-If that space is not available in the first cylinder group, a critical data
-structure has to be relocated into one of the new available cylinder groups.
-On
-.Fx
-3.x this will cause problems with
-.Xr fsck 8
-afterwards.
-So
-.Xr fsck 8
-needs to be patched if you want to use
-.Nm
-for
-.Fx
-3.x.
-This patch is already integrated in
-.Fx
-starting with
-.Fx 4.4 .
-To avoid an unexpected relocation of that structure it is possible to use
-.Nm ffsinfo
-.Fl g Ar 0
-.Fl l Ar 4
-on the first cylinder group to verify that
-.Em nbfree
-in the CYLINDER SUMMARY (internal cs) of the CYLINDER GROUP
-.Em cgr0
-has enough blocks.
-As a rule of thumb for default file system parameters one block is needed for
-every 2 GB of total file system size.
 .Pp
 Normally
 .Nm
-writes this critical structure to disk and reads it again later for doing more
+writes cylinder group summary to disk and reads it again later for doing more
 updates.
 This read operation will provide unexpected data when using
 .Fl N .

Modified: stable/9/sbin/growfs/growfs.c
==============================================================================
--- stable/9/sbin/growfs/growfs.c	Sat Jun 23 19:08:24 2012	(r237500)
+++ stable/9/sbin/growfs/growfs.c	Sat Jun 23 19:15:12 2012	(r237501)
@@ -1,11 +1,15 @@
 /*
- * Copyright (c) 2000 Christoph Herrmann, Thomas-Henning von Kamptz
  * Copyright (c) 1980, 1989, 1993 The Regents of the University of California.
+ * Copyright (c) 2000 Christoph Herrmann, Thomas-Henning von Kamptz
+ * Copyright (c) 2012 The FreeBSD Foundation
  * All rights reserved.
  *
  * This code is derived from software contributed to Berkeley by
  * Christoph Herrmann and Thomas-Henning von Kamptz, Munich and Frankfurt.
  *
+ * Portions of this software were developed by Edward Tomasz Napierala
+ * under sponsorship from the FreeBSD Foundation.
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
@@ -53,13 +57,18 @@ __FBSDID("$FreeBSD$");
 #include <sys/ioctl.h>
 #include <sys/stat.h>
 #include <sys/disk.h>
+#include <sys/ucred.h>
+#include <sys/mount.h>
 
 #include <stdio.h>
 #include <paths.h>
 #include <ctype.h>
 #include <err.h>
 #include <fcntl.h>
+#include <fstab.h>
+#include <inttypes.h>
 #include <limits.h>
+#include <mntopts.h>
 #include <stdlib.h>
 #include <stdint.h>
 #include <string.h>
@@ -67,6 +76,7 @@ __FBSDID("$FreeBSD$");
 #include <unistd.h>
 #include <ufs/ufs/dinode.h>
 #include <ufs/ffs/fs.h>
+#include <libutil.h>
 
 #include "debug.h"
 
@@ -109,7 +119,7 @@ static void	updjcg(int, time_t, int, int
 static void	updcsloc(time_t, int, int, unsigned int);
 static void	frag_adjust(ufs2_daddr_t, int);
 static void	updclst(int);
-static void	get_dev_size(int, int *);
+static void	mount_reload(const struct statfs *stfs);
 
 /*
  * Here we actually start growing the file system. We basically read the
@@ -177,6 +187,7 @@ growfs(int fsi, int fso, unsigned int Nf
 	/*
 	 * Dump out summary information about file system.
 	 */
+#ifdef FS_DEBUG
 #define B2MBFACTOR (1 / (1024.0 * 1024.0))
 	printf("growfs: %.1fMB (%jd sectors) block size %d, fragment size %d\n",
 	    (float)sblock.fs_size * sblock.fs_fsize * B2MBFACTOR,
@@ -188,6 +199,7 @@ growfs(int fsi, int fso, unsigned int Nf
 	if (sblock.fs_flags & FS_DOSOFTDEP)
 		printf("\twith soft updates\n");
 #undef B2MBFACTOR
+#endif /* FS_DEBUG */
 
 	/*
 	 * Now build the cylinders group blocks and
@@ -774,7 +786,7 @@ updjcg(int cylno, time_t modtime, int fs
 
 /*
  * Here we update the location of the cylinder summary. We have two possible
- * ways of growing the cylinder summary.
+ * ways of growing the cylinder summary:
  * (1)	We can try to grow the summary in the current location, and relocate
  *	possibly used blocks within the current cylinder group.
  * (2)	Alternatively we can relocate the whole cylinder summary to the first
@@ -1238,24 +1250,104 @@ charsperline(void)
 	return (columns);
 }
 
+static int
+is_dev(const char *name)
+{
+	struct stat devstat;
+
+	if (stat(name, &devstat) != 0)
+		return (0);
+	if (!S_ISCHR(devstat.st_mode))
+		return (0);
+	return (1);
+}
+
 /*
- * Get the size of the partition.
- */
-static void
-get_dev_size(int fd, int *size)
+ * Return mountpoint on which the device is currently mounted.
+ */ 
+static const struct statfs *
+dev_to_statfs(const char *dev)
 {
-	int sectorsize;
-	off_t mediasize;
+	struct stat devstat, mntdevstat;
+	struct statfs *mntbuf, *statfsp;
+	char device[MAXPATHLEN];
+	char *mntdevname;
+	int i, mntsize;
+
+	/*
+	 * First check the mounted filesystems.
+	 */
+	if (stat(dev, &devstat) != 0)
+		return (NULL);
+	if (!S_ISCHR(devstat.st_mode) && !S_ISBLK(devstat.st_mode))
+		return (NULL);
+
+	mntsize = getmntinfo(&mntbuf, MNT_NOWAIT);
+	for (i = 0; i < mntsize; i++) {
+		statfsp = &mntbuf[i];
+		mntdevname = statfsp->f_mntfromname;
+		if (*mntdevname != '/') {
+			strcpy(device, _PATH_DEV);
+			strcat(device, mntdevname);
+			mntdevname = device;
+		}
+		if (stat(mntdevname, &mntdevstat) == 0 &&
+		    mntdevstat.st_rdev == devstat.st_rdev)
+			return (statfsp);
+	}
 
-	if (ioctl(fd, DIOCGSECTORSIZE, &sectorsize) == -1)
-		err(1,"DIOCGSECTORSIZE");
-	if (ioctl(fd, DIOCGMEDIASIZE, &mediasize) == -1)
-		err(1,"DIOCGMEDIASIZE");
+	return (NULL);
+}
 
-	if (sectorsize <= 0)
-		errx(1, "bogus sectorsize: %d", sectorsize);
+static const char *
+mountpoint_to_dev(const char *mountpoint)
+{
+	struct statfs *mntbuf, *statfsp;
+	struct fstab *fs;
+	int i, mntsize;
 
-	*size = mediasize / sectorsize;
+	/*
+	 * First check the mounted filesystems.
+	 */
+	mntsize = getmntinfo(&mntbuf, MNT_NOWAIT);
+	for (i = 0; i < mntsize; i++) {
+		statfsp = &mntbuf[i];
+
+		if (strcmp(statfsp->f_mntonname, mountpoint) == 0)
+			return (statfsp->f_mntfromname);
+	}
+
+	/*
+	 * Check the fstab.
+	 */
+	fs = getfsfile(mountpoint);
+	if (fs != NULL)
+		return (fs->fs_spec);
+
+	return (NULL);
+}
+
+static const char *
+getdev(const char *name)
+{
+	static char device[MAXPATHLEN];
+	const char *cp, *dev;
+
+	if (is_dev(name))
+		return (name);
+
+	cp = strrchr(name, '/');
+	if (cp == 0) {
+		snprintf(device, sizeof(device), "%s%s", _PATH_DEV, name);
+		if (is_dev(device))
+			return (device);
+	}
+
+	dev = mountpoint_to_dev(name);
+	if (dev != NULL && is_dev(dev))
+		return (dev);
+
+	return (NULL);
 }
 
 /*
@@ -1283,17 +1375,13 @@ int
 main(int argc, char **argv)
 {
 	DBG_FUNC("main")
-	char *device, *special;
-	int ch;
-	unsigned int size = 0;
-	size_t len;
-	unsigned int Nflag = 0;
-	int ExpertFlag = 0;
-	struct stat st;
-	int i, fsi, fso;
-	u_int32_t p_size;
-	char reply[5];
-	int j;
+	const char *device;
+	const struct statfs *statfsp;
+	uint64_t size = 0;
+	off_t mediasize;
+	int error, i, j, fsi, fso, ch, Nflag = 0, yflag = 0;
+	char *p, reply[5], oldsizebuf[6], newsizebuf[6];
+	void *testbuf;
 
 	DBG_ENTER;
 
@@ -1303,14 +1391,27 @@ main(int argc, char **argv)
 			Nflag = 1;
 			break;
 		case 's':
-			size = (size_t)atol(optarg);
-			if (size < 1)
-				usage();
+			size = (off_t)strtoumax(optarg, &p, 0);
+			if (p == NULL || *p == '\0')
+				size *= DEV_BSIZE;
+			else if (*p == 'b' || *p == 'B')
+				; /* do nothing */
+			else if (*p == 'k' || *p == 'K')
+				size <<= 10;
+			else if (*p == 'm' || *p == 'M')
+				size <<= 20;
+			else if (*p == 'g' || *p == 'G')
+				size <<= 30;
+			else if (*p == 't' || *p == 'T') {
+				size <<= 30;
+				size <<= 10;
+			} else
+				errx(1, "unknown suffix on -s argument");
 			break;
 		case 'v': /* for compatibility to newfs */
 			break;
 		case 'y':
-			ExpertFlag = 1;
+			yflag = 1;
 			break;
 		case '?':
 			/* FALLTHROUGH */
@@ -1324,71 +1425,29 @@ main(int argc, char **argv)
 	if (argc != 1)
 		usage();
 
-	device = *argv;
-
 	/*
-	 * Now try to guess the (raw)device name.
+	 * Now try to guess the device name.
 	 */
-	if (0 == strrchr(device, '/')) {
-		/*
-		 * No path prefix was given, so try in that order:
-		 *     /dev/r%s
-		 *     /dev/%s
-		 *     /dev/vinum/r%s
-		 *     /dev/vinum/%s.
-		 *
-		 * FreeBSD now doesn't distinguish between raw and block
-		 * devices any longer, but it should still work this way.
-		 */
-		len = strlen(device) + strlen(_PATH_DEV) + 2 + strlen("vinum/");
-		special = (char *)malloc(len);
-		if (special == NULL)
-			errx(1, "malloc failed");
-		snprintf(special, len, "%sr%s", _PATH_DEV, device);
-		if (stat(special, &st) == -1) {
-			snprintf(special, len, "%s%s", _PATH_DEV, device);
-			if (stat(special, &st) == -1) {
-				snprintf(special, len, "%svinum/r%s",
-				    _PATH_DEV, device);
-				if (stat(special, &st) == -1) {
-					/* For now this is the 'last resort' */
-					snprintf(special, len, "%svinum/%s",
-					    _PATH_DEV, device);
-				}
-			}
-		}
-		device = special;
-	}
+	device = getdev(*argv);
+	if (device == NULL)
+		errx(1, "cannot find special device for %s", *argv);
 
-	/*
-	 * Try to access our devices for writing ...
-	 */
-	if (Nflag) {
-		fso = -1;
-	} else {
-		fso = open(device, O_WRONLY);
-		if (fso < 0)
-			err(1, "%s", device);
-	}
+	statfsp = dev_to_statfs(device);
 
-	/*
-	 * ... and reading.
-	 */
 	fsi = open(device, O_RDONLY);
 	if (fsi < 0)
 		err(1, "%s", device);
 
 	/*
-	 * Try to guess the slice if not specified. This code should guess
-	 * the right thing and avoid to bother the user with the task
-	 * of specifying the option -v on vinum volumes.
+	 * Try to guess the slice size if not specified.
 	 */
-	get_dev_size(fsi, &p_size);
+	if (ioctl(fsi, DIOCGMEDIASIZE, &mediasize) == -1)
+		err(1,"DIOCGMEDIASIZE");
 
 	/*
 	 * Check if that partition is suitable for growing a file system.
 	 */
-	if (p_size < 1)
+	if (mediasize < 1)
 		errx(1, "partition is unavailable");
 
 	/*
@@ -1414,16 +1473,36 @@ main(int argc, char **argv)
 	/*
 	 * Determine size to grow to. Default to the device size.
 	 */
-	sblock.fs_size = dbtofsb(&osblock, p_size);
-	if (size != 0) {
-		if (size > p_size)
-			errx(1, "there is not enough space (%d < %d)",
-			    p_size, size);
-		sblock.fs_size = dbtofsb(&osblock, size);
+	if (size == 0)
+		size = mediasize;
+	else {
+		if (size > (uint64_t)mediasize) {
+			humanize_number(oldsizebuf, sizeof(oldsizebuf), size,
+			    "B", HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
+			humanize_number(newsizebuf, sizeof(newsizebuf),
+			    mediasize,
+			    "B", HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
+
+			errx(1, "requested size %s is larger "
+			    "than the available %s", oldsizebuf, newsizebuf);
+		}
+	}
+
+	if (size <= (uint64_t)(osblock.fs_size * osblock.fs_fsize)) {
+		humanize_number(oldsizebuf, sizeof(oldsizebuf),
+		    osblock.fs_size * osblock.fs_fsize,
+		    "B", HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
+		humanize_number(newsizebuf, sizeof(newsizebuf), size,
+		    "B", HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
+
+		errx(1, "requested size %s is not larger than the current "
+		   "filesystem size %s", newsizebuf, oldsizebuf);
 	}
 
+	sblock.fs_size = dbtofsb(&osblock, size / DEV_BSIZE);
+
 	/*
-	 * Are we really growing ?
+	 * Are we really growing?
 	 */
 	if (osblock.fs_size >= sblock.fs_size) {
 		errx(1, "we are not growing (%jd->%jd)",
@@ -1433,7 +1512,7 @@ main(int argc, char **argv)
 	/*
 	 * Check if we find an active snapshot.
 	 */
-	if (ExpertFlag == 0) {
+	if (yflag == 0) {
 		for (j = 0; j < FSMAXSNAP; j++) {
 			if (sblock.fs_snapinum[j]) {
 				errx(1, "active snapshot found in file system; "
@@ -1445,10 +1524,23 @@ main(int argc, char **argv)
 		}
 	}
 
-	if (ExpertFlag == 0 && Nflag == 0) {
-		printf("We strongly recommend you to make a backup "
+	if (yflag == 0 && Nflag == 0) {
+		if (statfsp != NULL && (statfsp->f_flags & MNT_RDONLY) == 0)
+			errx(1, "%s is mounted read-write on %s",
+			    statfsp->f_mntfromname, statfsp->f_mntonname);
+		printf("It's strongly recommended to make a backup "
 		    "before growing the file system.\n"
-		    "Did you backup your data (Yes/No)? ");
+		    "OK to grow filesystem on %s", device);
+		if (statfsp != NULL)
+			printf(", mounted on %s,", statfsp->f_mntonname);
+		humanize_number(oldsizebuf, sizeof(oldsizebuf),
+		    osblock.fs_size * osblock.fs_fsize,
+		    "B", HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
+		humanize_number(newsizebuf, sizeof(newsizebuf),
+		    sblock.fs_size * sblock.fs_fsize,
+		    "B", HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
+		printf(" from %s to %s? [Yes/No] ", oldsizebuf, newsizebuf);
+		fflush(stdout);
 		fgets(reply, (int)sizeof(reply), stdin);
 		if (strcmp(reply, "Yes\n")){
 			printf("\nNothing done\n");
@@ -1456,15 +1548,30 @@ main(int argc, char **argv)
 		}
 	}
 
-	printf("New file system size is %jd frags\n", (intmax_t)sblock.fs_size);
+	/*
+	 * Try to access our device for writing.  If it's not mounted,
+	 * or mounted read-only, simply open it; otherwise, use UFS
+	 * suspension mechanism.
+	 */
+	if (Nflag) {
+		fso = -1;
+	} else {
+		fso = open(device, O_WRONLY);
+		if (fso < 0)
+			err(1, "%s", device);
+	}
 
 	/*
-	 * Try to access our new last block in the file system. Even if we
-	 * later on realize we have to abort our operation, on that block
-	 * there should be no data, so we can't destroy something yet.
+	 * Try to access our new last block in the file system.
 	 */
-	wtfs((ufs2_daddr_t)p_size - 1, (size_t)DEV_BSIZE, (void *)&sblock,
-	    fso, Nflag);
+	testbuf = malloc(sblock.fs_fsize);
+	if (testbuf == NULL)
+		err(1, "malloc");
+	rdfs((ufs2_daddr_t)((size - sblock.fs_fsize) / DEV_BSIZE),
+	    sblock.fs_fsize, testbuf, fsi);
+	wtfs((ufs2_daddr_t)((size - sblock.fs_fsize) / DEV_BSIZE),
+	    sblock.fs_fsize, testbuf, fso, Nflag);
+	free(testbuf);
 
 	/*
 	 * Now calculate new superblock values and check for reasonable
@@ -1520,8 +1627,13 @@ main(int argc, char **argv)
 	growfs(fsi, fso, Nflag);
 
 	close(fsi);
-	if (fso > -1)
-		close(fso);
+	if (fso > -1) {
+		error = close(fso);
+		if (error != 0)
+			err(1, "close");
+	}
+	if (statfsp != NULL)
+		mount_reload(statfsp);
 
 	DBG_CLOSE;
 
@@ -1539,7 +1651,7 @@ usage(void)
 
 	DBG_ENTER;
 
-	fprintf(stderr, "usage: growfs [-Ny] [-s size] special\n");
+	fprintf(stderr, "usage: growfs [-Ny] [-s size] special | filesystem\n");
 
 	DBG_LEAVE;
 	exit(1);
@@ -1586,3 +1698,26 @@ updclst(int block)
 	DBG_LEAVE;
 	return;
 }
+
+static void
+mount_reload(const struct statfs *stfs)
+{
+	char errmsg[255];
+	struct iovec *iov;
+	int iovlen;
+
+	iov = NULL;
+	iovlen = 0;
+	*errmsg = '\0';
+	build_iovec(&iov, &iovlen, "fstype", __DECONST(char *, "ffs"), 4);
+	build_iovec(&iov, &iovlen, "fspath", __DECONST(char *, stfs->f_mntonname), (size_t)-1);
+	build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof(errmsg));
+	build_iovec(&iov, &iovlen, "update", NULL, 0);
+	build_iovec(&iov, &iovlen, "reload", NULL, 0);
+
+	if (nmount(iov, iovlen, stfs->f_flags) < 0) {
+		errmsg[sizeof(errmsg) - 1] = '\0';
+		err(9, "%s: cannot reload filesystem%s%s", stfs->f_mntonname,
+		    *errmsg != '\0' ? ": " : "", errmsg);
+	}
+}


More information about the svn-src-stable-9 mailing list