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
This commit is contained in:
parent
14c0cbcf62
commit
65de4208e7
@ -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>
|
||||
|
@ -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
|
||||
utility makes it possible to expand an UFS file system.
|
||||
Before running
|
||||
.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 .
|
||||
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 raw partition specified in
|
||||
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@FreeBSD.org
|
||||
.An Thomas-Henning von Kamptz Aq tomsoft@FreeBSD.org
|
||||
.An The GROWFS team Aq growfs@Tomsoft.COM
|
||||
.An Edward Tomasz Napierala Aq trasz@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 .
|
||||
|
@ -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, unsigned 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 Nflag)
|
||||
/*
|
||||
* 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 Nflag)
|
||||
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 fsi, int fso, unsigned int Nflag)
|
||||
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the size of the partition.
|
||||
*/
|
||||
static void
|
||||
get_dev_size(int fd, int *size)
|
||||
static int
|
||||
is_dev(const char *name)
|
||||
{
|
||||
int sectorsize;
|
||||
off_t mediasize;
|
||||
struct stat devstat;
|
||||
|
||||
if (ioctl(fd, DIOCGSECTORSIZE, §orsize) == -1)
|
||||
err(1,"DIOCGSECTORSIZE");
|
||||
if (ioctl(fd, DIOCGMEDIASIZE, &mediasize) == -1)
|
||||
err(1,"DIOCGMEDIASIZE");
|
||||
if (stat(name, &devstat) != 0)
|
||||
return (0);
|
||||
if (!S_ISCHR(devstat.st_mode))
|
||||
return (0);
|
||||
return (1);
|
||||
}
|
||||
|
||||
if (sectorsize <= 0)
|
||||
errx(1, "bogus sectorsize: %d", sectorsize);
|
||||
/*
|
||||
* Return mountpoint on which the device is currently mounted.
|
||||
*/
|
||||
static const struct statfs *
|
||||
dev_to_statfs(const char *dev)
|
||||
{
|
||||
struct stat devstat, mntdevstat;
|
||||
struct statfs *mntbuf, *statfsp;
|
||||
char device[MAXPATHLEN];
|
||||
char *mntdevname;
|
||||
int i, mntsize;
|
||||
|
||||
*size = mediasize / sectorsize;
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
static const char *
|
||||
mountpoint_to_dev(const char *mountpoint)
|
||||
{
|
||||
struct statfs *mntbuf, *statfsp;
|
||||
struct fstab *fs;
|
||||
int i, mntsize;
|
||||
|
||||
/*
|
||||
* 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 / DEV_BSIZE) - sblock.fs_fsize),
|
||||
sblock.fs_fsize, testbuf, fsi);
|
||||
wtfs((ufs2_daddr_t)((size / DEV_BSIZE) - sblock.fs_fsize),
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user