VFS messaging/interfacing work stage 1/99. This stage replaces the old
[dragonfly.git] / sys / vfs / gnu / ext2fs / ext2_vfsops.c
CommitLineData
984263bc
MD
1/*
2 * modified for EXT2FS support in Lites 1.1
3 *
4 * Aug 1995, Godmar Back (gback@cs.utah.edu)
5 * University of Utah, Department of Computer Science
6 */
7/*
8 * Copyright (c) 1989, 1991, 1993, 1994
9 * The Regents of the University of California. All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the University of
22 * California, Berkeley and its contributors.
23 * 4. Neither the name of the University nor the names of its contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * SUCH DAMAGE.
38 *
39 * @(#)ffs_vfsops.c 8.8 (Berkeley) 4/18/94
40 * $FreeBSD: src/sys/gnu/ext2fs/ext2_vfsops.c,v 1.63.2.7 2002/07/01 00:18:51 iedowse Exp $
2d3e977e 41 * $DragonFly: src/sys/vfs/gnu/ext2fs/ext2_vfsops.c,v 1.17 2004/08/13 17:51:10 dillon Exp $
984263bc
MD
42 */
43
44#include "opt_quota.h"
45
46#include <sys/param.h>
47#include <sys/systm.h>
48#include <sys/namei.h>
49#include <sys/proc.h>
50#include <sys/kernel.h>
51#include <sys/vnode.h>
52#include <sys/mount.h>
53#include <sys/buf.h>
54#include <sys/conf.h>
55#include <sys/fcntl.h>
56#include <sys/disklabel.h>
57#include <sys/malloc.h>
58#include <sys/stat.h>
7b95be2a 59#include <sys/buf2.h>
984263bc 60
1f2de5d4
MD
61#include <vfs/ufs/quota.h>
62#include <vfs/ufs/ufsmount.h>
63#include <vfs/ufs/inode.h>
64#include <vfs/ufs/ufs_extern.h>
984263bc
MD
65
66#include <vm/vm_zone.h>
67
1f2de5d4
MD
68#include "fs.h"
69#include "ext2_extern.h"
70#include "ext2_fs.h"
71#include "ext2_fs_sb.h"
984263bc 72
a6ee311a
RG
73static int ext2_fhtovp (struct mount *, struct fid *, struct vnode **);
74static int ext2_flushfiles (struct mount *mp, int flags, struct thread *td);
75static int ext2_mount (struct mount *,
76 char *, caddr_t, struct nameidata *, struct thread *);
77static int ext2_mountfs (struct vnode *, struct mount *, struct thread *);
78static int ext2_reload (struct mount *mountp, struct ucred *cred,
79 struct thread *p);
80static int ext2_sbupdate (struct ufsmount *, int);
81static int ext2_statfs (struct mount *, struct statfs *, struct thread *);
82static int ext2_sync (struct mount *, int, struct thread *);
83static int ext2_unmount (struct mount *, int, struct thread *);
84static int ext2_vget (struct mount *, ino_t, struct vnode **);
85static int ext2_vptofh (struct vnode *, struct fid *);
984263bc
MD
86
87static MALLOC_DEFINE(M_EXT2NODE, "EXT2 node", "EXT2 vnode private part");
88
89static struct vfsops ext2fs_vfsops = {
90 ext2_mount,
91 ufs_start, /* empty function */
92 ext2_unmount,
93 ufs_root, /* root inode via vget */
94 ufs_quotactl, /* does operations associated with quotas */
95 ext2_statfs,
96 ext2_sync,
97 ext2_vget,
98 ext2_fhtovp,
99 ufs_check_export,
100 ext2_vptofh,
101 ext2_init,
102 vfs_stduninit,
103 vfs_stdextattrctl,
104};
105
106VFS_SET(ext2fs_vfsops, ext2fs, 0);
107#define bsd_malloc malloc
108#define bsd_free free
109
110static int ext2fs_inode_hash_lock;
111
a6ee311a
RG
112static int ext2_check_sb_compat (struct ext2_super_block *es,
113 dev_t dev, int ronly);
114static int compute_sb_data (struct vnode * devvp,
984263bc 115 struct ext2_super_block * es,
a6ee311a 116 struct ext2_sb_info * fs);
984263bc
MD
117
118#ifdef notyet
a6ee311a 119static int ext2_mountroot (void);
984263bc
MD
120
121/*
122 * Called by main() when ext2fs is going to be mounted as root.
123 *
124 * Name is updated by mount(8) after booting.
125 */
126#define ROOTNAME "root_device"
127
128static int
0f7f7a49 129ext2_mountroot(void)
984263bc 130{
f7aae92f
RG
131 struct ext2_sb_info *fs;
132 struct mount *mp;
7b95be2a 133 struct thread *td = curthread;
984263bc
MD
134 struct ufsmount *ump;
135 u_int size;
136 int error;
137
138 if ((error = bdevvp(rootdev, &rootvp))) {
139 printf("ext2_mountroot: can't find rootvp\n");
140 return (error);
141 }
142 mp = bsd_malloc((u_long)sizeof(struct mount), M_MOUNT, M_WAITOK);
143 bzero((char *)mp, (u_long)sizeof(struct mount));
144 TAILQ_INIT(&mp->mnt_nvnodelist);
145 TAILQ_INIT(&mp->mnt_reservedvnlist);
146 mp->mnt_op = &ext2fs_vfsops;
147 mp->mnt_flag = MNT_RDONLY;
7b95be2a 148 if (error = ext2_mountfs(rootvp, mp, td)) {
984263bc
MD
149 bsd_free(mp, M_MOUNT);
150 return (error);
151 }
152 if (error = vfs_lock(mp)) {
7b95be2a 153 (void)ext2_unmount(mp, 0, td);
984263bc
MD
154 bsd_free(mp, M_MOUNT);
155 return (error);
156 }
157 TAILQ_INSERT_HEAD(&mountlist, mp, mnt_list);
158 mp->mnt_flag |= MNT_ROOTFS;
159 mp->mnt_vnodecovered = NULLVP;
160 ump = VFSTOUFS(mp);
161 fs = ump->um_e2fs;
162 bzero(fs->fs_fsmnt, sizeof(fs->fs_fsmnt));
163 fs->fs_fsmnt[0] = '/';
164 bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname,
165 MNAMELEN);
166 (void) copystr(ROOTNAME, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
167 &size);
168 bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
7b95be2a 169 (void)ext2_statfs(mp, &mp->mnt_stat, td);
984263bc
MD
170 vfs_unlock(mp);
171 inittodr(fs->s_es->s_wtime); /* this helps to set the time */
172 return (0);
173}
174#endif
175
176/*
177 * VFS Operations.
178 *
179 * mount system call
180 */
181static int
0f7f7a49
CP
182ext2_mount(struct mount *mp, char *path,
183 caddr_t data, /* this is actually a (struct ufs_args *) */
184 struct nameidata *ndp, struct thread *td)
984263bc
MD
185{
186 struct vnode *devvp;
187 struct ufs_args args;
188 struct ufsmount *ump = 0;
f7aae92f 189 struct ext2_sb_info *fs;
984263bc
MD
190 size_t size;
191 int error, flags;
192 mode_t accessmode;
7b95be2a 193 struct ucred *cred;
984263bc
MD
194
195 if ((error = copyin(data, (caddr_t)&args, sizeof (struct ufs_args))) != 0)
196 return (error);
7b95be2a
MD
197
198 cred = td->td_proc->p_ucred;
984263bc
MD
199 /*
200 * If updating, check whether changing from read-only to
201 * read/write; if there is no device name, that's all we do.
202 */
203 if (mp->mnt_flag & MNT_UPDATE) {
204 ump = VFSTOUFS(mp);
205 fs = ump->um_e2fs;
206 error = 0;
207 if (fs->s_rd_only == 0 && (mp->mnt_flag & MNT_RDONLY)) {
208 flags = WRITECLOSE;
209 if (mp->mnt_flag & MNT_FORCE)
210 flags |= FORCECLOSE;
41a01a4d 211 if (vfs_busy(mp, LK_NOWAIT, NULL, td))
984263bc 212 return (EBUSY);
7b95be2a
MD
213 error = ext2_flushfiles(mp, flags, td);
214 vfs_unbusy(mp, td);
984263bc
MD
215 if (!error && fs->s_wasvalid) {
216 fs->s_es->s_state |= EXT2_VALID_FS;
217 ext2_sbupdate(ump, MNT_WAIT);
218 }
219 fs->s_rd_only = 1;
220 }
221 if (!error && (mp->mnt_flag & MNT_RELOAD))
7b95be2a 222 error = ext2_reload(mp, ndp->ni_cnd.cn_cred, td);
984263bc
MD
223 if (error)
224 return (error);
225 devvp = ump->um_devvp;
226 if (ext2_check_sb_compat(fs->s_es, devvp->v_rdev,
227 (mp->mnt_kern_flag & MNTK_WANTRDWR) == 0) != 0)
228 return (EPERM);
229 if (fs->s_rd_only && (mp->mnt_kern_flag & MNTK_WANTRDWR)) {
230 /*
231 * If upgrade to read-write by non-root, then verify
232 * that user has necessary permissions on the device.
233 */
7b95be2a 234 if (cred->cr_uid != 0) {
41a01a4d 235 vn_lock(devvp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
984263bc 236 if ((error = VOP_ACCESS(devvp, VREAD | VWRITE,
7b95be2a 237 cred, td)) != 0) {
41a01a4d 238 VOP_UNLOCK(devvp, NULL, 0, td);
984263bc
MD
239 return (error);
240 }
41a01a4d 241 VOP_UNLOCK(devvp, NULL, 0, td);
984263bc
MD
242 }
243
244 if ((fs->s_es->s_state & EXT2_VALID_FS) == 0 ||
245 (fs->s_es->s_state & EXT2_ERROR_FS)) {
246 if (mp->mnt_flag & MNT_FORCE) {
247 printf(
248"WARNING: %s was not properly dismounted\n",
249 fs->fs_fsmnt);
250 } else {
251 printf(
252"WARNING: R/W mount of %s denied. Filesystem is not clean - run fsck\n",
253 fs->fs_fsmnt);
254 return (EPERM);
255 }
256 }
257 fs->s_es->s_state &= ~EXT2_VALID_FS;
258 ext2_sbupdate(ump, MNT_WAIT);
259 fs->s_rd_only = 0;
260 }
261 if (args.fspec == 0) {
262 /*
263 * Process export requests.
264 */
265 return (vfs_export(mp, &ump->um_export, &args.export));
266 }
267 }
268 /*
269 * Not an update, or updating the name: look up the name
270 * and verify that it refers to a sensible block device.
271 */
2b69e610 272 NDINIT(ndp, NAMEI_LOOKUP, CNP_FOLLOW, UIO_USERSPACE, args.fspec, td);
984263bc
MD
273 if ((error = namei(ndp)) != 0)
274 return (error);
275 NDFREE(ndp, NDF_ONLY_PNBUF);
276 devvp = ndp->ni_vp;
277
278 if (!vn_isdisk(devvp, &error)) {
279 vrele(devvp);
280 return (error);
281 }
282
283 /*
284 * If mount by non-root, then verify that user has necessary
285 * permissions on the device.
286 */
7b95be2a 287 if (cred->cr_uid != 0) {
984263bc
MD
288 accessmode = VREAD;
289 if ((mp->mnt_flag & MNT_RDONLY) == 0)
290 accessmode |= VWRITE;
41a01a4d 291 vn_lock(devvp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
7b95be2a 292 if ((error = VOP_ACCESS(devvp, accessmode, cred, td)) != 0) {
984263bc
MD
293 vput(devvp);
294 return (error);
295 }
41a01a4d 296 VOP_UNLOCK(devvp, NULL, 0, td);
984263bc
MD
297 }
298
299 if ((mp->mnt_flag & MNT_UPDATE) == 0) {
7b95be2a 300 error = ext2_mountfs(devvp, mp, td);
984263bc
MD
301 } else {
302 if (devvp != ump->um_devvp)
303 error = EINVAL; /* needs translation */
304 else
305 vrele(devvp);
306 }
307 if (error) {
308 vrele(devvp);
309 return (error);
310 }
311 ump = VFSTOUFS(mp);
312 fs = ump->um_e2fs;
313 (void) copyinstr(path, fs->fs_fsmnt, sizeof(fs->fs_fsmnt) - 1, &size);
314 bzero(fs->fs_fsmnt + size, sizeof(fs->fs_fsmnt) - size);
315 bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname,
316 MNAMELEN);
317 (void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
318 &size);
319 bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
7b95be2a 320 (void)ext2_statfs(mp, &mp->mnt_stat, td);
984263bc
MD
321 return (0);
322}
323
324/*
325 * checks that the data in the descriptor blocks make sense
326 * this is taken from ext2/super.c
327 */
0f7f7a49 328static int ext2_check_descriptors(struct ext2_sb_info *sb)
984263bc
MD
329{
330 int i;
331 int desc_block = 0;
332 unsigned long block = sb->s_es->s_first_data_block;
333 struct ext2_group_desc * gdp = NULL;
334
335 /* ext2_debug ("Checking group descriptors"); */
336
337 for (i = 0; i < sb->s_groups_count; i++)
338 {
339 /* examine next descriptor block */
340 if ((i % EXT2_DESC_PER_BLOCK(sb)) == 0)
341 gdp = (struct ext2_group_desc *)
342 sb->s_group_desc[desc_block++]->b_data;
343 if (gdp->bg_block_bitmap < block ||
344 gdp->bg_block_bitmap >= block + EXT2_BLOCKS_PER_GROUP(sb))
345 {
346 printf ("ext2_check_descriptors: "
347 "Block bitmap for group %d"
348 " not in group (block %lu)!\n",
349 i, (unsigned long) gdp->bg_block_bitmap);
350 return 0;
351 }
352 if (gdp->bg_inode_bitmap < block ||
353 gdp->bg_inode_bitmap >= block + EXT2_BLOCKS_PER_GROUP(sb))
354 {
355 printf ("ext2_check_descriptors: "
356 "Inode bitmap for group %d"
357 " not in group (block %lu)!\n",
358 i, (unsigned long) gdp->bg_inode_bitmap);
359 return 0;
360 }
361 if (gdp->bg_inode_table < block ||
362 gdp->bg_inode_table + sb->s_itb_per_group >=
363 block + EXT2_BLOCKS_PER_GROUP(sb))
364 {
365 printf ("ext2_check_descriptors: "
366 "Inode table for group %d"
367 " not in group (block %lu)!\n",
368 i, (unsigned long) gdp->bg_inode_table);
369 return 0;
370 }
371 block += EXT2_BLOCKS_PER_GROUP(sb);
372 gdp++;
373 }
374 return 1;
375}
376
377static int
0f7f7a49 378ext2_check_sb_compat(struct ext2_super_block *es, dev_t dev, int ronly)
984263bc 379{
984263bc
MD
380 if (es->s_magic != EXT2_SUPER_MAGIC) {
381 printf("ext2fs: %s: wrong magic number %#x (expected %#x)\n",
382 devtoname(dev), es->s_magic, EXT2_SUPER_MAGIC);
383 return (1);
384 }
385 if (es->s_rev_level > EXT2_GOOD_OLD_REV) {
386 if (es->s_feature_incompat & ~EXT2_FEATURE_INCOMPAT_SUPP) {
387 printf(
388"WARNING: mount of %s denied due to unsupported optional features\n",
389 devtoname(dev));
390 return (1);
391 }
392 if (!ronly &&
393 (es->s_feature_ro_compat & ~EXT2_FEATURE_RO_COMPAT_SUPP)) {
394 printf(
395"WARNING: R/W mount of %s denied due to unsupported optional features\n",
396 devtoname(dev));
397 return (1);
398 }
399 }
400 return (0);
401}
402
403/*
404 * this computes the fields of the ext2_sb_info structure from the
405 * data in the ext2_super_block structure read in
406 */
0f7f7a49
CP
407static int
408compute_sb_data(struct vnode *devvp, struct ext2_super_block *es,
409 struct ext2_sb_info *fs)
984263bc
MD
410{
411 int db_count, error;
412 int i, j;
413 int logic_sb_block = 1; /* XXX for now */
414
415#if 1
416#define V(v)
417#else
418#define V(v) printf(#v"= %d\n", fs->v);
419#endif
420
421 fs->s_blocksize = EXT2_MIN_BLOCK_SIZE << es->s_log_block_size;
422 V(s_blocksize)
423 fs->s_bshift = EXT2_MIN_BLOCK_LOG_SIZE + es->s_log_block_size;
424 V(s_bshift)
425 fs->s_fsbtodb = es->s_log_block_size + 1;
426 V(s_fsbtodb)
427 fs->s_qbmask = fs->s_blocksize - 1;
428 V(s_bmask)
429 fs->s_blocksize_bits = EXT2_BLOCK_SIZE_BITS(es);
430 V(s_blocksize_bits)
431 fs->s_frag_size = EXT2_MIN_FRAG_SIZE << es->s_log_frag_size;
432 V(s_frag_size)
433 if (fs->s_frag_size)
434 fs->s_frags_per_block = fs->s_blocksize / fs->s_frag_size;
435 V(s_frags_per_block)
436 fs->s_blocks_per_group = es->s_blocks_per_group;
437 V(s_blocks_per_group)
438 fs->s_frags_per_group = es->s_frags_per_group;
439 V(s_frags_per_group)
440 fs->s_inodes_per_group = es->s_inodes_per_group;
441 V(s_inodes_per_group)
442 fs->s_inodes_per_block = fs->s_blocksize / EXT2_INODE_SIZE;
443 V(s_inodes_per_block)
444 fs->s_itb_per_group = fs->s_inodes_per_group /fs->s_inodes_per_block;
445 V(s_itb_per_group)
446 fs->s_desc_per_block = fs->s_blocksize / sizeof (struct ext2_group_desc);
447 V(s_desc_per_block)
448 /* s_resuid / s_resgid ? */
449 fs->s_groups_count = (es->s_blocks_count -
450 es->s_first_data_block +
451 EXT2_BLOCKS_PER_GROUP(fs) - 1) /
452 EXT2_BLOCKS_PER_GROUP(fs);
453 V(s_groups_count)
454 db_count = (fs->s_groups_count + EXT2_DESC_PER_BLOCK(fs) - 1) /
455 EXT2_DESC_PER_BLOCK(fs);
456 fs->s_db_per_group = db_count;
457 V(s_db_per_group)
458
459 fs->s_group_desc = bsd_malloc(db_count * sizeof (struct buf *),
460 M_UFSMNT, M_WAITOK);
461
462 /* adjust logic_sb_block */
463 if(fs->s_blocksize > SBSIZE)
464 /* Godmar thinks: if the blocksize is greater than 1024, then
465 the superblock is logically part of block zero.
466 */
467 logic_sb_block = 0;
468
469 for (i = 0; i < db_count; i++) {
470 error = bread(devvp , fsbtodb(fs, logic_sb_block + i + 1),
7b95be2a 471 fs->s_blocksize, &fs->s_group_desc[i]);
984263bc
MD
472 if(error) {
473 for (j = 0; j < i; j++)
474 brelse(fs->s_group_desc[j]);
475 bsd_free(fs->s_group_desc, M_UFSMNT);
476 printf("EXT2-fs: unable to read group descriptors (%d)\n", error);
477 return EIO;
478 }
479 /* Set the B_LOCKED flag on the buffer, then brelse() it */
480 LCK_BUF(fs->s_group_desc[i])
481 }
482 if(!ext2_check_descriptors(fs)) {
483 for (j = 0; j < db_count; j++)
484 ULCK_BUF(fs->s_group_desc[j])
485 bsd_free(fs->s_group_desc, M_UFSMNT);
486 printf("EXT2-fs: (ext2_check_descriptors failure) "
487 "unable to read group descriptors\n");
488 return EIO;
489 }
490
491 for (i = 0; i < EXT2_MAX_GROUP_LOADED; i++) {
492 fs->s_inode_bitmap_number[i] = 0;
493 fs->s_inode_bitmap[i] = NULL;
494 fs->s_block_bitmap_number[i] = 0;
495 fs->s_block_bitmap[i] = NULL;
496 }
497 fs->s_loaded_inode_bitmaps = 0;
498 fs->s_loaded_block_bitmaps = 0;
499 return 0;
500}
501
502/*
503 * Reload all incore data for a filesystem (used after running fsck on
504 * the root filesystem and finding things to fix). The filesystem must
505 * be mounted read-only.
506 *
507 * Things to do to update the mount:
508 * 1) invalidate all cached meta-data.
509 * 2) re-read superblock from disk.
510 * 3) re-read summary information from disk.
511 * 4) invalidate all inactive vnodes.
512 * 5) invalidate all cached file data.
513 * 6) re-read inode data for all active vnodes.
514 */
41a01a4d
MD
515static int ext2_reload_scan1(struct mount *mp, struct vnode *vp, void *rescan);
516static int ext2_reload_scan2(struct mount *mp, struct vnode *vp,
517 lwkt_tokref_t vlock, void *rescan);
518
519struct scaninfo {
520 int rescan;
521 int allerror;
522 int waitfor;
523 thread_t td;
524 struct vnode *devvp;
525 struct ext2_sb_info *fs;
526};
527
984263bc 528static int
0f7f7a49 529ext2_reload(struct mount *mountp, struct ucred *cred, struct thread *td)
984263bc 530{
41a01a4d 531 struct vnode *devvp;
984263bc
MD
532 struct buf *bp;
533 struct ext2_super_block * es;
534 struct ext2_sb_info *fs;
535 int error;
41a01a4d 536 struct scaninfo scaninfo;
984263bc
MD
537
538 if ((mountp->mnt_flag & MNT_RDONLY) == 0)
539 return (EINVAL);
540 /*
541 * Step 1: invalidate all cached meta-data.
542 */
543 devvp = VFSTOUFS(mountp)->um_devvp;
7b95be2a 544 if (vinvalbuf(devvp, 0, td, 0, 0))
984263bc
MD
545 panic("ext2_reload: dirty1");
546 /*
547 * Step 2: re-read superblock from disk.
548 * constants have been adjusted for ext2
549 */
7b95be2a 550 if ((error = bread(devvp, SBLOCK, SBSIZE, &bp)) != 0)
984263bc
MD
551 return (error);
552 es = (struct ext2_super_block *)bp->b_data;
553 if (ext2_check_sb_compat(es, devvp->v_rdev, 0) != 0) {
554 brelse(bp);
555 return (EIO); /* XXX needs translation */
556 }
557 fs = VFSTOUFS(mountp)->um_e2fs;
558 bcopy(bp->b_data, fs->s_es, sizeof(struct ext2_super_block));
559
560 if((error = compute_sb_data(devvp, es, fs)) != 0) {
561 brelse(bp);
562 return error;
563 }
564#ifdef UNKLAR
565 if (fs->fs_sbsize < SBSIZE)
566 bp->b_flags |= B_INVAL;
567#endif
568 brelse(bp);
569
41a01a4d
MD
570 scaninfo.rescan = 1;
571 scaninfo.td = td;
572 scaninfo.devvp = devvp;
573 scaninfo.fs = fs;
574 while (error == 0 && scaninfo.rescan) {
575 scaninfo.rescan = 0;
576 error = vmntvnodescan(mountp, ext2_reload_scan1,
577 ext2_reload_scan2, &scaninfo);
578 }
579 return(error);
580}
581
582static int
583ext2_reload_scan1(struct mount *mp, struct vnode *vp, void *data)
584{
585 struct scaninfo *info = data;
586
587 /*
588 * Step 4: invalidate all inactive vnodes.
589 */
590 if (vrecycle(vp, NULL, curthread)) {
591 info->rescan = 1;
592 return(-1); /* continue loop, do not call scan2 */
593 }
594 return(0);
595}
596
597static int
598ext2_reload_scan2(struct mount *mp, struct vnode *vp, lwkt_tokref_t vlock, void *data)
599{
600 struct scaninfo *info = data;
601 struct inode *ip;
602 struct buf *bp;
603 int error;
604
605 /*
606 * Step 5: invalidate all cached file data.
607 */
608 if (vget(vp, vlock, LK_EXCLUSIVE | LK_INTERLOCK, info->td)) {
609 info->rescan = 1;
610 return(0);
611 }
612 if (vinvalbuf(vp, 0, info->td, 0, 0))
613 panic("ext2_reload: dirty2");
614 /*
615 * Step 6: re-read inode data for all active vnodes.
616 */
617 ip = VTOI(vp);
618 error = bread(info->devvp, fsbtodb(info->fs, ino_to_fsba(info->fs, ip->i_number)),
619 (int)info->fs->s_blocksize, &bp);
620 if (error) {
984263bc 621 vput(vp);
41a01a4d 622 return (error);
984263bc 623 }
41a01a4d
MD
624 ext2_ei2di((struct ext2_inode *) ((char *)bp->b_data +
625 EXT2_INODE_SIZE * ino_to_fsbo(info->fs, ip->i_number)),
626 &ip->i_din);
627 brelse(bp);
628 vput(vp);
629 return(0);
984263bc
MD
630}
631
632/*
633 * Common code for mount and mountroot
634 */
635static int
0f7f7a49 636ext2_mountfs(struct vnode *devvp, struct mount *mp, struct thread *td)
984263bc 637{
f7aae92f 638 struct ufsmount *ump;
984263bc 639 struct buf *bp;
f7aae92f 640 struct ext2_sb_info *fs;
984263bc 641 struct ext2_super_block * es;
e4c9c0c8 642 dev_t dev;
984263bc
MD
643 struct partinfo dpart;
644 int havepart = 0;
645 int error, i, size;
646 int ronly;
647
648 /*
649 * Disallow multiple mounts of the same device.
650 * Disallow mounting of a device that is currently in use
651 * (except for root, which might share swap device for miniroot).
652 * Flush out any old buffers remaining from a previous use.
653 */
654 if ((error = vfs_mountedon(devvp)) != 0)
655 return (error);
715f92b6 656 if (count_udev(devvp->v_udev) > 0 && devvp != rootvp)
984263bc 657 return (EBUSY);
7b95be2a 658 if ((error = vinvalbuf(devvp, V_SAVE, td, 0, 0)) != 0)
984263bc
MD
659 return (error);
660#ifdef READONLY
661/* turn on this to force it to be read-only */
662 mp->mnt_flag |= MNT_RDONLY;
663#endif
664
665 ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
41a01a4d 666 vn_lock(devvp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
7b95be2a 667 error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, td);
41a01a4d 668 VOP_UNLOCK(devvp, NULL, 0, td);
984263bc
MD
669 if (error)
670 return (error);
e4c9c0c8
MD
671 dev = devvp->v_rdev;
672 if (dev->si_iosize_max != 0)
673 mp->mnt_iosize_max = dev->si_iosize_max;
984263bc
MD
674 if (mp->mnt_iosize_max > MAXPHYS)
675 mp->mnt_iosize_max = MAXPHYS;
7b95be2a 676 if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, NOCRED, td) != 0)
984263bc
MD
677 size = DEV_BSIZE;
678 else {
679 havepart = 1;
680 size = dpart.disklab->d_secsize;
681 }
682
683 bp = NULL;
684 ump = NULL;
7b95be2a 685 if ((error = bread(devvp, SBLOCK, SBSIZE, &bp)) != 0)
984263bc
MD
686 goto out;
687 es = (struct ext2_super_block *)bp->b_data;
688 if (ext2_check_sb_compat(es, dev, ronly) != 0) {
689 error = EINVAL; /* XXX needs translation */
690 goto out;
691 }
692 if ((es->s_state & EXT2_VALID_FS) == 0 ||
693 (es->s_state & EXT2_ERROR_FS)) {
694 if (ronly || (mp->mnt_flag & MNT_FORCE)) {
695 printf(
696"WARNING: Filesystem was not properly dismounted\n");
697 } else {
698 printf(
699"WARNING: R/W mount denied. Filesystem is not clean - run fsck\n");
700 error = EPERM;
701 goto out;
702 }
703 }
704 ump = bsd_malloc(sizeof *ump, M_UFSMNT, M_WAITOK);
705 bzero((caddr_t)ump, sizeof *ump);
706 ump->um_malloctype = M_EXT2NODE;
707 ump->um_blkatoff = ext2_blkatoff;
708 ump->um_truncate = ext2_truncate;
709 ump->um_update = ext2_update;
710 ump->um_valloc = ext2_valloc;
711 ump->um_vfree = ext2_vfree;
712 /* I don't know whether this is the right strategy. Note that
713 we dynamically allocate both a ext2_sb_info and a ext2_super_block
714 while Linux keeps the super block in a locked buffer
715 */
716 ump->um_e2fs = bsd_malloc(sizeof(struct ext2_sb_info),
717 M_UFSMNT, M_WAITOK);
718 ump->um_e2fs->s_es = bsd_malloc(sizeof(struct ext2_super_block),
719 M_UFSMNT, M_WAITOK);
720 bcopy(es, ump->um_e2fs->s_es, (u_int)sizeof(struct ext2_super_block));
721 if ((error = compute_sb_data(devvp, ump->um_e2fs->s_es, ump->um_e2fs)))
722 goto out;
723 /*
724 * We don't free the group descriptors allocated by compute_sb_data()
725 * until ext2_unmount(). This is OK since the mount will succeed.
726 */
727 brelse(bp);
728 bp = NULL;
729 fs = ump->um_e2fs;
730 fs->s_rd_only = ronly; /* ronly is set according to mnt_flags */
731 /* if the fs is not mounted read-only, make sure the super block is
732 always written back on a sync()
733 */
734 fs->s_wasvalid = fs->s_es->s_state & EXT2_VALID_FS ? 1 : 0;
735 if (ronly == 0) {
736 fs->s_dirt = 1; /* mark it modified */
737 fs->s_es->s_state &= ~EXT2_VALID_FS; /* set fs invalid */
738 }
739 mp->mnt_data = (qaddr_t)ump;
740 mp->mnt_stat.f_fsid.val[0] = dev2udev(dev);
741 mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum;
742 mp->mnt_maxsymlinklen = EXT2_MAXSYMLINKLEN;
743 mp->mnt_flag |= MNT_LOCAL;
744 ump->um_mountp = mp;
745 ump->um_dev = dev;
746 ump->um_devvp = devvp;
747 /* setting those two parameters allows us to use
748 ufs_bmap w/o changse !
749 */
750 ump->um_nindir = EXT2_ADDR_PER_BLOCK(fs);
751 ump->um_bptrtodb = fs->s_es->s_log_block_size + 1;
752 ump->um_seqinc = EXT2_FRAGS_PER_BLOCK(fs);
753 for (i = 0; i < MAXQUOTAS; i++)
754 ump->um_quotas[i] = NULLVP;
e4c9c0c8 755 dev->si_mountpoint = mp;
984263bc
MD
756 if (ronly == 0)
757 ext2_sbupdate(ump, MNT_WAIT);
758 return (0);
759out:
760 if (bp)
761 brelse(bp);
7b95be2a 762 (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, td);
984263bc
MD
763 if (ump) {
764 bsd_free(ump->um_e2fs->s_es, M_UFSMNT);
765 bsd_free(ump->um_e2fs, M_UFSMNT);
766 bsd_free(ump, M_UFSMNT);
767 mp->mnt_data = (qaddr_t)0;
768 }
769 return (error);
770}
771
772/*
773 * unmount system call
774 */
775static int
0f7f7a49 776ext2_unmount(struct mount *mp, int mntflags, struct thread *td)
984263bc 777{
f7aae92f
RG
778 struct ufsmount *ump;
779 struct ext2_sb_info *fs;
984263bc
MD
780 int error, flags, ronly, i;
781
782 flags = 0;
783 if (mntflags & MNT_FORCE) {
784 if (mp->mnt_flag & MNT_ROOTFS)
785 return (EINVAL);
786 flags |= FORCECLOSE;
787 }
7b95be2a 788 if ((error = ext2_flushfiles(mp, flags, td)) != 0)
984263bc
MD
789 return (error);
790 ump = VFSTOUFS(mp);
791 fs = ump->um_e2fs;
792 ronly = fs->s_rd_only;
793 if (ronly == 0) {
794 if (fs->s_wasvalid)
795 fs->s_es->s_state |= EXT2_VALID_FS;
796 ext2_sbupdate(ump, MNT_WAIT);
797 }
798
799 /* release buffers containing group descriptors */
800 for(i = 0; i < fs->s_db_per_group; i++)
801 ULCK_BUF(fs->s_group_desc[i])
802 bsd_free(fs->s_group_desc, M_UFSMNT);
803
804 /* release cached inode/block bitmaps */
805 for (i = 0; i < EXT2_MAX_GROUP_LOADED; i++)
806 if (fs->s_inode_bitmap[i])
807 ULCK_BUF(fs->s_inode_bitmap[i])
808
809 for (i = 0; i < EXT2_MAX_GROUP_LOADED; i++)
810 if (fs->s_block_bitmap[i])
811 ULCK_BUF(fs->s_block_bitmap[i])
812
e4c9c0c8 813 ump->um_devvp->v_rdev->si_mountpoint = NULL;
7b95be2a 814 error = VOP_CLOSE(ump->um_devvp, ronly ? FREAD : FREAD|FWRITE, td);
984263bc
MD
815 vrele(ump->um_devvp);
816 bsd_free(fs->s_es, M_UFSMNT);
817 bsd_free(fs, M_UFSMNT);
818 bsd_free(ump, M_UFSMNT);
819 mp->mnt_data = (qaddr_t)0;
820 mp->mnt_flag &= ~MNT_LOCAL;
821 return (error);
822}
823
824/*
825 * Flush out all the files in a filesystem.
826 */
827static int
0f7f7a49 828ext2_flushfiles(struct mount *mp, int flags, struct thread *td)
984263bc 829{
f7aae92f 830 struct ufsmount *ump;
984263bc
MD
831 int error;
832#if QUOTA
833 int i;
834#endif
835
836 ump = VFSTOUFS(mp);
837#if QUOTA
838 if (mp->mnt_flag & MNT_QUOTA) {
839 if ((error = vflush(mp, 0, SKIPSYSTEM|flags)) != 0)
840 return (error);
841 for (i = 0; i < MAXQUOTAS; i++) {
842 if (ump->um_quotas[i] == NULLVP)
843 continue;
7b95be2a 844 quotaoff(td, mp, i);
984263bc
MD
845 }
846 /*
847 * Here we fall through to vflush again to ensure
848 * that we have gotten rid of all the system vnodes.
849 */
850 }
851#endif
852 error = vflush(mp, 0, flags);
853 return (error);
854}
855
856/*
857 * Get file system statistics.
858 * taken from ext2/super.c ext2_statfs
859 */
860static int
0f7f7a49 861ext2_statfs(struct mount *mp, struct statfs *sbp, struct thread *td)
984263bc
MD
862{
863 unsigned long overhead;
f7aae92f
RG
864 struct ufsmount *ump;
865 struct ext2_sb_info *fs;
866 struct ext2_super_block *es;
984263bc
MD
867 int i, nsb;
868
869 ump = VFSTOUFS(mp);
870 fs = ump->um_e2fs;
871 es = fs->s_es;
872
873 if (es->s_magic != EXT2_SUPER_MAGIC)
874 panic("ext2_statfs - magic number spoiled");
875
876 /*
877 * Compute the overhead (FS structures)
878 */
879 if (es->s_feature_ro_compat & EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER) {
880 nsb = 0;
881 for (i = 0 ; i < fs->s_groups_count; i++)
882 if (ext2_group_sparse(i))
883 nsb++;
884 } else
885 nsb = fs->s_groups_count;
886 overhead = es->s_first_data_block +
887 /* Superblocks and block group descriptors: */
888 nsb * (1 + fs->s_db_per_group) +
889 /* Inode bitmap, block bitmap, and inode table: */
890 fs->s_groups_count * (1 + 1 + fs->s_itb_per_group);
891
892 sbp->f_bsize = EXT2_FRAG_SIZE(fs);
893 sbp->f_iosize = EXT2_BLOCK_SIZE(fs);
894 sbp->f_blocks = es->s_blocks_count - overhead;
895 sbp->f_bfree = es->s_free_blocks_count;
896 sbp->f_bavail = sbp->f_bfree - es->s_r_blocks_count;
897 sbp->f_files = es->s_inodes_count;
898 sbp->f_ffree = es->s_free_inodes_count;
899 if (sbp != &mp->mnt_stat) {
900 sbp->f_type = mp->mnt_vfc->vfc_typenum;
901 bcopy((caddr_t)mp->mnt_stat.f_mntonname,
902 (caddr_t)&sbp->f_mntonname[0], MNAMELEN);
903 bcopy((caddr_t)mp->mnt_stat.f_mntfromname,
904 (caddr_t)&sbp->f_mntfromname[0], MNAMELEN);
905 }
906 return (0);
907}
908
909/*
910 * Go through the disk queues to initiate sandbagged IO;
911 * go through the inodes to write those that have been modified;
912 * initiate the writing of the super block if it has been modified.
913 *
914 * Note: we are always called with the filesystem marked `MPBUSY'.
915 */
41a01a4d
MD
916
917static int ext2_sync_scan(struct mount *mp, struct vnode *vp,
918 lwkt_tokref_t vlock, void *data);
919
984263bc 920static int
0f7f7a49 921ext2_sync(struct mount *mp, int waitfor, struct thread *td)
984263bc 922{
984263bc
MD
923 struct ufsmount *ump = VFSTOUFS(mp);
924 struct ext2_sb_info *fs;
41a01a4d
MD
925 struct scaninfo scaninfo;
926 int error;
984263bc
MD
927
928 fs = ump->um_e2fs;
929 if (fs->s_dirt != 0 && fs->s_rd_only != 0) { /* XXX */
930 printf("fs = %s\n", fs->fs_fsmnt);
931 panic("ext2_sync: rofs mod");
932 }
41a01a4d 933
984263bc
MD
934 /*
935 * Write back each (modified) inode.
936 */
41a01a4d
MD
937 scaninfo.allerror = 0;
938 scaninfo.rescan = 1;
939 scaninfo.waitfor = waitfor;
940 scaninfo.td = td;
941 while (scaninfo.rescan) {
942 scaninfo.rescan = 0;
943 vmntvnodescan(mp, NULL, ext2_sync_scan, &scaninfo);
984263bc 944 }
41a01a4d 945
984263bc
MD
946 /*
947 * Force stale file system control information to be flushed.
948 */
949 if (waitfor != MNT_LAZY) {
41a01a4d 950 vn_lock(ump->um_devvp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
7b95be2a 951 if ((error = VOP_FSYNC(ump->um_devvp, waitfor, td)) != 0)
41a01a4d
MD
952 scaninfo.allerror = error;
953 VOP_UNLOCK(ump->um_devvp, NULL, 0, td);
984263bc
MD
954 }
955#if QUOTA
956 qsync(mp);
957#endif
958 /*
959 * Write back modified superblock.
960 */
961 if (fs->s_dirt != 0) {
962 fs->s_dirt = 0;
963 fs->s_es->s_wtime = time_second;
964 if ((error = ext2_sbupdate(ump, waitfor)) != 0)
41a01a4d
MD
965 scaninfo.allerror = error;
966 }
967 return (scaninfo.allerror);
968}
969
970static int
971ext2_sync_scan(struct mount *mp, struct vnode *vp,
0f7f7a49 972 lwkt_tokref_t vlock, void *data)
41a01a4d
MD
973{
974 struct scaninfo *info = data;
975 struct inode *ip;
976 int error;
977
978 ip = VTOI(vp);
979 if (vp->v_type == VNON ||
980 ((ip->i_flag &
981 (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0 &&
982 (TAILQ_EMPTY(&vp->v_dirtyblkhd) || info->waitfor == MNT_LAZY))) {
983 lwkt_reltoken(vlock);
984 return(0);
985 }
986 error = vget(vp, vlock, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK, info->td);
987 if (error) {
988 if (error == ENOENT)
989 info->rescan = 1;
990 return(0);
984263bc 991 }
41a01a4d
MD
992 if ((error = VOP_FSYNC(vp, info->waitfor, info->td)) != 0)
993 info->allerror = error;
994 VOP_UNLOCK(vp, NULL, 0, info->td);
995 vrele(vp);
996 return(0);
984263bc
MD
997}
998
999/*
1000 * Look up a EXT2FS dinode number to find its incore vnode, otherwise read it
1001 * in from disk. If it is in core, wait for the lock bit to clear, then
1002 * return the inode locked. Detection and handling of mount points must be
1003 * done by the calling routine.
1004 */
1005static int
0f7f7a49 1006ext2_vget(struct mount *mp, ino_t ino, struct vnode **vpp)
984263bc 1007{
f7aae92f
RG
1008 struct ext2_sb_info *fs;
1009 struct inode *ip;
984263bc
MD
1010 struct ufsmount *ump;
1011 struct buf *bp;
1012 struct vnode *vp;
1013 dev_t dev;
1014 int i, error;
1015 int used_blocks;
1016
1017 ump = VFSTOUFS(mp);
1018 dev = ump->um_dev;
1019restart:
1020 if ((*vpp = ufs_ihashget(dev, ino)) != NULL)
1021 return (0);
1022
1023 /*
1024 * Lock out the creation of new entries in the FFS hash table in
1025 * case getnewvnode() or MALLOC() blocks, otherwise a duplicate
1026 * may occur!
1027 */
1028 if (ext2fs_inode_hash_lock) {
1029 while (ext2fs_inode_hash_lock) {
1030 ext2fs_inode_hash_lock = -1;
377d4740 1031 tsleep(&ext2fs_inode_hash_lock, 0, "e2vget", 0);
984263bc
MD
1032 }
1033 goto restart;
1034 }
1035 ext2fs_inode_hash_lock = 1;
1036
1037 /*
1038 * If this MALLOC() is performed after the getnewvnode()
1039 * it might block, leaving a vnode with a NULL v_data to be
1040 * found by ext2_sync() if a sync happens to fire right then,
1041 * which will cause a panic because ext2_sync() blindly
1042 * dereferences vp->v_data (as well it should).
1043 */
1044 MALLOC(ip, struct inode *, sizeof(struct inode), M_EXT2NODE, M_WAITOK);
1045
1046 /* Allocate a new vnode/inode. */
2d3e977e 1047 if ((error = getnewvnode(VT_UFS, mp, ext2_vnode_vops, &vp)) != 0) {
984263bc
MD
1048 if (ext2fs_inode_hash_lock < 0)
1049 wakeup(&ext2fs_inode_hash_lock);
1050 ext2fs_inode_hash_lock = 0;
1051 *vpp = NULL;
1052 FREE(ip, M_EXT2NODE);
1053 return (error);
1054 }
1055 bzero((caddr_t)ip, sizeof(struct inode));
377d4740 1056 lockinit(&ip->i_lock, 0, "ext2in", 0, 0);
984263bc
MD
1057 vp->v_data = ip;
1058 ip->i_vnode = vp;
1059 ip->i_e2fs = fs = ump->um_e2fs;
1060 ip->i_dev = dev;
1061 ip->i_number = ino;
1062#if QUOTA
1063 for (i = 0; i < MAXQUOTAS; i++)
1064 ip->i_dquot[i] = NODQUOT;
1065#endif
1066 /*
1067 * Put it onto its hash chain and lock it so that other requests for
1068 * this inode will block if they arrive while we are sleeping waiting
1069 * for old data structures to be purged or for the contents of the
1070 * disk portion of this inode to be read.
1071 */
1072 ufs_ihashins(ip);
1073
1074 if (ext2fs_inode_hash_lock < 0)
1075 wakeup(&ext2fs_inode_hash_lock);
1076 ext2fs_inode_hash_lock = 0;
1077
1078 /* Read in the disk contents for the inode, copy into the inode. */
1079#if 0
1080printf("ext2_vget(%d) dbn= %d ", ino, fsbtodb(fs, ino_to_fsba(fs, ino)));
1081#endif
1082 if ((error = bread(ump->um_devvp, fsbtodb(fs, ino_to_fsba(fs, ino)),
7b95be2a 1083 (int)fs->s_blocksize, &bp)) != 0) {
984263bc
MD
1084 /*
1085 * The inode does not contain anything useful, so it would
1086 * be misleading to leave it on its hash chain. With mode
1087 * still zero, it will be unlinked and returned to the free
1088 * list by vput().
1089 */
1090 vput(vp);
1091 brelse(bp);
1092 *vpp = NULL;
1093 return (error);
1094 }
1095 /* convert ext2 inode to dinode */
1096 ext2_ei2di((struct ext2_inode *) ((char *)bp->b_data + EXT2_INODE_SIZE *
1097 ino_to_fsbo(fs, ino)), &ip->i_din);
1098 ip->i_block_group = ino_to_cg(fs, ino);
1099 ip->i_next_alloc_block = 0;
1100 ip->i_next_alloc_goal = 0;
1101 ip->i_prealloc_count = 0;
1102 ip->i_prealloc_block = 0;
1103 /* now we want to make sure that block pointers for unused
1104 blocks are zeroed out - ext2_balloc depends on this
1105 although for regular files and directories only
1106 */
1107 if(S_ISDIR(ip->i_mode) || S_ISREG(ip->i_mode)) {
1108 used_blocks = (ip->i_size+fs->s_blocksize-1) / fs->s_blocksize;
1109 for(i = used_blocks; i < EXT2_NDIR_BLOCKS; i++)
1110 ip->i_db[i] = 0;
1111 }
1112/*
1113 ext2_print_inode(ip);
1114*/
1115 brelse(bp);
1116
1117 /*
1118 * Initialize the vnode from the inode, check for aliases.
1119 * Note that the underlying vnode may have changed.
1120 */
2d3e977e 1121 if ((error = ufs_vinit(mp, ext2_spec_vops, ext2_fifo_vops, &vp)) != 0) {
984263bc
MD
1122 vput(vp);
1123 *vpp = NULL;
1124 return (error);
1125 }
1126 /*
1127 * Finish inode initialization now that aliasing has been resolved.
1128 */
1129 ip->i_devvp = ump->um_devvp;
597aea93 1130 vref(ip->i_devvp);
984263bc
MD
1131 /*
1132 * Set up a generation number for this inode if it does not
1133 * already have one. This should only happen on old filesystems.
1134 */
1135 if (ip->i_gen == 0) {
1136 ip->i_gen = random() / 2 + 1;
1137 if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0)
1138 ip->i_flag |= IN_MODIFIED;
1139 }
1140 *vpp = vp;
1141 return (0);
1142}
1143
1144/*
1145 * File handle to vnode
1146 *
1147 * Have to be really careful about stale file handles:
1148 * - check that the inode number is valid
1149 * - call ext2_vget() to get the locked inode
1150 * - check for an unallocated inode (i_mode == 0)
1151 * - check that the given client host has export rights and return
1152 * those rights via. exflagsp and credanonp
1153 */
1154static int
0f7f7a49 1155ext2_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp)
984263bc 1156{
f7aae92f 1157 struct ufid *ufhp;
984263bc
MD
1158 struct ext2_sb_info *fs;
1159
1160 ufhp = (struct ufid *)fhp;
1161 fs = VFSTOUFS(mp)->um_e2fs;
1162 if (ufhp->ufid_ino < ROOTINO ||
1163 ufhp->ufid_ino > fs->s_groups_count * fs->s_es->s_inodes_per_group)
1164 return (ESTALE);
1165 return (ufs_fhtovp(mp, ufhp, vpp));
1166}
1167
1168/*
1169 * Vnode pointer to File handle
1170 */
1171/* ARGSUSED */
1172static int
0f7f7a49 1173ext2_vptofh(struct vnode *vp, struct fid *fhp)
984263bc 1174{
f7aae92f
RG
1175 struct inode *ip;
1176 struct ufid *ufhp;
984263bc
MD
1177
1178 ip = VTOI(vp);
1179 ufhp = (struct ufid *)fhp;
1180 ufhp->ufid_len = sizeof(struct ufid);
1181 ufhp->ufid_ino = ip->i_number;
1182 ufhp->ufid_gen = ip->i_gen;
1183 return (0);
1184}
1185
1186/*
1187 * Write a superblock and associated information back to disk.
1188 */
1189static int
0f7f7a49 1190ext2_sbupdate(struct ufsmount *mp, int waitfor)
984263bc 1191{
f7aae92f
RG
1192 struct ext2_sb_info *fs = mp->um_e2fs;
1193 struct ext2_super_block *es = fs->s_es;
1194 struct buf *bp;
984263bc
MD
1195 int error = 0;
1196/*
1197printf("\nupdating superblock, waitfor=%s\n", waitfor == MNT_WAIT ? "yes":"no");
1198*/
1199 bp = getblk(mp->um_devvp, SBLOCK, SBSIZE, 0, 0);
1200 bcopy((caddr_t)es, bp->b_data, (u_int)sizeof(struct ext2_super_block));
1201 if (waitfor == MNT_WAIT)
1202 error = bwrite(bp);
1203 else
1204 bawrite(bp);
1205
1206 /*
1207 * The buffers for group descriptors, inode bitmaps and block bitmaps
1208 * are not busy at this point and are (hopefully) written by the
1209 * usual sync mechanism. No need to write them here
0f7f7a49 1210 */
984263bc
MD
1211
1212 return (error);
1213}