hpfs_vfsops.c revision 137040
1/*-
2 * Copyright (c) 1998, 1999 Semen Ustimenko (semenu@FreeBSD.org)
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD: head/sys/fs/hpfs/hpfs_vfsops.c 137040 2004-10-29 10:43:07Z phk $
27 */
28
29
30#include <sys/param.h>
31#include <sys/systm.h>
32#include <sys/namei.h>
33#include <sys/conf.h>
34#include <sys/proc.h>
35#include <sys/kernel.h>
36#include <sys/vnode.h>
37#include <sys/mount.h>
38#include <sys/bio.h>
39#include <sys/buf.h>
40#include <sys/fcntl.h>
41#include <sys/malloc.h>
42
43#include <geom/geom.h>
44#include <geom/geom_vfs.h>
45
46#include <vm/vm.h>
47#include <vm/vm_param.h>
48#include <vm/vm_page.h>
49#include <vm/vm_object.h>
50#include <vm/vm_extern.h>
51
52#include <fs/hpfs/hpfs.h>
53#include <fs/hpfs/hpfsmount.h>
54#include <fs/hpfs/hpfs_subr.h>
55
56MALLOC_DEFINE(M_HPFSMNT, "HPFS mount", "HPFS mount structure");
57MALLOC_DEFINE(M_HPFSNO, "HPFS node", "HPFS node structure");
58
59struct sockaddr;
60
61static int	hpfs_mountfs(register struct vnode *, struct mount *,
62				  struct hpfs_args *, struct thread *);
63
64static vfs_init_t       hpfs_init;
65static vfs_uninit_t     hpfs_uninit;
66static vfs_fhtovp_t     hpfs_fhtovp;
67static vfs_vget_t       hpfs_vget;
68static vfs_omount_t     hpfs_omount;
69static vfs_root_t       hpfs_root;
70static vfs_statfs_t     hpfs_statfs;
71static vfs_unmount_t    hpfs_unmount;
72static vfs_vptofh_t     hpfs_vptofh;
73
74static int
75hpfs_init (
76	struct vfsconf *vcp )
77{
78	dprintf(("hpfs_init():\n"));
79
80	hpfs_hphashinit();
81	return 0;
82}
83
84static int
85hpfs_uninit (vfsp)
86	struct vfsconf *vfsp;
87{
88	hpfs_hphashdestroy();
89	return 0;;
90}
91
92static int
93hpfs_omount (
94	struct mount *mp,
95	char *path,
96	caddr_t data,
97	struct thread *td )
98{
99	size_t		size;
100	int		err = 0;
101	struct vnode	*devvp;
102	struct hpfs_args args;
103	struct hpfsmount *hpmp = 0;
104	struct nameidata ndp;
105
106	dprintf(("hpfs_omount():\n"));
107	/*
108	 ***
109	 * Mounting non-root filesystem or updating a filesystem
110	 ***
111	 */
112
113	/* copy in user arguments*/
114	err = copyin(data, (caddr_t)&args, sizeof (struct hpfs_args));
115	if (err)
116		goto error_1;		/* can't get arguments*/
117
118	/*
119	 * If updating, check whether changing from read-only to
120	 * read/write; if there is no device name, that's all we do.
121	 */
122	if (mp->mnt_flag & MNT_UPDATE) {
123		dprintf(("hpfs_omount: MNT_UPDATE: "));
124
125		hpmp = VFSTOHPFS(mp);
126
127		if (args.fspec == 0) {
128			dprintf(("export 0x%x\n",args.export.ex_flags));
129			err = vfs_export(mp, &args.export);
130			if (err) {
131				printf("hpfs_omount: vfs_export failed %d\n",
132					err);
133			}
134			goto success;
135		} else {
136			dprintf(("name [FAILED]\n"));
137			err = EINVAL;
138			goto success;
139		}
140		dprintf(("\n"));
141	}
142
143	/*
144	 * Not an update, or updating the name: look up the name
145	 * and verify that it refers to a sensible block device.
146	 */
147	NDINIT(&ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, td);
148	err = namei(&ndp);
149	if (err) {
150		/* can't get devvp!*/
151		goto error_1;
152	}
153
154	devvp = ndp.ni_vp;
155
156	if (!vn_isdisk(devvp, &err))
157		goto error_2;
158
159	/*
160	 ********************
161	 * NEW MOUNT
162	 ********************
163	 */
164
165	/*
166	 * Since this is a new mount, we want the names for
167	 * the device and the mount point copied in.  If an
168	 * error occurs, the mountpoint is discarded by the
169	 * upper level code.  Note that vfs_omount() handles
170	 * copying the mountpoint f_mntonname for us, so we
171	 * don't have to do it here unless we want to set it
172	 * to something other than "path" for some rason.
173	 */
174	/* Save "mounted from" info for mount point (NULL pad)*/
175	copyinstr(	args.fspec,			/* device name*/
176			mp->mnt_stat.f_mntfromname,	/* save area*/
177			MNAMELEN - 1,			/* max size*/
178			&size);				/* real size*/
179	bzero( mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
180
181	err = hpfs_mountfs(devvp, mp, &args, td);
182	if (err)
183		goto error_2;
184
185	/*
186	 * Initialize FS stat information in mount struct; uses both
187	 * mp->mnt_stat.f_mntonname and mp->mnt_stat.f_mntfromname
188	 *
189	 * This code is common to root and non-root mounts
190	 */
191	(void)VFS_STATFS(mp, &mp->mnt_stat, td);
192
193	goto success;
194
195
196error_2:	/* error with devvp held*/
197
198	/* release devvp before failing*/
199	vrele(devvp);
200
201error_1:	/* no state to back out*/
202	/* XXX: Missing NDFREE(&ndp, ...) */
203
204success:
205	return( err);
206}
207
208/*
209 * Common code for mount and mountroot
210 */
211int
212hpfs_mountfs(devvp, mp, argsp, td)
213	register struct vnode *devvp;
214	struct mount *mp;
215	struct hpfs_args *argsp;
216	struct thread *td;
217{
218	int error, ronly;
219	struct sublock *sup;
220	struct spblock *spp;
221	struct hpfsmount *hpmp;
222	struct buf *bp = NULL;
223	struct vnode *vp;
224	struct cdev *dev = devvp->v_rdev;
225	struct g_consumer *cp;
226	struct bufobj *bo;
227
228	dprintf(("hpfs_mountfs():\n"));
229	ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
230	vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td);
231	/* XXX: use VOP_ACCESS to check FS perms */
232	DROP_GIANT();
233	g_topology_lock();
234	error = g_vfs_open(devvp, &cp, "hpfs", ronly ? 0 : 1);
235	g_topology_unlock();
236	PICKUP_GIANT();
237	VOP_UNLOCK(devvp, 0, td);
238	if (error)
239		return (error);
240
241	bo = &devvp->v_bufobj;
242	bo->bo_private = cp;
243	bo->bo_ops = g_vfs_bufops;
244
245	/*
246	 * Do actual mount
247	 */
248	hpmp = malloc(sizeof(struct hpfsmount), M_HPFSMNT, M_WAITOK | M_ZERO);
249
250	hpmp->hpm_cp = cp;
251	hpmp->hpm_bo = bo;
252
253	/* Read in SuperBlock */
254	error = bread(devvp, SUBLOCK, SUSIZE, NOCRED, &bp);
255	if (error)
256		goto failed;
257	bcopy(bp->b_data, &hpmp->hpm_su, sizeof(struct sublock));
258	brelse(bp); bp = NULL;
259
260	/* Read in SpareBlock */
261	error = bread(devvp, SPBLOCK, SPSIZE, NOCRED, &bp);
262	if (error)
263		goto failed;
264	bcopy(bp->b_data, &hpmp->hpm_sp, sizeof(struct spblock));
265	brelse(bp); bp = NULL;
266
267	sup = &hpmp->hpm_su;
268	spp = &hpmp->hpm_sp;
269
270	/* Check magic */
271	if (sup->su_magic != SU_MAGIC) {
272		printf("hpfs_mountfs: SuperBlock MAGIC DOESN'T MATCH\n");
273		error = EINVAL;
274		goto failed;
275	}
276	if (spp->sp_magic != SP_MAGIC) {
277		printf("hpfs_mountfs: SpareBlock MAGIC DOESN'T MATCH\n");
278		error = EINVAL;
279		goto failed;
280	}
281
282	mp->mnt_data = (qaddr_t)hpmp;
283	hpmp->hpm_devvp = devvp;
284	hpmp->hpm_dev = devvp->v_rdev;
285	hpmp->hpm_mp = mp;
286	hpmp->hpm_uid = argsp->uid;
287	hpmp->hpm_gid = argsp->gid;
288	hpmp->hpm_mode = argsp->mode;
289
290	error = hpfs_bminit(hpmp);
291	if (error)
292		goto failed;
293
294	error = hpfs_cpinit(hpmp, argsp);
295	if (error) {
296		hpfs_bmdeinit(hpmp);
297		goto failed;
298	}
299
300	error = hpfs_root(mp, &vp, td);
301	if (error) {
302		hpfs_cpdeinit(hpmp);
303		hpfs_bmdeinit(hpmp);
304		goto failed;
305	}
306
307	vput(vp);
308
309	mp->mnt_stat.f_fsid.val[0] = (long)dev2udev(dev);
310	mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum;
311	mp->mnt_maxsymlinklen = 0;
312	mp->mnt_flag |= MNT_LOCAL;
313	return (0);
314
315failed:
316	if (bp)
317		brelse (bp);
318	mp->mnt_data = (qaddr_t)NULL;
319	g_wither_geom_close(cp->geom, ENXIO);
320	return (error);
321}
322
323static int
324hpfs_unmount(
325	struct mount *mp,
326	int mntflags,
327	struct thread *td)
328{
329	int error, flags, ronly;
330	register struct hpfsmount *hpmp = VFSTOHPFS(mp);
331
332	dprintf(("hpfs_unmount():\n"));
333
334	ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
335
336	flags = 0;
337	if(mntflags & MNT_FORCE)
338		flags |= FORCECLOSE;
339
340	dprintf(("hpfs_unmount: vflushing...\n"));
341
342	error = vflush(mp, 0, flags, td);
343	if (error) {
344		printf("hpfs_unmount: vflush failed: %d\n",error);
345		return (error);
346	}
347
348	vinvalbuf(hpmp->hpm_devvp, V_SAVE, NOCRED, td, 0, 0);
349	g_wither_geom_close(hpmp->hpm_cp->geom, ENXIO);
350	vrele(hpmp->hpm_devvp);
351
352	dprintf(("hpfs_umount: freeing memory...\n"));
353	hpfs_cpdeinit(hpmp);
354	hpfs_bmdeinit(hpmp);
355	mp->mnt_data = (qaddr_t)0;
356	mp->mnt_flag &= ~MNT_LOCAL;
357	FREE(hpmp, M_HPFSMNT);
358
359	return (0);
360}
361
362static int
363hpfs_root(
364	struct mount *mp,
365	struct vnode **vpp,
366	struct thread *td )
367{
368	int error = 0;
369	struct hpfsmount *hpmp = VFSTOHPFS(mp);
370
371	dprintf(("hpfs_root():\n"));
372	error = VFS_VGET(mp, (ino_t)hpmp->hpm_su.su_rootfno, LK_EXCLUSIVE, vpp);
373	if(error) {
374		printf("hpfs_root: VFS_VGET failed: %d\n",error);
375		return (error);
376	}
377
378	return (error);
379}
380
381static int
382hpfs_statfs(
383	struct mount *mp,
384	struct statfs *sbp,
385	struct thread *td)
386{
387	struct hpfsmount *hpmp = VFSTOHPFS(mp);
388
389	dprintf(("hpfs_statfs(): HPFS%d.%d\n",
390		hpmp->hpm_su.su_hpfsver, hpmp->hpm_su.su_fnctver));
391
392	sbp->f_type = mp->mnt_vfc->vfc_typenum;
393	sbp->f_bsize = DEV_BSIZE;
394	sbp->f_iosize = DEV_BSIZE;
395	sbp->f_blocks = hpmp->hpm_su.su_btotal;
396	sbp->f_bfree = sbp->f_bavail = hpmp->hpm_bavail;
397	sbp->f_ffree = 0;
398	sbp->f_files = 0;
399	if (sbp != &mp->mnt_stat) {
400		bcopy((caddr_t)mp->mnt_stat.f_mntonname,
401			(caddr_t)&sbp->f_mntonname[0], MNAMELEN);
402		bcopy((caddr_t)mp->mnt_stat.f_mntfromname,
403			(caddr_t)&sbp->f_mntfromname[0], MNAMELEN);
404	}
405	sbp->f_flags = mp->mnt_flag;
406
407	return (0);
408}
409
410/*ARGSUSED*/
411static int
412hpfs_fhtovp(
413	struct mount *mp,
414	struct fid *fhp,
415	struct vnode **vpp)
416{
417	struct vnode *nvp;
418	struct hpfid *hpfhp = (struct hpfid *)fhp;
419	int error;
420
421	if ((error = VFS_VGET(mp, hpfhp->hpfid_ino, LK_EXCLUSIVE, &nvp)) != 0) {
422		*vpp = NULLVP;
423		return (error);
424	}
425	/* XXX as unlink/rmdir/mkdir/creat are not currently possible
426	 * with HPFS, we don't need to check anything else for now */
427	*vpp = nvp;
428
429	return (0);
430}
431
432static int
433hpfs_vptofh(
434	struct vnode *vp,
435	struct fid *fhp)
436{
437	register struct hpfsnode *hpp;
438	register struct hpfid *hpfhp;
439
440	hpp = VTOHP(vp);
441	hpfhp = (struct hpfid *)fhp;
442	hpfhp->hpfid_len = sizeof(struct hpfid);
443	hpfhp->hpfid_ino = hpp->h_no;
444	/* hpfhp->hpfid_gen = hpp->h_gen; */
445	return (0);
446}
447
448static int
449hpfs_vget(
450	struct mount *mp,
451	ino_t ino,
452	int flags,
453	struct vnode **vpp)
454{
455	struct hpfsmount *hpmp = VFSTOHPFS(mp);
456	struct vnode *vp;
457	struct hpfsnode *hp;
458	struct buf *bp;
459	struct thread *td = curthread;	/* XXX */
460	int error;
461
462	dprintf(("hpfs_vget(0x%x): ",ino));
463
464	*vpp = NULL;
465	hp = NULL;
466	vp = NULL;
467
468	if ((error = hpfs_hphashvget(hpmp->hpm_dev, ino, flags, vpp, td)) != 0)
469		return (error);
470	if (*vpp != NULL) {
471		dprintf(("hashed\n"));
472		return (0);
473	}
474
475	/*
476	 * We have to lock node creation for a while,
477	 * but then we have to call getnewvnode(),
478	 * this may cause hpfs_reclaim() to be called,
479	 * this may need to VOP_VGET() parent dir for
480	 * update reasons, and if parent is not in
481	 * hash, we have to lock node creation...
482	 * To solve this, we MALLOC, getnewvnode and init while
483	 * not locked (probability of node appearence
484	 * at that time is little, and anyway - we'll
485	 * check for it).
486	 */
487	MALLOC(hp, struct hpfsnode *, sizeof(struct hpfsnode),
488		M_HPFSNO, M_WAITOK);
489
490	error = getnewvnode("hpfs", hpmp->hpm_mp, hpfs_vnodeop_p, &vp);
491	if (error) {
492		printf("hpfs_vget: can't get new vnode\n");
493		FREE(hp, M_HPFSNO);
494		return (error);
495	}
496
497	dprintf(("prenew "));
498
499	vp->v_data = hp;
500
501	if (ino == (ino_t)hpmp->hpm_su.su_rootfno)
502		vp->v_vflag |= VV_ROOT;
503
504
505	mtx_init(&hp->h_interlock, "hpfsnode interlock", NULL, MTX_DEF);
506
507	hp->h_flag = H_INVAL;
508	hp->h_vp = vp;
509	hp->h_hpmp = hpmp;
510	hp->h_no = ino;
511	hp->h_dev = hpmp->hpm_dev;
512	hp->h_uid = hpmp->hpm_uid;
513	hp->h_gid = hpmp->hpm_uid;
514	hp->h_mode = hpmp->hpm_mode;
515	hp->h_devvp = hpmp->hpm_devvp;
516	VREF(hp->h_devvp);
517
518	error = vn_lock(vp, LK_EXCLUSIVE, td);
519	if (error) {
520		vput(vp);
521		return (error);
522	}
523
524	do {
525		if ((error =
526		     hpfs_hphashvget(hpmp->hpm_dev, ino, flags, vpp, td))) {
527			vput(vp);
528			return (error);
529		}
530		if (*vpp != NULL) {
531			dprintf(("hashed2\n"));
532			vput(vp);
533			return (0);
534		}
535	} while(lockmgr(&hpfs_hphash_lock,LK_EXCLUSIVE|LK_SLEEPFAIL,NULL,NULL));
536
537	hpfs_hphashins(hp);
538
539	lockmgr(&hpfs_hphash_lock, LK_RELEASE, NULL, NULL);
540
541	error = bread(hpmp->hpm_devvp, ino, FNODESIZE, NOCRED, &bp);
542	if (error) {
543		printf("hpfs_vget: can't read ino %d\n",ino);
544		vput(vp);
545		return (error);
546	}
547	bcopy(bp->b_data, &hp->h_fn, sizeof(struct fnode));
548	brelse(bp);
549
550	if (hp->h_fn.fn_magic != FN_MAGIC) {
551		printf("hpfs_vget: MAGIC DOESN'T MATCH\n");
552		vput(vp);
553		return (EINVAL);
554	}
555
556	vp->v_type = hp->h_fn.fn_flag ? VDIR:VREG;
557	hp->h_flag &= ~H_INVAL;
558
559	*vpp = vp;
560
561	return (0);
562}
563
564static struct vfsops hpfs_vfsops = {
565	.vfs_fhtovp =		hpfs_fhtovp,
566	.vfs_init =		hpfs_init,
567	.vfs_omount =		hpfs_omount,
568	.vfs_root =		hpfs_root,
569	.vfs_statfs =		hpfs_statfs,
570	.vfs_uninit =		hpfs_uninit,
571	.vfs_unmount =		hpfs_unmount,
572	.vfs_vget =		hpfs_vget,
573	.vfs_vptofh =		hpfs_vptofh,
574};
575VFS_SET(hpfs_vfsops, hpfs, 0);
576