1 /* $NetBSD: ntfs_vfsops.c,v 1.79 2009/09/01 15:16:41 pooka Exp $ */
4 * Copyright (c) 1998, 1999 Semen Ustimenko
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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
28 * Id: ntfs_vfsops.c,v 1.7 1999/05/31 11:28:30 phk Exp
31 #include <sys/cdefs.h>
32 __KERNEL_RCSID(0, "$NetBSD: ntfs_vfsops.c,v 1.79 2009/09/01 15:16:41 pooka Exp $");
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/namei.h>
38 #include <sys/kernel.h>
39 #include <sys/vnode.h>
40 #include <sys/mount.h>
42 #include <sys/fcntl.h>
43 #include <sys/malloc.h>
44 #include <sys/sysctl.h>
45 #include <sys/device.h>
47 #include <sys/kauth.h>
48 #include <sys/module.h>
50 #include <uvm/uvm_extern.h>
52 #include <miscfs/genfs/genfs.h>
53 #include <miscfs/specfs/specdev.h>
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>
62 MODULE(MODULE_CLASS_VFS
, ntfs
, NULL
);
64 MALLOC_JUSTDEFINE(M_NTFSMNT
, "NTFS mount", "NTFS mount structure");
65 MALLOC_JUSTDEFINE(M_NTFSNTNODE
,"NTFS ntnode", "NTFS ntnode information");
66 MALLOC_JUSTDEFINE(M_NTFSFNODE
,"NTFS fnode", "NTFS fnode information");
67 MALLOC_JUSTDEFINE(M_NTFSDIR
,"NTFS dir", "NTFS dir buffer");
69 static int ntfs_mount(struct mount
*, const char *, void *, size_t *);
70 static int ntfs_root(struct mount
*, struct vnode
**);
71 static int ntfs_start(struct mount
*, int);
72 static int ntfs_statvfs(struct mount
*, struct statvfs
*);
73 static int ntfs_sync(struct mount
*, int, kauth_cred_t
);
74 static int ntfs_unmount(struct mount
*, int);
75 static int ntfs_vget(struct mount
*mp
, ino_t ino
,
77 static int ntfs_mountfs(struct vnode
*, struct mount
*,
78 struct ntfs_args
*, struct lwp
*);
79 static int ntfs_vptofh(struct vnode
*, struct fid
*, size_t *);
81 static void ntfs_init(void);
82 static void ntfs_reinit(void);
83 static void ntfs_done(void);
84 static int ntfs_fhtovp(struct mount
*, struct fid
*,
86 static int ntfs_mountroot(void);
88 static const struct genfs_ops ntfs_genfsops
= {
89 .gop_write
= genfs_compat_gop_write
,
92 static struct sysctllog
*ntfs_sysctl_log
;
98 struct lwp
*l
= curlwp
; /* XXX */
100 struct ntfs_args args
;
102 if (device_class(root_device
) != DV_DISK
)
105 if ((error
= vfs_rootmountalloc(MOUNT_NTFS
, "root_device", &mp
))) {
115 if ((error
= ntfs_mountfs(rootvp
, mp
, &args
, l
)) != 0) {
116 vfs_unbusy(mp
, false, NULL
);
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
);
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
);
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
);
172 struct lwp
*l
= curlwp
;
175 struct ntfs_args
*args
= data
;
177 if (*data_len
< sizeof *args
)
180 if (mp
->mnt_flag
& MNT_GETARGS
) {
181 struct ntfsmount
*ntmp
= VFSTONTFS(mp
);
185 args
->uid
= ntmp
->ntm_uid
;
186 args
->gid
= ntmp
->ntm_gid
;
187 args
->mode
= ntmp
->ntm_mode
;
188 args
->flag
= ntmp
->ntm_flag
;
189 *data_len
= sizeof *args
;
194 * Mounting non-root file system or updating a file system
199 * If updating, check whether changing from read-only to
200 * read/write; if there is no device name, that's all we do.
202 if (mp
->mnt_flag
& MNT_UPDATE
) {
203 printf("ntfs_mount(): MNT_UPDATE not supported\n");
208 * Not an update, or updating the name: look up the name
209 * and verify that it refers to a sensible block device.
211 err
= namei_simple_user(args
->fspec
,
212 NSM_FOLLOW_NOEMULROOT
, &devvp
);
214 /* can't get devvp!*/
218 if (devvp
->v_type
!= VBLK
) {
222 if (bdevsw_lookup(devvp
->v_rdev
) == NULL
) {
226 if (mp
->mnt_flag
& MNT_UPDATE
) {
234 if (devvp
!= ntmp
->um_devvp
) {
235 err
= EINVAL
; /* needs translation */
240 * Update device name only on success
242 err
= set_statvfs_info(NULL
, UIO_USERSPACE
, args
->fspec
,
243 UIO_USERSPACE
, mp
->mnt_op
->vfs_name
, mp
, p
);
257 * Since this is a new mount, we want the names for
258 * the device and the mount point copied in. If an
259 * error occurs, the mountpoint is discarded by the
263 /* Save "last mounted on" info for mount point (NULL pad)*/
264 err
= set_statvfs_info(path
, UIO_USERSPACE
, args
->fspec
,
265 UIO_USERSPACE
, mp
->mnt_op
->vfs_name
, mp
, l
);
269 if (mp
->mnt_flag
& MNT_RDONLY
)
272 flags
= FREAD
|FWRITE
;
273 err
= VOP_OPEN(devvp
, flags
, FSCRED
);
276 err
= ntfs_mountfs(devvp
, mp
, args
, l
);
278 vn_lock(devvp
, LK_EXCLUSIVE
| LK_RETRY
);
279 (void)VOP_CLOSE(devvp
, flags
, NOCRED
);
280 VOP_UNLOCK(devvp
, 0);
286 * Initialize FS stat information in mount struct; uses both
287 * mp->mnt_stat.f_mntonname and mp->mnt_stat.f_mntfromname
289 * This code is common to root and non-root mounts
291 (void)VFS_STATVFS(mp
, &mp
->mnt_stat
);
300 * Common code for mount and mountroot
303 ntfs_mountfs(struct vnode
*devvp
, struct mount
*mp
, struct ntfs_args
*argsp
, struct lwp
*l
)
306 struct ntfsmount
*ntmp
;
307 dev_t dev
= devvp
->v_rdev
;
314 * Flush out any old buffers remaining from a previous use.
316 vn_lock(devvp
, LK_EXCLUSIVE
| LK_RETRY
);
317 error
= vinvalbuf(devvp
, V_SAVE
, l
->l_cred
, l
, 0, 0);
318 VOP_UNLOCK(devvp
, 0);
322 ronly
= (mp
->mnt_flag
& MNT_RDONLY
) != 0;
326 error
= bread(devvp
, BBLOCK
, BBSIZE
, NOCRED
, 0, &bp
);
329 ntmp
= malloc( sizeof *ntmp
, M_NTFSMNT
, M_WAITOK
|M_ZERO
);
330 memcpy( &ntmp
->ntm_bootfile
, bp
->b_data
, sizeof(struct bootfile
) );
334 if (strncmp(ntmp
->ntm_bootfile
.bf_sysid
, NTFS_BBID
, NTFS_BBIDLEN
)) {
336 dprintf(("ntfs_mountfs: invalid boot block\n"));
341 int8_t cpr
= ntmp
->ntm_mftrecsz
;
343 ntmp
->ntm_bpmftrec
= ntmp
->ntm_spc
* cpr
;
345 ntmp
->ntm_bpmftrec
= (1 << (-cpr
)) / ntmp
->ntm_bps
;
347 dprintf(("ntfs_mountfs(): bps: %d, spc: %d, media: %x, mftrecsz: %d (%d sects)\n",
348 ntmp
->ntm_bps
,ntmp
->ntm_spc
,ntmp
->ntm_bootfile
.bf_media
,
349 ntmp
->ntm_mftrecsz
,ntmp
->ntm_bpmftrec
));
350 dprintf(("ntfs_mountfs(): mftcn: 0x%x|0x%x\n",
351 (u_int32_t
)ntmp
->ntm_mftcn
,(u_int32_t
)ntmp
->ntm_mftmirrcn
));
353 ntmp
->ntm_mountp
= mp
;
355 ntmp
->ntm_devvp
= devvp
;
356 ntmp
->ntm_uid
= argsp
->uid
;
357 ntmp
->ntm_gid
= argsp
->gid
;
358 ntmp
->ntm_mode
= argsp
->mode
;
359 ntmp
->ntm_flag
= argsp
->flag
;
362 /* set file name encode/decode hooks XXX utf-8 only for now */
363 ntmp
->ntm_wget
= ntfs_utf8_wget
;
364 ntmp
->ntm_wput
= ntfs_utf8_wput
;
365 ntmp
->ntm_wcmp
= ntfs_utf8_wcmp
;
367 dprintf(("ntfs_mountfs(): case-%s,%s uid: %d, gid: %d, mode: %o\n",
368 (ntmp
->ntm_flag
& NTFS_MFLAG_CASEINS
)?"insens.":"sens.",
369 (ntmp
->ntm_flag
& NTFS_MFLAG_ALLNAMES
)?" allnames,":"",
370 ntmp
->ntm_uid
, ntmp
->ntm_gid
, ntmp
->ntm_mode
));
373 * We read in some system nodes to do not allow
374 * reclaim them and to have everytime access to them.
377 int pi
[3] = { NTFS_MFTINO
, NTFS_ROOTINO
, NTFS_BITMAPINO
};
378 for (i
=0; i
<3; i
++) {
379 error
= VFS_VGET(mp
, pi
[i
], &(ntmp
->ntm_sysvn
[pi
[i
]]));
382 ntmp
->ntm_sysvn
[pi
[i
]]->v_vflag
|= VV_SYSTEM
;
383 vref(ntmp
->ntm_sysvn
[pi
[i
]]);
384 vput(ntmp
->ntm_sysvn
[pi
[i
]]);
388 /* read the Unicode lowercase --> uppercase translation table,
390 if ((error
= ntfs_toupper_use(mp
, ntmp
)))
394 * Scan $BitMap and count free clusters
396 error
= ntfs_calccfree(ntmp
, &ntmp
->ntm_cfree
);
401 * Read and translate to internal format attribute
409 error
= VFS_VGET(mp
, NTFS_ATTRDEFINO
, &vp
);
413 /* Count valid entries */
415 error
= ntfs_readattr(ntmp
, VTONT(vp
),
417 num
* sizeof(ad
), sizeof(ad
),
421 if (ad
.ad_name
[0] == 0)
425 /* Alloc memory for attribute definitions */
426 ntmp
->ntm_ad
= (struct ntvattrdef
*) malloc(
427 num
* sizeof(struct ntvattrdef
),
428 M_NTFSMNT
, M_WAITOK
);
430 ntmp
->ntm_adnum
= num
;
432 /* Read them and translate */
434 error
= ntfs_readattr(ntmp
, VTONT(vp
),
436 i
* sizeof(ad
), sizeof(ad
),
442 ntmp
->ntm_ad
[i
].ad_name
[j
] = ad
.ad_name
[j
];
443 } while(ad
.ad_name
[j
++]);
444 ntmp
->ntm_ad
[i
].ad_namelen
= j
- 1;
445 ntmp
->ntm_ad
[i
].ad_type
= ad
.ad_type
;
451 mp
->mnt_stat
.f_fsidx
.__fsid_val
[0] = dev
;
452 mp
->mnt_stat
.f_fsidx
.__fsid_val
[1] = makefstype(MOUNT_NTFS
);
453 mp
->mnt_stat
.f_fsid
= mp
->mnt_stat
.f_fsidx
.__fsid_val
[0];
454 mp
->mnt_stat
.f_namemax
= NTFS_MAXFILENAME
;
455 mp
->mnt_flag
|= MNT_LOCAL
;
456 devvp
->v_specmountpoint
= mp
;
460 for(i
=0;i
<NTFS_SYSNODESNUM
;i
++)
461 if(ntmp
->ntm_sysvn
[i
]) vrele(ntmp
->ntm_sysvn
[i
]);
463 if (vflush(mp
,NULLVP
,0)) {
464 dprintf(("ntfs_mountfs: vflush failed\n"));
467 devvp
->v_specmountpoint
= NULL
;
474 free(ntmp
->ntm_ad
, M_NTFSMNT
);
475 free(ntmp
, M_NTFSMNT
);
495 struct lwp
*l
= curlwp
;
496 struct ntfsmount
*ntmp
;
497 int error
, ronly
= 0, flags
, i
;
499 dprintf(("ntfs_unmount: unmounting...\n"));
500 ntmp
= VFSTONTFS(mp
);
503 if(mntflags
& MNT_FORCE
)
506 dprintf(("ntfs_unmount: vflushing...\n"));
507 error
= vflush(mp
,NULLVP
,flags
| SKIPSYSTEM
);
509 dprintf(("ntfs_unmount: vflush failed: %d\n",error
));
513 /* Check if only system vnodes are rest */
514 for(i
=0;i
<NTFS_SYSNODESNUM
;i
++)
515 if((ntmp
->ntm_sysvn
[i
]) &&
516 (ntmp
->ntm_sysvn
[i
]->v_usecount
> 1)) return (EBUSY
);
518 /* Dereference all system vnodes */
519 for(i
=0;i
<NTFS_SYSNODESNUM
;i
++)
520 if(ntmp
->ntm_sysvn
[i
]) vrele(ntmp
->ntm_sysvn
[i
]);
522 /* vflush system vnodes */
523 error
= vflush(mp
,NULLVP
,flags
);
525 panic("ntfs_unmount: vflush failed(sysnodes): %d\n",error
);
528 /* Check if the type of device node isn't VBAD before
529 * touching v_specinfo. If the device vnode is revoked, the
530 * field is NULL and touching it causes null pointer derefercence.
532 if (ntmp
->ntm_devvp
->v_type
!= VBAD
)
533 ntmp
->ntm_devvp
->v_specmountpoint
= NULL
;
535 vinvalbuf(ntmp
->ntm_devvp
, V_SAVE
, NOCRED
, l
, 0, 0);
537 /* lock the device vnode before calling VOP_CLOSE() */
538 vn_lock(ntmp
->ntm_devvp
, LK_EXCLUSIVE
| LK_RETRY
);
539 error
= VOP_CLOSE(ntmp
->ntm_devvp
, ronly
? FREAD
: FREAD
|FWRITE
,
542 VOP_UNLOCK(ntmp
->ntm_devvp
, 0);
544 vrele(ntmp
->ntm_devvp
);
546 /* free the toupper table, if this has been last mounted ntfs volume */
547 ntfs_toupper_unuse();
549 dprintf(("ntfs_umount: freeing memory...\n"));
551 mp
->mnt_flag
&= ~MNT_LOCAL
;
552 free(ntmp
->ntm_ad
, M_NTFSMNT
);
553 free(ntmp
, M_NTFSMNT
);
565 dprintf(("ntfs_root(): sysvn: %p\n",
566 VFSTONTFS(mp
)->ntm_sysvn
[NTFS_ROOTINO
]));
567 error
= VFS_VGET(mp
, (ino_t
)NTFS_ROOTINO
, &nvp
);
569 printf("ntfs_root: VFS_VGET failed: %d\n",error
);
579 struct ntfsmount
*ntmp
,
588 vp
= ntmp
->ntm_sysvn
[NTFS_BITMAPINO
];
590 bmsize
= VTOF(vp
)->f_size
;
592 tmp
= (u_int8_t
*) malloc(bmsize
, M_TEMP
, M_WAITOK
);
594 error
= ntfs_readattr(ntmp
, VTONT(vp
), NTFS_A_DATA
, NULL
,
595 0, bmsize
, tmp
, NULL
);
599 for(i
=0;i
<bmsize
;i
++)
601 if(~tmp
[i
] & (1 << j
)) cfree
++;
614 struct ntfsmount
*ntmp
= VFSTONTFS(mp
);
615 u_int64_t mftallocated
;
617 dprintf(("ntfs_statvfs():\n"));
619 mftallocated
= VTOF(ntmp
->ntm_sysvn
[NTFS_MFTINO
])->f_allocated
;
621 sbp
->f_bsize
= ntmp
->ntm_bps
;
622 sbp
->f_frsize
= sbp
->f_bsize
; /* XXX */
623 sbp
->f_iosize
= ntmp
->ntm_bps
* ntmp
->ntm_spc
;
624 sbp
->f_blocks
= ntmp
->ntm_bootfile
.bf_spv
;
625 sbp
->f_bfree
= sbp
->f_bavail
= ntfs_cntobn(ntmp
->ntm_cfree
);
626 sbp
->f_ffree
= sbp
->f_favail
= sbp
->f_bfree
/ ntmp
->ntm_bpmftrec
;
627 sbp
->f_files
= mftallocated
/ ntfs_bntob(ntmp
->ntm_bpmftrec
) +
629 sbp
->f_fresvd
= sbp
->f_bresvd
= 0; /* XXX */
630 sbp
->f_flag
= mp
->mnt_flag
;
631 copy_statvfs_info(sbp
, mp
);
641 /*dprintf(("ntfs_sync():\n"));*/
655 if (fhp
->fid_len
!= sizeof(struct ntfid
))
657 memcpy(&ntfh
, fhp
, sizeof(ntfh
));
658 ddprintf(("ntfs_fhtovp(): %s: %llu\n", mp
->mnt_stat
.f_mntonname
,
659 (unsigned long long)ntfh
.ntfid_ino
));
661 error
= ntfs_vgetex(mp
, ntfh
.ntfid_ino
, ntfh
.ntfid_attr
, NULL
,
662 LK_EXCLUSIVE
| LK_RETRY
, 0, vpp
);
668 /* XXX as unlink/rmdir/mkdir/creat are not currently possible
669 * with NTFS, we don't need to check anything else for now */
683 if (*fh_size
< sizeof(struct ntfid
)) {
684 *fh_size
= sizeof(struct ntfid
);
687 *fh_size
= sizeof(struct ntfid
);
689 ddprintf(("ntfs_fhtovp(): %s: %p\n", vp
->v_mount
->mnt_stat
.f_mntonname
,
694 memset(&ntfh
, 0, sizeof(ntfh
));
695 ntfh
.ntfid_len
= sizeof(struct ntfid
);
696 ntfh
.ntfid_ino
= ntp
->i_number
;
697 ntfh
.ntfid_attr
= fn
->f_attrtype
;
699 ntfh
.ntfid_gen
= ntp
->i_gen
;
701 memcpy(fhp
, &ntfh
, sizeof(ntfh
));
716 struct ntfsmount
*ntmp
;
720 enum vtype f_type
= VBAD
;
722 dprintf(("ntfs_vgetex: ino: %llu, attr: 0x%x:%s, lkf: 0x%lx, f:"
723 " 0x%lx\n", (unsigned long long)ino
, attrtype
,
724 attrname
? attrname
: "", (u_long
)lkflags
, (u_long
)flags
));
726 ntmp
= VFSTONTFS(mp
);
730 error
= ntfs_ntlookup(ntmp
, ino
, &ip
);
732 printf("ntfs_vget: ntfs_ntget failed\n");
736 /* It may be not initialized fully, so force load it */
737 if (!(flags
& VG_DONTLOADIN
) && !(ip
->i_flag
& IN_LOADED
)) {
738 error
= ntfs_loadntnode(ntmp
, ip
);
740 printf("ntfs_vget: CAN'T LOAD ATTRIBUTES FOR INO:"
741 " %llu\n", (unsigned long long)ip
->i_number
);
747 error
= ntfs_fget(ntmp
, ip
, attrtype
, attrname
, &fp
);
749 printf("ntfs_vget: ntfs_fget failed\n");
754 if (!(flags
& VG_DONTVALIDFN
) && !(fp
->f_flag
& FN_VALID
)) {
755 if ((ip
->i_frflag
& NTFS_FRFLAG_DIR
) &&
756 (fp
->f_attrtype
== NTFS_A_DATA
&& fp
->f_attrname
== NULL
)) {
758 } else if (flags
& VG_EXT
) {
760 fp
->f_size
= fp
->f_allocated
= 0;
764 error
= ntfs_filesize(ntmp
, fp
,
765 &fp
->f_size
, &fp
->f_allocated
);
772 fp
->f_flag
|= FN_VALID
;
776 * We may be calling vget() now. To avoid potential deadlock, we need
777 * to release ntnode lock, since due to locking order vnode
778 * lock has to be acquired first.
779 * ntfs_fget() bumped ntnode usecount, so ntnode won't be recycled
785 /* vget() returns error if the vnode has been recycled */
786 if (vget(FTOV(fp
), lkflags
) == 0) {
792 error
= getnewvnode(VT_NTFS
, ntmp
->ntm_mountp
, ntfs_vnodeop_p
, &vp
);
798 dprintf(("ntfs_vget: vnode: %p for ntnode: %llu\n", vp
,
799 (unsigned long long)ino
));
805 genfs_node_init(vp
, &ntfs_genfsops
);
807 if (ino
== NTFS_ROOTINO
)
808 vp
->v_vflag
|= VV_ROOT
;
810 if (lkflags
& LK_TYPE_MASK
) {
811 error
= vn_lock(vp
, lkflags
);
818 uvm_vnp_setsize(vp
, fp
->f_size
); /* XXX: mess, cf. ntfs_lookupfile() */
830 return ntfs_vgetex(mp
, ino
, NTFS_A_DATA
, NULL
,
831 LK_EXCLUSIVE
| LK_RETRY
, 0, vpp
);
834 extern const struct vnodeopv_desc ntfs_vnodeop_opv_desc
;
836 const struct vnodeopv_desc
* const ntfs_vnodeopv_descs
[] = {
837 &ntfs_vnodeop_opv_desc
,
841 struct vfsops ntfs_vfsops
= {
843 sizeof (struct ntfs_args
),
848 (void *)eopnotsupp
, /* vfs_quotactl */
858 (int (*)(struct mount
*, struct vnode
*, struct timespec
*)) eopnotsupp
,
860 (void *)eopnotsupp
, /* vfs_suspendctl */
861 genfs_renamelock_enter
,
862 genfs_renamelock_exit
,
870 ntfs_modcmd(modcmd_t cmd
, void *arg
)
875 case MODULE_CMD_INIT
:
876 error
= vfs_attach(&ntfs_vfsops
);
879 sysctl_createv(&ntfs_sysctl_log
, 0, NULL
, NULL
,
881 CTLTYPE_NODE
, "vfs", NULL
,
884 sysctl_createv(&ntfs_sysctl_log
, 0, NULL
, NULL
,
886 CTLTYPE_NODE
, "ntfs",
887 SYSCTL_DESCR("NTFS file system"),
889 CTL_VFS
, 20, CTL_EOL
);
891 * XXX the "20" above could be dynamic, thereby eliminating
892 * one more instance of the "number to vfs" mapping problem,
893 * but "20" is the order as taken from sys/mount.h
896 case MODULE_CMD_FINI
:
897 error
= vfs_detach(&ntfs_vfsops
);
900 sysctl_teardown(&ntfs_sysctl_log
);