1 /* $NetBSD: resize_lfs.c,v 1.5 2006/11/11 14:47:28 jmmv Exp $ */
3 * Copyright (c) 2005 The NetBSD Foundation, Inc.
6 * This code is derived from software contributed to The NetBSD Foundation
7 * by Konrad E. Schroder <perseant@hhhh.org>.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
19 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
22 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
31 #include <sys/param.h>
32 #include <sys/types.h>
34 #include <sys/ioctl.h>
35 #include <sys/disklabel.h>
38 #include <sys/mount.h>
39 #include <sys/statvfs.h>
41 #include <ufs/ufs/dinode.h>
42 #include <ufs/lfs/lfs.h>
56 errx(1, "usage: resize_lfs [-v] [-s new-size] [filesystem]");
60 main(int argc
, char **argv
)
62 char *rdev
, *fsname
, buf
[LFS_SBPAD
];
63 daddr_t newsize
, newnsegs
;
68 struct dkwedge_info dkw
;
72 /* Initialize and parse arguments */
75 while ((ch
= getopt(argc
, argv
, "s:v")) != -1) {
77 case 's': /* New size, in sectors */
78 newsize
= strtoll(optarg
, NULL
, 10);
87 fsname
= argv
[optind
];
93 * If the user did not supply a filesystem size, use the
94 * length of the mounted partition.
96 if (statvfs(fsname
, &vfs
) < 0)
98 rdev
= (char *)malloc(strlen(vfs
.f_mntfromname
+ 2));
99 sprintf(rdev
, "/dev/r%s", vfs
.f_mntfromname
+ 5);
100 devfd
= open(rdev
, O_RDONLY
);
102 err(1, "open raw device");
105 * Read the disklabel to find the sector size. Check the
106 * given size against the partition size. We can skip some
107 * error checking here since we know the fs is mountable.
109 if (getdiskinfo(rdev
, devfd
, NULL
, &geo
, &dkw
) == -1)
110 err(1, "%s: could not get info", rdev
);
111 secsize
= geo
.dg_secsize
;
112 if (newsize
> dkw
.dkw_size
)
113 errx(1, "new size must be <= the partition size");
115 newsize
= dkw
.dkw_size
;
117 /* Open the root of the filesystem so we can fcntl() it */
118 rootfd
= open(fsname
, O_RDONLY
);
120 err(1, "open filesystem root");
122 /* Read the superblock, finding alternates if necessary */
123 fs
= (struct lfs
*)malloc(sizeof(*fs
));
124 for (sboff
= LFS_LABELPAD
;;) {
125 pread(devfd
, buf
, sboff
, LFS_SBPAD
);
126 memcpy(&fs
->lfs_dlfs
, buf
, sizeof(struct dlfs
));
127 if (sboff
== LFS_LABELPAD
&& fsbtob(fs
, 1) > LFS_LABELPAD
)
128 sboff
= fsbtob(fs
, (off_t
)fs
->lfs_sboffs
[0]);
134 /* Calculate new number of segments. */
135 newnsegs
= (newsize
* secsize
) / fs
->lfs_ssize
;
136 if (newnsegs
== fs
->lfs_nseg
) {
137 errx(0, "the filesystem is unchanged.");
141 * If the new filesystem is smaller than the old, we have to
142 * invalidate the segments that extend beyond the new boundary.
143 * Make the cleaner do this for us.
144 * (XXX make the kernel able to do this instead?)
146 for (i
= fs
->lfs_nseg
- 1; i
>= newnsegs
; --i
) {
149 /* If it's already empty, don't call the cleaner */
150 if (fcntl(rootfd
, LFCNINVAL
, &i
) == 0)
153 sprintf(cmd
, "/libexec/lfs_cleanerd -q -i %d %s", i
, fsname
);
154 if (system(cmd
) != 0)
155 err(1, "invalidating segment %d", i
);
158 /* Tell the filesystem to resize itself. */
159 if (fcntl(rootfd
, LFCNRESIZE
, &newnsegs
) == -1) {
164 printf("Successfully resized %s from %d to %lld segments\n",
165 fsname
, fs
->lfs_nseg
, (long long)newnsegs
);