2 * Copyright (c) 1999, 2000 Boris Popov
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by Boris Popov.
16 * 4. Neither the name of the author nor the names of any co-contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * $FreeBSD: src/sys/nwfs/nwfs_vfsops.c,v 1.6.2.6 2001/10/25 19:18:54 dillon Exp $
33 * $DragonFly: src/sys/vfs/nwfs/nwfs_vfsops.c,v 1.30 2008/01/06 16:55:53 swildner Exp $
37 #error "NWFS requires NCP protocol"
40 #include <sys/param.h>
41 #include <sys/systm.h>
43 #include <sys/kernel.h>
44 #include <sys/sysctl.h>
45 #include <sys/vnode.h>
46 #include <sys/mount.h>
48 #include <sys/malloc.h>
51 #include <netproto/ncp/ncp.h>
52 #include <netproto/ncp/ncp_conn.h>
53 #include <netproto/ncp/ncp_subr.h>
54 #include <netproto/ncp/ncp_ncp.h>
55 #include <netproto/ncp/ncp_nls.h>
58 #include "nwfs_node.h"
59 #include "nwfs_subr.h"
61 extern struct vop_ops nwfs_vnode_vops
;
63 int nwfs_debuglevel
= 0;
65 static int nwfs_version
= NWFS_VERSION
;
67 SYSCTL_DECL(_vfs_nwfs
);
68 SYSCTL_NODE(_vfs
, OID_AUTO
, nwfs
, CTLFLAG_RW
, 0, "Netware file system");
69 SYSCTL_INT(_vfs_nwfs
, OID_AUTO
, version
, CTLFLAG_RD
, &nwfs_version
, 0, "");
70 SYSCTL_INT(_vfs_nwfs
, OID_AUTO
, debuglevel
, CTLFLAG_RW
, &nwfs_debuglevel
, 0, "");
72 static int nwfs_mount(struct mount
*, char *, caddr_t
, struct ucred
*);
73 static int nwfs_root(struct mount
*, struct vnode
**);
74 static int nwfs_statfs(struct mount
*, struct statfs
*, struct ucred
*);
75 static int nwfs_sync(struct mount
*, int);
76 static int nwfs_unmount(struct mount
*, int);
77 static int nwfs_init(struct vfsconf
*vfsp
);
78 static int nwfs_uninit(struct vfsconf
*vfsp
);
80 static struct vfsops nwfs_vfsops
= {
81 .vfs_mount
= nwfs_mount
,
82 .vfs_unmount
= nwfs_unmount
,
83 .vfs_root
= nwfs_root
,
84 .vfs_statfs
= nwfs_statfs
,
85 .vfs_sync
= nwfs_sync
,
86 .vfs_init
= nwfs_init
,
87 .vfs_uninit
= nwfs_uninit
91 VFS_SET(nwfs_vfsops
, nwfs
, VFCF_NETWORK
);
93 int nwfs_pbuf_freecnt
= -1; /* start out unlimited */
94 static int nwfsid
= 1;
97 nwfs_initnls(struct nwmount
*nmp
) {
100 #define COPY_TABLE(t,d) { \
102 error = copyin((t), pc, 256); \
106 (t) = pc; pc += 256; \
109 nmp
->m
.nls
.opt
|= NWHP_NLS
| NWHP_DOS
;
110 if ((nmp
->m
.flags
& NWFS_MOUNT_HAVE_NLS
) == 0) {
111 nmp
->m
.nls
.to_lower
= ncp_defnls
.to_lower
;
112 nmp
->m
.nls
.to_upper
= ncp_defnls
.to_upper
;
113 nmp
->m
.nls
.n2u
= ncp_defnls
.n2u
;
114 nmp
->m
.nls
.u2n
= ncp_defnls
.u2n
;
117 MALLOC(pe
, char *, 256 * 4, M_NWFSDATA
, M_WAITOK
);
120 COPY_TABLE(nmp
->m
.nls
.to_lower
, ncp_defnls
.to_lower
);
121 COPY_TABLE(nmp
->m
.nls
.to_upper
, ncp_defnls
.to_upper
);
122 COPY_TABLE(nmp
->m
.nls
.n2u
, ncp_defnls
.n2u
);
123 COPY_TABLE(nmp
->m
.nls
.u2n
, ncp_defnls
.u2n
);
126 kfree(pe
, M_NWFSDATA
);
132 * mp - path - addr in user space of mount point (ie /usr or whatever)
133 * data - addr in user space of mount params
136 nwfs_mount(struct mount
*mp
, char *path
, caddr_t data
, struct ucred
*cred
)
138 struct nwfs_args args
; /* will hold data from mount request */
140 struct nwmount
*nmp
= NULL
;
141 struct ncp_conn
*conn
= NULL
;
142 struct ncp_handle
*handle
= NULL
;
147 nwfs_printf("missing data argument\n");
150 if (mp
->mnt_flag
& MNT_UPDATE
) {
151 nwfs_printf("MNT_UPDATE not implemented");
154 error
= copyin(data
, (caddr_t
)&args
, sizeof(struct nwfs_args
));
157 if (args
.version
!= NWFS_VERSION
) {
158 nwfs_printf("mount version mismatch: kernel=%d, mount=%d\n",NWFS_VERSION
,args
.version
);
161 error
= ncp_conn_getbyref(args
.connRef
,curthread
,cred
,NCPM_EXECUTE
,&conn
);
163 nwfs_printf("invalid connection reference %d\n",args
.connRef
);
166 error
= ncp_conn_gethandle(conn
, NULL
, &handle
);
168 nwfs_printf("can't get connection handle\n");
171 ncp_conn_unlock(conn
,curthread
); /* we keep the ref */
172 mp
->mnt_stat
.f_iosize
= conn
->buffer_size
;
173 /* We must malloc our own mount info */
174 MALLOC(nmp
,struct nwmount
*,sizeof(struct nwmount
),M_NWFSDATA
, M_WAITOK
|M_USE_RESERVE
|M_ZERO
);
175 mp
->mnt_data
= (qaddr_t
)nmp
;
178 nmp
->n_id
= nwfsid
++;
180 nmp
->m
.file_mode
= (nmp
->m
.file_mode
&
181 (S_IRWXU
|S_IRWXG
|S_IRWXO
)) | S_IFREG
;
182 nmp
->m
.dir_mode
= (nmp
->m
.dir_mode
&
183 (S_IRWXU
|S_IRWXG
|S_IRWXO
)) | S_IFDIR
;
184 if ((error
= nwfs_initnls(nmp
)) != 0) goto bad
;
185 pc
= mp
->mnt_stat
.f_mntfromname
;
186 pe
= pc
+sizeof(mp
->mnt_stat
.f_mntfromname
);
189 pc
= index(strncpy(pc
, conn
->li
.server
, pe
-pc
-2),0);
192 pc
=index(strncpy(pc
, conn
->li
.user
, pe
-pc
-2),0);
195 strncpy(pc
, nmp
->m
.mounted_vol
, pe
-pc
-2);
198 /* protect against invalid mount points */
199 nmp
->m
.mount_point
[sizeof(nmp
->m
.mount_point
)-1] = '\0';
201 vfs_add_vnodeops(mp
, &nwfs_vnode_vops
, &mp
->mnt_vn_norm_ops
);
204 error
= nwfs_root(mp
, &vp
);
208 * Lose the lock but keep the ref.
211 NCPVODEBUG("rootvp.vrefcnt=%d\n",vp
->v_sysref
.refcnt
);
215 kfree(nmp
, M_NWFSDATA
);
217 ncp_conn_puthandle(handle
, NULL
, 0);
221 /* Unmount the filesystem described by mp. */
223 nwfs_unmount(struct mount
*mp
, int mntflags
)
225 struct nwmount
*nmp
= VFSTONWFS(mp
);
226 struct ncp_conn
*conn
;
229 NCPVODEBUG("nwfs_unmount: flags=%04x\n",mntflags
);
231 if (mntflags
& MNT_FORCE
)
233 /* There is 1 extra root vnode reference from nwfs_mount(). */
234 error
= vflush(mp
, 1, flags
);
237 conn
= NWFSTOCONN(nmp
);
238 ncp_conn_puthandle(nmp
->connh
,NULL
,0);
239 if (ncp_conn_lock(conn
, curthread
, proc0
.p_ucred
, NCPM_WRITE
| NCPM_EXECUTE
) == 0) {
240 if(ncp_disconnect(conn
))
241 ncp_conn_unlock(conn
, curthread
);
243 mp
->mnt_data
= (qaddr_t
)0;
244 if (nmp
->m
.flags
& NWFS_MOUNT_HAVE_NLS
)
245 kfree(nmp
->m
.nls
.to_lower
, M_NWFSDATA
);
246 kfree(nmp
, M_NWFSDATA
);
247 mp
->mnt_flag
&= ~MNT_LOCAL
;
251 /* Return locked vnode to root of a filesystem */
253 nwfs_root(struct mount
*mp
, struct vnode
**vpp
)
258 struct ncp_conn
*conn
;
259 struct nw_entry_info fattr
;
260 struct thread
*td
= curthread
; /* XXX */
265 KKASSERT(td
->td_proc
);
266 cred
= td
->td_proc
->p_ucred
;
269 conn
= NWFSTOCONN(nmp
);
271 *vpp
= NWTOV(nmp
->n_root
);
272 while (vget(*vpp
, LK_EXCLUSIVE
) != 0) /* XXX */
276 error
= ncp_lookup_volume(conn
, nmp
->m
.mounted_vol
, &vol
,
277 &nmp
->n_rootent
.f_id
, td
, cred
);
281 error
= ncp_get_namespaces(conn
, vol
, &nsf
, td
, cred
);
284 if (nsf
& NW_NSB_OS2
) {
285 NCPVODEBUG("volume %s has os2 namespace\n",nmp
->m
.mounted_vol
);
286 if ((nmp
->m
.flags
& NWFS_MOUNT_NO_OS2
) == 0) {
287 nmp
->name_space
= NW_NS_OS2
;
288 nmp
->m
.nls
.opt
&= ~NWHP_DOS
;
291 opt
= nmp
->m
.nls
.opt
;
292 nsf
= opt
& (NWHP_UPPER
| NWHP_LOWER
);
293 if (opt
& NWHP_DOS
) {
294 if (nsf
== (NWHP_UPPER
| NWHP_LOWER
)) {
295 nmp
->m
.nls
.opt
&= ~(NWHP_LOWER
| NWHP_UPPER
);
296 } else if (nsf
== 0) {
297 nmp
->m
.nls
.opt
|= NWHP_LOWER
;
300 if (nsf
== (NWHP_UPPER
| NWHP_LOWER
)) {
301 nmp
->m
.nls
.opt
&= ~(NWHP_LOWER
| NWHP_UPPER
);
304 if (nmp
->m
.root_path
[0]) {
305 nmp
->m
.root_path
[0]--;
306 error
= ncp_obtain_info(nmp
, nmp
->n_rootent
.f_id
,
307 -nmp
->m
.root_path
[0], nmp
->m
.root_path
, &fattr
, td
, cred
);
309 NCPFATAL("Invalid root path specified\n");
312 nmp
->n_rootent
.f_parent
= fattr
.dirEntNum
;
313 nmp
->m
.root_path
[0]++;
314 error
= ncp_obtain_info(nmp
, nmp
->n_rootent
.f_id
,
315 -nmp
->m
.root_path
[0], nmp
->m
.root_path
, &fattr
, td
, cred
);
317 NCPFATAL("Invalid root path specified\n");
320 nmp
->n_rootent
.f_id
= fattr
.dirEntNum
;
322 error
= ncp_obtain_info(nmp
, nmp
->n_rootent
.f_id
,
323 0, NULL
, &fattr
, td
, cred
);
325 NCPFATAL("Can't obtain volume info\n");
328 fattr
.nameLen
= strlen(strcpy(fattr
.entryName
, NWFS_ROOTVOL
));
329 nmp
->n_rootent
.f_parent
= nmp
->n_rootent
.f_id
;
331 error
= nwfs_nget(mp
, nmp
->n_rootent
, &fattr
, NULL
, &vp
);
336 if (nmp
->m
.root_path
[0] == 0)
337 np
->n_flag
|= NVOLUME
;
339 /* error = VOP_GETATTR(vp, &vattr);
342 NCPFATAL("Can't get root directory entry\n");
351 nwfs_init(struct vfsconf
*vfsp
)
360 error
= kernel_sysctl(name
, 2, &ncpu
, &olen
, NULL
, 0, &plen
);
361 if (error
== 0 && ncpu
> 1)
362 kprintf("warning: nwfs module compiled without SMP support.");
365 nwfs_pbuf_freecnt
= nswbuf
/ 2 + 1;
366 NCPVODEBUG("always happy to load!\n");
372 nwfs_uninit(struct vfsconf
*vfsp
)
376 NCPVODEBUG("unloaded\n");
384 nwfs_statfs(struct mount
*mp
, struct statfs
*sbp
, struct ucred
*cred
)
386 struct nwmount
*nmp
= VFSTONWFS(mp
);
387 int error
= 0, secsize
;
388 struct nwnode
*np
= nmp
->n_root
;
389 struct ncp_volume_info vi
;
391 if (np
== NULL
) return EINVAL
;
392 error
= ncp_get_volume_info_with_number(NWFSTOCONN(nmp
), nmp
->n_volume
,
393 &vi
, curthread
, cred
);
394 if (error
) return error
;
395 secsize
= 512; /* XXX how to get real value ??? */
396 sbp
->f_spare2
=0; /* placeholder */
397 /* fundamental file system block size */
398 sbp
->f_bsize
= vi
.sectors_per_block
*secsize
;
399 /* optimal transfer block size */
400 sbp
->f_iosize
= NWFSTOCONN(nmp
)->buffer_size
;
401 /* total data blocks in file system */
402 sbp
->f_blocks
= vi
.total_blocks
;
403 /* free blocks in fs */
404 sbp
->f_bfree
= vi
.free_blocks
+ vi
.purgeable_blocks
;
405 /* free blocks avail to non-superuser */
406 sbp
->f_bavail
= vi
.free_blocks
+vi
.purgeable_blocks
;
407 /* total file nodes in file system */
408 sbp
->f_files
= vi
.total_dir_entries
;
409 /* free file nodes in fs */
410 sbp
->f_ffree
= vi
.available_dir_entries
;
411 sbp
->f_flags
= 0; /* copy of mount exported flags */
412 if (sbp
!= &mp
->mnt_stat
) {
413 sbp
->f_fsid
= mp
->mnt_stat
.f_fsid
; /* file system id */
414 sbp
->f_owner
= mp
->mnt_stat
.f_owner
; /* user that mounted the filesystem */
415 sbp
->f_type
= mp
->mnt_vfc
->vfc_typenum
; /* type of filesystem */
416 bcopy(mp
->mnt_stat
.f_mntfromname
, sbp
->f_mntfromname
, MNAMELEN
);
418 strncpy(sbp
->f_fstypename
, mp
->mnt_vfc
->vfc_name
, MFSNAMELEN
);
423 * Flush out the buffer cache
427 nwfs_sync(struct mount
*mp
, int waitfor
)
430 int error
, allerror
= 0;
432 * Force stale buffer cache information to be flushed.
435 for (vp
= TAILQ_FIRST(&mp
->mnt_nvnodelist
);
437 vp
= TAILQ_NEXT(vp
, v_nmntvnodes
)) {
439 * If the vnode that we are about to sync is no longer
440 * associated with this mount point, start over.
442 if (vp
->v_mount
!= mp
)
444 if (vn_islocked(vp
) || RB_EMPTY(&vp
->v_rbdirty_tree
) ||
447 if (vget(vp
, LK_EXCLUSIVE
))
449 /* XXX vp may not be retained */
450 error
= VOP_FSYNC(vp
, waitfor
);