1/*	$NetBSD: ntfs_vfsops.c,v 1.87 2011/11/14 18:35:13 hannken Exp $	*/
2
3/*-
4 * Copyright (c) 1998, 1999 Semen Ustimenko
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 *
28 *	Id: ntfs_vfsops.c,v 1.7 1999/05/31 11:28:30 phk Exp
29 */
30
31#include <sys/cdefs.h>
32__KERNEL_RCSID(0, "$NetBSD: ntfs_vfsops.c,v 1.87 2011/11/14 18:35:13 hannken Exp $");
33
34#include <sys/param.h>
35#include <sys/systm.h>
36#include <sys/namei.h>
37#include <sys/proc.h>
38#include <sys/kernel.h>
39#include <sys/vnode.h>
40#include <sys/mount.h>
41#include <sys/buf.h>
42#include <sys/fcntl.h>
43#include <sys/malloc.h>
44#include <sys/sysctl.h>
45#include <sys/device.h>
46#include <sys/conf.h>
47#include <sys/kauth.h>
48#include <sys/module.h>
49
50#include <uvm/uvm_extern.h>
51
52#include <miscfs/genfs/genfs.h>
53#include <miscfs/specfs/specdev.h>
54
55#include <fs/ntfs/ntfs.h>
56#include <fs/ntfs/ntfs_inode.h>
57#include <fs/ntfs/ntfs_subr.h>
58#include <fs/ntfs/ntfs_vfsops.h>
59#include <fs/ntfs/ntfs_ihash.h>
60#include <fs/ntfs/ntfsmount.h>
61
62MODULE(MODULE_CLASS_VFS, ntfs, NULL);
63
64MALLOC_JUSTDEFINE(M_NTFSMNT, "NTFS mount", "NTFS mount structure");
65MALLOC_JUSTDEFINE(M_NTFSNTNODE,"NTFS ntnode",  "NTFS ntnode information");
66MALLOC_JUSTDEFINE(M_NTFSFNODE,"NTFS fnode",  "NTFS fnode information");
67MALLOC_JUSTDEFINE(M_NTFSDIR,"NTFS dir",  "NTFS dir buffer");
68
69static int	ntfs_mount(struct mount *, const char *, void *, size_t *);
70static int	ntfs_root(struct mount *, struct vnode **);
71static int	ntfs_start(struct mount *, int);
72static int	ntfs_statvfs(struct mount *, struct statvfs *);
73static int	ntfs_sync(struct mount *, int, kauth_cred_t);
74static int	ntfs_unmount(struct mount *, int);
75static int	ntfs_vget(struct mount *mp, ino_t ino,
76			       struct vnode **vpp);
77static int	ntfs_mountfs(struct vnode *, struct mount *,
78				  struct ntfs_args *, struct lwp *);
79static int	ntfs_vptofh(struct vnode *, struct fid *, size_t *);
80
81static void     ntfs_init(void);
82static void     ntfs_reinit(void);
83static void     ntfs_done(void);
84static int      ntfs_fhtovp(struct mount *, struct fid *,
85				struct vnode **);
86static int      ntfs_mountroot(void);
87
88static const struct genfs_ops ntfs_genfsops = {
89	.gop_write = genfs_compat_gop_write,
90};
91
92static struct sysctllog *ntfs_sysctl_log;
93
94static int
95ntfs_mountroot(void)
96{
97	struct mount *mp;
98	struct lwp *l = curlwp;	/* XXX */
99	int error;
100	struct ntfs_args args;
101
102	if (device_class(root_device) != DV_DISK)
103		return (ENODEV);
104
105	if ((error = vfs_rootmountalloc(MOUNT_NTFS, "root_device", &mp))) {
106		vrele(rootvp);
107		return (error);
108	}
109
110	args.flag = 0;
111	args.uid = 0;
112	args.gid = 0;
113	args.mode = 0777;
114
115	if ((error = ntfs_mountfs(rootvp, mp, &args, l)) != 0) {
116		vfs_unbusy(mp, false, NULL);
117		vfs_destroy(mp);
118		return (error);
119	}
120
121	mutex_enter(&mountlist_lock);
122	CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list);
123	mutex_exit(&mountlist_lock);
124	(void)ntfs_statvfs(mp, &mp->mnt_stat);
125	vfs_unbusy(mp, false, NULL);
126	return (0);
127}
128
129static void
130ntfs_init(void)
131{
132
133	malloc_type_attach(M_NTFSMNT);
134	malloc_type_attach(M_NTFSNTNODE);
135	malloc_type_attach(M_NTFSFNODE);
136	malloc_type_attach(M_NTFSDIR);
137	malloc_type_attach(M_NTFSNTVATTR);
138	malloc_type_attach(M_NTFSRDATA);
139	malloc_type_attach(M_NTFSDECOMP);
140	malloc_type_attach(M_NTFSRUN);
141	ntfs_nthashinit();
142	ntfs_toupper_init();
143}
144
145static void
146ntfs_reinit(void)
147{
148	ntfs_nthashreinit();
149}
150
151static void
152ntfs_done(void)
153{
154	ntfs_nthashdone();
155	malloc_type_detach(M_NTFSMNT);
156	malloc_type_detach(M_NTFSNTNODE);
157	malloc_type_detach(M_NTFSFNODE);
158	malloc_type_detach(M_NTFSDIR);
159	malloc_type_detach(M_NTFSNTVATTR);
160	malloc_type_detach(M_NTFSRDATA);
161	malloc_type_detach(M_NTFSDECOMP);
162	malloc_type_detach(M_NTFSRUN);
163}
164
165static int
166ntfs_mount (
167	struct mount *mp,
168	const char *path,
169	void *data,
170	size_t *data_len)
171{
172	struct lwp *l = curlwp;
173	int		err = 0, flags;
174	struct vnode	*devvp;
175	struct ntfs_args *args = data;
176
177	if (args == NULL)
178		return EINVAL;
179	if (*data_len < sizeof *args)
180		return EINVAL;
181
182	if (mp->mnt_flag & MNT_GETARGS) {
183		struct ntfsmount *ntmp = VFSTONTFS(mp);
184		if (ntmp == NULL)
185			return EIO;
186		args->fspec = NULL;
187		args->uid = ntmp->ntm_uid;
188		args->gid = ntmp->ntm_gid;
189		args->mode = ntmp->ntm_mode;
190		args->flag = ntmp->ntm_flag;
191		*data_len = sizeof *args;
192		return 0;
193	}
194	/*
195	 ***
196	 * Mounting non-root file system or updating a file system
197	 ***
198	 */
199
200	/*
201	 * If updating, check whether changing from read-only to
202	 * read/write; if there is no device name, that's all we do.
203	 */
204	if (mp->mnt_flag & MNT_UPDATE) {
205		printf("ntfs_mount(): MNT_UPDATE not supported\n");
206		return (EINVAL);
207	}
208
209	/*
210	 * Not an update, or updating the name: look up the name
211	 * and verify that it refers to a sensible block device.
212	 */
213	err = namei_simple_user(args->fspec,
214				NSM_FOLLOW_NOEMULROOT, &devvp);
215	if (err) {
216		/* can't get devvp!*/
217		return (err);
218	}
219
220	if (devvp->v_type != VBLK) {
221		err = ENOTBLK;
222		goto fail;
223	}
224	if (bdevsw_lookup(devvp->v_rdev) == NULL) {
225		err = ENXIO;
226		goto fail;
227	}
228	if (mp->mnt_flag & MNT_UPDATE) {
229#if 0
230		/*
231		 ********************
232		 * UPDATE
233		 ********************
234		 */
235
236		if (devvp != ntmp->um_devvp) {
237			err = EINVAL;	/* needs translation */
238			goto fail;
239		}
240
241		/*
242		 * Update device name only on success
243		 */
244		err = set_statvfs_info(NULL, UIO_USERSPACE, args->fspec,
245		    UIO_USERSPACE, mp->mnt_op->vfs_name, mp, p);
246		if (err)
247			goto fail;
248
249		vrele(devvp);
250#endif
251	} else {
252		/*
253		 ********************
254		 * NEW MOUNT
255		 ********************
256		 */
257
258		/*
259		 * Since this is a new mount, we want the names for
260		 * the device and the mount point copied in.  If an
261		 * error occurs,  the mountpoint is discarded by the
262		 * upper level code.
263		 */
264
265		/* Save "last mounted on" info for mount point (NULL pad)*/
266		err = set_statvfs_info(path, UIO_USERSPACE, args->fspec,
267		    UIO_USERSPACE, mp->mnt_op->vfs_name, mp, l);
268		if (err)
269			goto fail;
270
271		if (mp->mnt_flag & MNT_RDONLY)
272			flags = FREAD;
273		else
274			flags = FREAD|FWRITE;
275		vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
276		err = VOP_OPEN(devvp, flags, FSCRED);
277		VOP_UNLOCK(devvp);
278		if (err)
279			goto fail;
280		err = ntfs_mountfs(devvp, mp, args, l);
281		if (err) {
282			vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
283			(void)VOP_CLOSE(devvp, flags, NOCRED);
284			VOP_UNLOCK(devvp);
285			goto fail;
286		}
287	}
288
289	/*
290	 * Initialize FS stat information in mount struct; uses both
291	 * mp->mnt_stat.f_mntonname and mp->mnt_stat.f_mntfromname
292	 *
293	 * This code is common to root and non-root mounts
294	 */
295	(void)VFS_STATVFS(mp, &mp->mnt_stat);
296	return (err);
297
298fail:
299	vrele(devvp);
300	return (err);
301}
302
303/*
304 * Common code for mount and mountroot
305 */
306int
307ntfs_mountfs(struct vnode *devvp, struct mount *mp, struct ntfs_args *argsp, struct lwp *l)
308{
309	struct buf *bp;
310	struct ntfsmount *ntmp;
311	dev_t dev = devvp->v_rdev;
312	int error, ronly, i;
313	struct vnode *vp;
314
315	ntmp = NULL;
316
317	/*
318	 * Flush out any old buffers remaining from a previous use.
319	 */
320	vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
321	error = vinvalbuf(devvp, V_SAVE, l->l_cred, l, 0, 0);
322	VOP_UNLOCK(devvp);
323	if (error)
324		return (error);
325
326	ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
327
328	bp = NULL;
329
330	error = bread(devvp, BBLOCK, BBSIZE, NOCRED, 0, &bp);
331	if (error)
332		goto out;
333	ntmp = malloc( sizeof *ntmp, M_NTFSMNT, M_WAITOK|M_ZERO);
334	memcpy( &ntmp->ntm_bootfile,  bp->b_data, sizeof(struct bootfile) );
335	brelse( bp , 0 );
336	bp = NULL;
337
338	if (strncmp(ntmp->ntm_bootfile.bf_sysid, NTFS_BBID, NTFS_BBIDLEN)) {
339		error = EINVAL;
340		dprintf(("ntfs_mountfs: invalid boot block\n"));
341		goto out;
342	}
343
344	{
345		int8_t cpr = ntmp->ntm_mftrecsz;
346		if( cpr > 0 )
347			ntmp->ntm_bpmftrec = ntmp->ntm_spc * cpr;
348		else
349			ntmp->ntm_bpmftrec = (1 << (-cpr)) / ntmp->ntm_bps;
350	}
351	dprintf(("ntfs_mountfs(): bps: %d, spc: %d, media: %x, mftrecsz: %d (%d sects)\n",
352		ntmp->ntm_bps,ntmp->ntm_spc,ntmp->ntm_bootfile.bf_media,
353		ntmp->ntm_mftrecsz,ntmp->ntm_bpmftrec));
354	dprintf(("ntfs_mountfs(): mftcn: 0x%x|0x%x\n",
355		(u_int32_t)ntmp->ntm_mftcn,(u_int32_t)ntmp->ntm_mftmirrcn));
356
357	ntmp->ntm_mountp = mp;
358	ntmp->ntm_dev = dev;
359	ntmp->ntm_devvp = devvp;
360	ntmp->ntm_uid = argsp->uid;
361	ntmp->ntm_gid = argsp->gid;
362	ntmp->ntm_mode = argsp->mode;
363	ntmp->ntm_flag = argsp->flag;
364	mp->mnt_data = ntmp;
365
366	/* set file name encode/decode hooks XXX utf-8 only for now */
367	ntmp->ntm_wget = ntfs_utf8_wget;
368	ntmp->ntm_wput = ntfs_utf8_wput;
369	ntmp->ntm_wcmp = ntfs_utf8_wcmp;
370
371	dprintf(("ntfs_mountfs(): case-%s,%s uid: %d, gid: %d, mode: %o\n",
372		(ntmp->ntm_flag & NTFS_MFLAG_CASEINS)?"insens.":"sens.",
373		(ntmp->ntm_flag & NTFS_MFLAG_ALLNAMES)?" allnames,":"",
374		ntmp->ntm_uid, ntmp->ntm_gid, ntmp->ntm_mode));
375
376	/*
377	 * We read in some system nodes to do not allow
378	 * reclaim them and to have everytime access to them.
379	 */
380	{
381		int pi[3] = { NTFS_MFTINO, NTFS_ROOTINO, NTFS_BITMAPINO };
382		for (i=0; i<3; i++) {
383			error = VFS_VGET(mp, pi[i], &(ntmp->ntm_sysvn[pi[i]]));
384			if(error)
385				goto out1;
386			ntmp->ntm_sysvn[pi[i]]->v_vflag |= VV_SYSTEM;
387			vref(ntmp->ntm_sysvn[pi[i]]);
388			vput(ntmp->ntm_sysvn[pi[i]]);
389		}
390	}
391
392	/* read the Unicode lowercase --> uppercase translation table,
393	 * if necessary */
394	if ((error = ntfs_toupper_use(mp, ntmp)))
395		goto out1;
396
397	/*
398	 * Scan $BitMap and count free clusters
399	 */
400	error = ntfs_calccfree(ntmp, &ntmp->ntm_cfree);
401	if(error)
402		goto out1;
403
404	/*
405	 * Read and translate to internal format attribute
406	 * definition file.
407	 */
408	{
409		int num,j;
410		struct attrdef ad;
411
412		/* Open $AttrDef */
413		error = VFS_VGET(mp, NTFS_ATTRDEFINO, &vp );
414		if(error)
415			goto out1;
416
417		/* Count valid entries */
418		for(num=0;;num++) {
419			error = ntfs_readattr(ntmp, VTONT(vp),
420					NTFS_A_DATA, NULL,
421					num * sizeof(ad), sizeof(ad),
422					&ad, NULL);
423			if (error)
424				goto out1;
425			if (ad.ad_name[0] == 0)
426				break;
427		}
428
429		/* Alloc memory for attribute definitions */
430		ntmp->ntm_ad = (struct ntvattrdef *) malloc(
431			num * sizeof(struct ntvattrdef),
432			M_NTFSMNT, M_WAITOK);
433
434		ntmp->ntm_adnum = num;
435
436		/* Read them and translate */
437		for(i=0;i<num;i++){
438			error = ntfs_readattr(ntmp, VTONT(vp),
439					NTFS_A_DATA, NULL,
440					i * sizeof(ad), sizeof(ad),
441					&ad, NULL);
442			if (error)
443				goto out1;
444			j = 0;
445			do {
446				ntmp->ntm_ad[i].ad_name[j] = ad.ad_name[j];
447			} while(ad.ad_name[j++]);
448			ntmp->ntm_ad[i].ad_namelen = j - 1;
449			ntmp->ntm_ad[i].ad_type = ad.ad_type;
450		}
451
452		vput(vp);
453	}
454
455	mp->mnt_stat.f_fsidx.__fsid_val[0] = dev;
456	mp->mnt_stat.f_fsidx.__fsid_val[1] = makefstype(MOUNT_NTFS);
457	mp->mnt_stat.f_fsid = mp->mnt_stat.f_fsidx.__fsid_val[0];
458	mp->mnt_stat.f_namemax = NTFS_MAXFILENAME;
459	mp->mnt_flag |= MNT_LOCAL;
460	devvp->v_specmountpoint = mp;
461	return (0);
462
463out1:
464	for(i=0;i<NTFS_SYSNODESNUM;i++)
465		if(ntmp->ntm_sysvn[i]) vrele(ntmp->ntm_sysvn[i]);
466
467	if (vflush(mp,NULLVP,0)) {
468		dprintf(("ntfs_mountfs: vflush failed\n"));
469	}
470out:
471	devvp->v_specmountpoint = NULL;
472	if (bp)
473		brelse(bp, 0);
474
475	if (error) {
476		if (ntmp) {
477			if (ntmp->ntm_ad)
478				free(ntmp->ntm_ad, M_NTFSMNT);
479			free(ntmp, M_NTFSMNT);
480		}
481	}
482
483	return (error);
484}
485
486static int
487ntfs_start (
488	struct mount *mp,
489	int flags)
490{
491	return (0);
492}
493
494static int
495ntfs_unmount(
496	struct mount *mp,
497	int mntflags)
498{
499	struct lwp *l = curlwp;
500	struct ntfsmount *ntmp;
501	int error, ronly = 0, flags, i;
502
503	dprintf(("ntfs_unmount: unmounting...\n"));
504	ntmp = VFSTONTFS(mp);
505
506	flags = 0;
507	if(mntflags & MNT_FORCE)
508		flags |= FORCECLOSE;
509
510	dprintf(("ntfs_unmount: vflushing...\n"));
511	error = vflush(mp,NULLVP,flags | SKIPSYSTEM);
512	if (error) {
513		dprintf(("ntfs_unmount: vflush failed: %d\n",error));
514		return (error);
515	}
516
517	/* Check if only system vnodes are rest */
518	for(i=0;i<NTFS_SYSNODESNUM;i++)
519		 if((ntmp->ntm_sysvn[i]) &&
520		    (ntmp->ntm_sysvn[i]->v_usecount > 1)) return (EBUSY);
521
522	/* Dereference all system vnodes */
523	for(i=0;i<NTFS_SYSNODESNUM;i++)
524		 if(ntmp->ntm_sysvn[i]) vrele(ntmp->ntm_sysvn[i]);
525
526	/* vflush system vnodes */
527	error = vflush(mp,NULLVP,flags);
528	if (error) {
529		panic("ntfs_unmount: vflush failed(sysnodes): %d\n",error);
530	}
531
532	/* Check if the type of device node isn't VBAD before
533	 * touching v_specinfo.  If the device vnode is revoked, the
534	 * field is NULL and touching it causes null pointer derefercence.
535	 */
536	if (ntmp->ntm_devvp->v_type != VBAD)
537		ntmp->ntm_devvp->v_specmountpoint = NULL;
538
539	vinvalbuf(ntmp->ntm_devvp, V_SAVE, NOCRED, l, 0, 0);
540
541	/* lock the device vnode before calling VOP_CLOSE() */
542	vn_lock(ntmp->ntm_devvp, LK_EXCLUSIVE | LK_RETRY);
543	error = VOP_CLOSE(ntmp->ntm_devvp, ronly ? FREAD : FREAD|FWRITE,
544		NOCRED);
545	KASSERT(error == 0);
546	VOP_UNLOCK(ntmp->ntm_devvp);
547
548	vrele(ntmp->ntm_devvp);
549
550	/* free the toupper table, if this has been last mounted ntfs volume */
551	ntfs_toupper_unuse();
552
553	dprintf(("ntfs_umount: freeing memory...\n"));
554	mp->mnt_data = NULL;
555	mp->mnt_flag &= ~MNT_LOCAL;
556	free(ntmp->ntm_ad, M_NTFSMNT);
557	free(ntmp, M_NTFSMNT);
558	return (0);
559}
560
561static int
562ntfs_root(
563	struct mount *mp,
564	struct vnode **vpp)
565{
566	struct vnode *nvp;
567	int error = 0;
568
569	dprintf(("ntfs_root(): sysvn: %p\n",
570		VFSTONTFS(mp)->ntm_sysvn[NTFS_ROOTINO]));
571	error = VFS_VGET(mp, (ino_t)NTFS_ROOTINO, &nvp);
572	if(error) {
573		printf("ntfs_root: VFS_VGET failed: %d\n",error);
574		return (error);
575	}
576
577	*vpp = nvp;
578	return (0);
579}
580
581int
582ntfs_calccfree(
583	struct ntfsmount *ntmp,
584	cn_t *cfreep)
585{
586	struct vnode *vp;
587	u_int8_t *tmp;
588	int j, error;
589	cn_t cfree = 0;
590	size_t bmsize, i;
591
592	vp = ntmp->ntm_sysvn[NTFS_BITMAPINO];
593
594	bmsize = VTOF(vp)->f_size;
595
596	tmp = (u_int8_t *) malloc(bmsize, M_TEMP, M_WAITOK);
597
598	error = ntfs_readattr(ntmp, VTONT(vp), NTFS_A_DATA, NULL,
599			       0, bmsize, tmp, NULL);
600	if (error)
601		goto out;
602
603	for(i=0;i<bmsize;i++)
604		for(j=0;j<8;j++)
605			if(~tmp[i] & (1 << j)) cfree++;
606	*cfreep = cfree;
607
608    out:
609	free(tmp, M_TEMP);
610	return(error);
611}
612
613static int
614ntfs_statvfs(
615	struct mount *mp,
616	struct statvfs *sbp)
617{
618	struct ntfsmount *ntmp = VFSTONTFS(mp);
619	u_int64_t mftallocated;
620
621	dprintf(("ntfs_statvfs():\n"));
622
623	mftallocated = VTOF(ntmp->ntm_sysvn[NTFS_MFTINO])->f_allocated;
624
625	sbp->f_bsize = ntmp->ntm_bps;
626	sbp->f_frsize = sbp->f_bsize; /* XXX */
627	sbp->f_iosize = ntmp->ntm_bps * ntmp->ntm_spc;
628	sbp->f_blocks = ntmp->ntm_bootfile.bf_spv;
629	sbp->f_bfree = sbp->f_bavail = ntfs_cntobn(ntmp->ntm_cfree);
630	sbp->f_ffree = sbp->f_favail = sbp->f_bfree / ntmp->ntm_bpmftrec;
631	sbp->f_files = mftallocated / ntfs_bntob(ntmp->ntm_bpmftrec) +
632	    sbp->f_ffree;
633	sbp->f_fresvd = sbp->f_bresvd = 0; /* XXX */
634	sbp->f_flag = mp->mnt_flag;
635	copy_statvfs_info(sbp, mp);
636	return (0);
637}
638
639static int
640ntfs_sync (
641	struct mount *mp,
642	int waitfor,
643	kauth_cred_t cred)
644{
645	/*dprintf(("ntfs_sync():\n"));*/
646	return (0);
647}
648
649/*ARGSUSED*/
650static int
651ntfs_fhtovp(
652	struct mount *mp,
653	struct fid *fhp,
654	struct vnode **vpp)
655{
656	struct ntfid ntfh;
657	int error;
658
659	if (fhp->fid_len != sizeof(struct ntfid))
660		return EINVAL;
661	memcpy(&ntfh, fhp, sizeof(ntfh));
662	ddprintf(("ntfs_fhtovp(): %s: %llu\n", mp->mnt_stat.f_mntonname,
663	    (unsigned long long)ntfh.ntfid_ino));
664
665	error = ntfs_vgetex(mp, ntfh.ntfid_ino, ntfh.ntfid_attr, NULL,
666			LK_EXCLUSIVE, 0, vpp);
667	if (error != 0) {
668		*vpp = NULLVP;
669		return (error);
670	}
671
672	/* XXX as unlink/rmdir/mkdir/creat are not currently possible
673	 * with NTFS, we don't need to check anything else for now */
674	return (0);
675}
676
677static int
678ntfs_vptofh(
679	struct vnode *vp,
680	struct fid *fhp,
681	size_t *fh_size)
682{
683	struct ntnode *ntp;
684	struct ntfid ntfh;
685	struct fnode *fn;
686
687	if (*fh_size < sizeof(struct ntfid)) {
688		*fh_size = sizeof(struct ntfid);
689		return E2BIG;
690	}
691	*fh_size = sizeof(struct ntfid);
692
693	ddprintf(("ntfs_fhtovp(): %s: %p\n", vp->v_mount->mnt_stat.f_mntonname,
694		vp));
695
696	fn = VTOF(vp);
697	ntp = VTONT(vp);
698	memset(&ntfh, 0, sizeof(ntfh));
699	ntfh.ntfid_len = sizeof(struct ntfid);
700	ntfh.ntfid_ino = ntp->i_number;
701	ntfh.ntfid_attr = fn->f_attrtype;
702#ifdef notyet
703	ntfh.ntfid_gen = ntp->i_gen;
704#endif
705	memcpy(fhp, &ntfh, sizeof(ntfh));
706	return (0);
707}
708
709int
710ntfs_vgetex(
711	struct mount *mp,
712	ino_t ino,
713	u_int32_t attrtype,
714	char *attrname,
715	u_long lkflags,
716	u_long flags,
717	struct vnode **vpp)
718{
719	int error;
720	struct ntfsmount *ntmp;
721	struct ntnode *ip;
722	struct fnode *fp;
723	struct vnode *vp;
724	enum vtype f_type = VBAD;
725
726	dprintf(("ntfs_vgetex: ino: %llu, attr: 0x%x:%s, lkf: 0x%lx, f:"
727	    " 0x%lx\n", (unsigned long long)ino, attrtype,
728	    attrname ? attrname : "", (u_long)lkflags, (u_long)flags));
729
730	ntmp = VFSTONTFS(mp);
731	*vpp = NULL;
732
733loop:
734	/* Get ntnode */
735	error = ntfs_ntlookup(ntmp, ino, &ip);
736	if (error) {
737		printf("ntfs_vget: ntfs_ntget failed\n");
738		return (error);
739	}
740
741	/* It may be not initialized fully, so force load it */
742	if (!(flags & VG_DONTLOADIN) && !(ip->i_flag & IN_LOADED)) {
743		error = ntfs_loadntnode(ntmp, ip);
744		if(error) {
745			printf("ntfs_vget: CAN'T LOAD ATTRIBUTES FOR INO:"
746			    " %llu\n", (unsigned long long)ip->i_number);
747			ntfs_ntput(ip);
748			return (error);
749		}
750	}
751
752	error = ntfs_fget(ntmp, ip, attrtype, attrname, &fp);
753	if (error) {
754		printf("ntfs_vget: ntfs_fget failed\n");
755		ntfs_ntput(ip);
756		return (error);
757	}
758
759	if (!(flags & VG_DONTVALIDFN) && !(fp->f_flag & FN_VALID)) {
760		if ((ip->i_frflag & NTFS_FRFLAG_DIR) &&
761		    (fp->f_attrtype == NTFS_A_DATA && fp->f_attrname == NULL)) {
762			f_type = VDIR;
763		} else if (flags & VG_EXT) {
764			f_type = VNON;
765			fp->f_size = fp->f_allocated = 0;
766		} else {
767			f_type = VREG;
768
769			error = ntfs_filesize(ntmp, fp,
770					      &fp->f_size, &fp->f_allocated);
771			if (error) {
772				ntfs_ntput(ip);
773				return (error);
774			}
775		}
776
777		fp->f_flag |= FN_VALID;
778	}
779
780	/*
781	 * We may be calling vget() now. To avoid potential deadlock, we need
782	 * to release ntnode lock, since due to locking order vnode
783	 * lock has to be acquired first.
784	 * ntfs_fget() bumped ntnode usecount, so ntnode won't be recycled
785	 * prematurely.
786	 * Take v_interlock before releasing ntnode lock to avoid races.
787	 */
788	vp = FTOV(fp);
789	if (vp) {
790		mutex_enter(vp->v_interlock);
791		ntfs_ntput(ip);
792		if (vget(vp, lkflags) != 0)
793			goto loop;
794		*vpp = vp;
795		return 0;
796	}
797	ntfs_ntput(ip);
798
799	error = getnewvnode(VT_NTFS, ntmp->ntm_mountp, ntfs_vnodeop_p,
800	    NULL, &vp);
801	if(error) {
802		ntfs_frele(fp);
803		return (error);
804	}
805	ntfs_ntget(ip);
806	error = ntfs_fget(ntmp, ip, attrtype, attrname, &fp);
807	if (error) {
808		printf("ntfs_vget: ntfs_fget failed\n");
809		ntfs_ntput(ip);
810		return (error);
811	}
812	if (FTOV(fp)) {
813		/*
814		 * Another thread beat us, put back freshly allocated
815		 * vnode and retry.
816		 */
817		ntfs_ntput(ip);
818		ungetnewvnode(vp);
819		goto loop;
820	}
821	dprintf(("ntfs_vget: vnode: %p for ntnode: %llu\n", vp,
822	    (unsigned long long)ino));
823
824	fp->f_vp = vp;
825	vp->v_data = fp;
826	if (f_type != VBAD)
827		vp->v_type = f_type;
828	genfs_node_init(vp, &ntfs_genfsops);
829
830	if (ino == NTFS_ROOTINO)
831		vp->v_vflag |= VV_ROOT;
832
833	ntfs_ntput(ip);
834
835	if (lkflags & (LK_EXCLUSIVE | LK_SHARED)) {
836		error = vn_lock(vp, lkflags);
837		if (error) {
838			vput(vp);
839			return (error);
840		}
841	}
842
843	uvm_vnp_setsize(vp, fp->f_size); /* XXX: mess, cf. ntfs_lookupfile() */
844	vref(ip->i_devvp);
845	*vpp = vp;
846	return (0);
847}
848
849static int
850ntfs_vget(
851	struct mount *mp,
852	ino_t ino,
853	struct vnode **vpp)
854{
855	return ntfs_vgetex(mp, ino, NTFS_A_DATA, NULL, LK_EXCLUSIVE, 0, vpp);
856}
857
858extern const struct vnodeopv_desc ntfs_vnodeop_opv_desc;
859
860const struct vnodeopv_desc * const ntfs_vnodeopv_descs[] = {
861	&ntfs_vnodeop_opv_desc,
862	NULL,
863};
864
865struct vfsops ntfs_vfsops = {
866	MOUNT_NTFS,
867	sizeof (struct ntfs_args),
868	ntfs_mount,
869	ntfs_start,
870	ntfs_unmount,
871	ntfs_root,
872	(void *)eopnotsupp,	/* vfs_quotactl */
873	ntfs_statvfs,
874	ntfs_sync,
875	ntfs_vget,
876	ntfs_fhtovp,
877	ntfs_vptofh,
878	ntfs_init,
879	ntfs_reinit,
880	ntfs_done,
881	ntfs_mountroot,
882	(int (*)(struct mount *, struct vnode *, struct timespec *)) eopnotsupp,
883	vfs_stdextattrctl,
884	(void *)eopnotsupp,		/* vfs_suspendctl */
885	genfs_renamelock_enter,
886	genfs_renamelock_exit,
887	(void *)eopnotsupp,
888	ntfs_vnodeopv_descs,
889	0,
890	{ NULL, NULL },
891};
892
893static int
894ntfs_modcmd(modcmd_t cmd, void *arg)
895{
896	int error;
897
898	switch (cmd) {
899	case MODULE_CMD_INIT:
900		error = vfs_attach(&ntfs_vfsops);
901		if (error != 0)
902			break;
903		sysctl_createv(&ntfs_sysctl_log, 0, NULL, NULL,
904			       CTLFLAG_PERMANENT,
905			       CTLTYPE_NODE, "vfs", NULL,
906			       NULL, 0, NULL, 0,
907			       CTL_VFS, CTL_EOL);
908		sysctl_createv(&ntfs_sysctl_log, 0, NULL, NULL,
909			       CTLFLAG_PERMANENT,
910			       CTLTYPE_NODE, "ntfs",
911			       SYSCTL_DESCR("NTFS file system"),
912			       NULL, 0, NULL, 0,
913			       CTL_VFS, 20, CTL_EOL);
914		/*
915		 * XXX the "20" above could be dynamic, thereby eliminating
916		 * one more instance of the "number to vfs" mapping problem,
917		 * but "20" is the order as taken from sys/mount.h
918		 */
919		break;
920	case MODULE_CMD_FINI:
921		error = vfs_detach(&ntfs_vfsops);
922		if (error != 0)
923			break;
924		sysctl_teardown(&ntfs_sysctl_log);
925		break;
926	default:
927		error = ENOTTY;
928		break;
929	}
930
931	return (error);
932}
933