2 * Copyright (c) 2000-2001 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/fs/smbfs/smbfs_node.c,v 1.2.2.3 2003/01/17 08:20:26 tjr Exp $
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/kernel.h>
39 #include <sys/mount.h>
40 #include <sys/vnode.h>
41 #include <sys/malloc.h>
42 #include <sys/sysctl.h>
44 #include <vm/vm_extern.h>
45 /*#include <vm/vm_page.h>
46 #include <vm/vm_object.h>*/
47 #include <sys/queue.h>
49 #include <netproto/smb/smb.h>
50 #include <netproto/smb/smb_conn.h>
51 #include <netproto/smb/smb_subr.h>
54 #include "smbfs_node.h"
55 #include "smbfs_subr.h"
57 #define SMBFS_NOHASH(smp, hval) (&(smp)->sm_hash[(hval) & (smp)->sm_hashlen])
58 #define smbfs_hash_lock(smp, td) lockmgr(&smp->sm_hashlock, LK_EXCLUSIVE)
59 #define smbfs_hash_unlock(smp, td) lockmgr(&smp->sm_hashlock, LK_RELEASE)
62 MALLOC_DEFINE(M_SMBNODE
, "SMBFS node", "SMBFS vnode private part");
63 static MALLOC_DEFINE(M_SMBNODENAME
, "SMBFS nname", "SMBFS node name");
65 int smbfs_hashprint(struct mount
*mp
);
69 SYSCTL_DECL(_vfs_smbfs
);
71 SYSCTL_PROC(_vfs_smbfs
, OID_AUTO
, vnprint
, CTLFLAG_WR
|CTLTYPE_OPAQUE
,
72 NULL
, 0, smbfs_hashprint
, "S,vnlist", "vnode hash");
75 #define FNV_32_PRIME ((u_int32_t) 0x01000193UL)
76 #define FNV1_32_INIT ((u_int32_t) 33554467UL)
79 smbfs_hash(const u_char
*name
, int nmlen
)
83 for (v
= FNV1_32_INIT
; nmlen
; name
++, nmlen
--) {
85 v
^= (u_int32_t
)*name
;
91 smbfs_hashprint(struct mount
*mp
)
93 struct smbmount
*smp
= VFSTOSMBFS(mp
);
94 struct smbnode_hashhead
*nhpp
;
98 for(i
= 0; i
<= smp
->sm_hashlen
; i
++) {
99 nhpp
= &smp
->sm_hash
[i
];
100 LIST_FOREACH(np
, nhpp
, n_hash
)
101 vprint(NULL
, SMBTOV(np
));
107 smbfs_name_alloc(const u_char
*name
, int nmlen
)
112 #ifdef SMBFS_NAME_DEBUG
113 cp
= kmalloc(nmlen
+ 2 + sizeof(int), M_SMBNODENAME
, M_WAITOK
);
118 bcopy(name
, cp
, nmlen
- 1);
121 cp
= kmalloc(nmlen
, M_SMBNODENAME
, M_WAITOK
);
122 bcopy(name
, cp
, nmlen
- 1);
129 smbfs_name_free(u_char
*name
)
131 #ifdef SMBFS_NAME_DEBUG
138 kprintf("First byte of name entry '%s' corrupted\n", name
);
143 slen
= strlen(name
) + 1;
145 kprintf("Name length mismatch: was %d, now %d name '%s'\n",
149 if (name
[nmlen
] != 0xfe) {
150 kprintf("Last byte of name entry '%s' corrupted\n", name
);
153 kfree(cp
, M_SMBNODENAME
);
155 kfree(name
, M_SMBNODENAME
);
160 smbfs_node_alloc(struct mount
*mp
, struct vnode
*dvp
,
161 const char *name
, int nmlen
, struct smbfattr
*fap
,
164 struct smbmount
*smp
= VFSTOSMBFS(mp
);
165 struct smbnode_hashhead
*nhpp
;
166 struct smbnode
*np
, *np2
, *dnp
;
172 if (smp
->sm_root
!= NULL
&& dvp
== NULL
) {
173 SMBERROR("do not allocate root vnode twice!\n");
176 if (nmlen
== 2 && bcmp(name
, "..", 2) == 0) {
179 vp
= VTOSMB(VTOSMB(dvp
)->n_parent
)->n_vnode
;
180 error
= vget(vp
, LK_EXCLUSIVE
);
184 } else if (nmlen
== 1 && name
[0] == '.') {
185 SMBERROR("do not call me with dot!\n");
188 dnp
= dvp
? VTOSMB(dvp
) : NULL
;
189 if (dnp
== NULL
&& dvp
!= NULL
) {
190 vprint("smbfs_node_alloc: dead parent vnode", dvp
);
193 hashval
= smbfs_hash(name
, nmlen
);
195 smbfs_hash_lock(smp
, td
);
197 nhpp
= SMBFS_NOHASH(smp
, hashval
);
198 LIST_FOREACH(np
, nhpp
, n_hash
) {
199 if (np
->n_parent
!= dvp
||
200 np
->n_nmlen
!= nmlen
|| bcmp(name
, np
->n_name
, nmlen
) != 0)
203 smbfs_hash_unlock(smp
, td
);
204 if (vget(vp
, LK_EXCLUSIVE
) != 0)
207 * relookup after we blocked.
209 LIST_FOREACH(np2
, nhpp
, n_hash
) {
210 if (np2
->n_parent
== dvp
&& np2
->n_nmlen
== nmlen
&&
211 bcmp(name
, np2
->n_name
, nmlen
) == 0)
214 if (np2
!= np
|| SMBTOV(np2
) != vp
) {
221 smbfs_hash_unlock(smp
, td
);
223 * If we don't have node attributes, then it is an explicit lookup
224 * for an existing vnode.
229 np
= kmalloc(sizeof *np
, M_SMBNODE
, M_WAITOK
| M_ZERO
);
230 error
= getnewvnode(VT_SMBFS
, mp
, &vp
, VLKTIMEOUT
, LK_CANRECURSE
);
232 kfree(np
, M_SMBNODE
);
235 vp
->v_type
= fap
->fa_attr
& SMB_FA_DIR
? VDIR
: VREG
;
238 np
->n_mount
= VFSTOSMBFS(mp
);
240 np
->n_name
= smbfs_name_alloc(name
, nmlen
);
241 np
->n_ino
= fap
->fa_ino
;
245 if (/*vp->v_type == VDIR &&*/ (dvp
->v_flag
& VROOT
) == 0) {
247 np
->n_flag
|= NREFPARENT
;
249 } else if (vp
->v_type
== VREG
)
250 SMBERROR("new vnode '%s' born without parent ?\n", np
->n_name
);
252 smbfs_hash_lock(smp
, td
);
253 LIST_FOREACH(np2
, nhpp
, n_hash
) {
254 if (np2
->n_parent
!= dvp
||
255 np2
->n_nmlen
!= nmlen
|| bcmp(name
, np2
->n_name
, nmlen
) != 0)
258 /* smb_name_free(np->n_name);
259 FREE(np, M_SMBNODE);*/
262 LIST_INSERT_HEAD(nhpp
, np
, n_hash
);
263 smbfs_hash_unlock(smp
, td
);
265 * Return a locked and refd vnode
272 smbfs_nget(struct mount
*mp
, struct vnode
*dvp
, const char *name
, int nmlen
,
273 struct smbfattr
*fap
, struct vnode
**vpp
)
279 error
= smbfs_node_alloc(mp
, dvp
, name
, nmlen
, fap
, &vp
);
283 smbfs_attr_cacheenter(vp
, fap
);
289 * Free smbnode, and give vnode back to system
291 * smbfs_reclaim(struct vnode *a_vp)
294 smbfs_reclaim(struct vop_reclaim_args
*ap
)
296 struct vnode
*vp
= ap
->a_vp
;
298 struct smbnode
*np
= VTOSMB(vp
);
299 struct smbmount
*smp
= VTOSMBFS(vp
);
301 SMBVDEBUG("%s,%08x\n", np
->n_name
, vp
->v_refcnt
);
303 smbfs_hash_lock(smp
, td
);
305 dvp
= (np
->n_parent
&& (np
->n_flag
& NREFPARENT
)) ?
308 if (np
->n_hash
.le_prev
)
309 LIST_REMOVE(np
, n_hash
);
310 if (smp
->sm_root
== np
) {
311 SMBVDEBUG("root vnode\n");
315 smbfs_hash_unlock(smp
, td
);
317 smbfs_name_free(np
->n_name
);
318 kfree(np
, M_SMBNODE
);
321 * Indicate that we released something; see comment
322 * in smbfs_unmount().
331 * smbfs_inactive(struct vnode *a_vp)
334 smbfs_inactive(struct vop_inactive_args
*ap
)
337 struct vnode
*vp
= ap
->a_vp
;
338 struct smbnode
*np
= VTOSMB(vp
);
339 struct smb_cred scred
;
342 SMBVDEBUG("%s: %08x\n", VTOSMB(vp
)->n_name
, vp
->v_refcnt
);
343 if (np
->n_opencount
) {
344 error
= smbfs_vinvalbuf(vp
, V_SAVE
, 1);
345 cred
= np
->n_cached_cred
;
346 np
->n_cached_cred
= NULL
;
347 smb_makescred(&scred
, curthread
, cred
);
348 error
= smbfs_smb_close(np
->n_mount
->sm_share
, np
->n_fid
,
349 &np
->n_mtime
, &scred
);
356 * routines to maintain vnode attributes cache
357 * smbfs_attr_cacheenter: unpack np.i to vattr structure
360 smbfs_attr_cacheenter(struct vnode
*vp
, struct smbfattr
*fap
)
362 struct smbnode
*np
= VTOSMB(vp
);
364 if (vp
->v_type
== VREG
) {
365 if (np
->n_size
!= fap
->fa_size
) {
366 np
->n_size
= fap
->fa_size
;
367 vnode_pager_setsize(vp
, np
->n_size
);
369 } else if (vp
->v_type
== VDIR
) {
370 np
->n_size
= 16384; /* should be a better way ... */
373 np
->n_mtime
= fap
->fa_mtime
;
374 np
->n_dosattr
= fap
->fa_attr
;
375 np
->n_attrage
= time_uptime
;
380 smbfs_attr_cachelookup(struct vnode
*vp
, struct vattr
*va
)
382 struct smbnode
*np
= VTOSMB(vp
);
383 struct smbmount
*smp
= VTOSMBFS(vp
);
386 diff
= (int)(time_uptime
- np
->n_attrage
);
387 if (diff
> 2) /* XXX should be configurable */
389 va
->va_type
= vp
->v_type
; /* vnode type (for create) */
390 if (vp
->v_type
== VREG
) {
391 va
->va_mode
= smp
->sm_args
.file_mode
; /* files access mode and type */
392 } else if (vp
->v_type
== VDIR
) {
393 va
->va_mode
= smp
->sm_args
.dir_mode
; /* files access mode and type */
396 va
->va_size
= np
->n_size
;
397 va
->va_nlink
= 1; /* number of references to file */
398 va
->va_uid
= smp
->sm_args
.uid
; /* owner user id */
399 va
->va_gid
= smp
->sm_args
.gid
; /* owner group id */
400 va
->va_fsid
= vp
->v_mount
->mnt_stat
.f_fsid
.val
[0];
401 va
->va_fileid
= np
->n_ino
; /* file id */
402 if (va
->va_fileid
== 0)
404 va
->va_blocksize
= SSTOVC(smp
->sm_share
)->vc_txmax
;
405 va
->va_mtime
= np
->n_mtime
;
406 va
->va_atime
= va
->va_ctime
= va
->va_mtime
; /* time file changed */
407 va
->va_gen
= VNOVAL
; /* generation number of file */
408 va
->va_flags
= 0; /* flags defined for file */
409 va
->va_rmajor
= VNOVAL
; /* device the special file represents */
410 va
->va_rminor
= VNOVAL
;
411 va
->va_bytes
= va
->va_size
; /* bytes of disk space held by file */
412 va
->va_filerev
= 0; /* file modification number */
413 va
->va_vaflags
= 0; /* operations flags */
418 smbfs_attr_cacherename(struct vnode
*vp
, const char *name
, int nmlen
)
420 struct smbnode_hashhead
*nhpp
;
421 struct smbmount
*smp
= VTOSMBFS(vp
);
425 hashval
= smbfs_hash(name
, nmlen
);
427 smbfs_hash_lock(smp
, td
);
430 if (np
->n_hash
.le_prev
)
431 LIST_REMOVE(np
, n_hash
);
433 smbfs_name_free(np
->n_name
);
435 np
->n_name
= smbfs_name_alloc(name
, nmlen
);
437 nhpp
= SMBFS_NOHASH(smp
, hashval
);
438 LIST_INSERT_HEAD(nhpp
, np
, n_hash
);
440 smbfs_hash_unlock(smp
, td
);