Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/fs/smbfs/smbfs_node.c
39536 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2000-2001 Boris Popov
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
#include <sys/param.h>
29
#include <sys/systm.h>
30
#include <sys/fnv_hash.h>
31
#include <sys/kernel.h>
32
#include <sys/lock.h>
33
#include <sys/malloc.h>
34
#include <sys/mount.h>
35
#include <sys/proc.h>
36
#include <sys/queue.h>
37
#include <sys/stat.h>
38
#include <sys/sx.h>
39
#include <sys/sysctl.h>
40
#include <sys/time.h>
41
#include <sys/vnode.h>
42
43
#include <netsmb/smb.h>
44
#include <netsmb/smb_conn.h>
45
#include <netsmb/smb_subr.h>
46
47
#include <vm/vm.h>
48
#include <vm/vm_extern.h>
49
/*#include <vm/vm_page.h>
50
#include <vm/vm_object.h>*/
51
52
#include <fs/smbfs/smbfs.h>
53
#include <fs/smbfs/smbfs_node.h>
54
#include <fs/smbfs/smbfs_subr.h>
55
56
extern struct vop_vector smbfs_vnodeops; /* XXX -> .h file */
57
58
static MALLOC_DEFINE(M_SMBNODE, "smbufs_node", "SMBFS vnode private part");
59
static MALLOC_DEFINE(M_SMBNODENAME, "smbufs_nname", "SMBFS node name");
60
61
u_int32_t __inline
62
smbfs_hash(const u_char *name, int nmlen)
63
{
64
return (fnv_32_buf(name, nmlen, FNV1_32_INIT));
65
}
66
67
static char *
68
smbfs_name_alloc(const u_char *name, int nmlen)
69
{
70
u_char *cp;
71
72
nmlen++;
73
cp = malloc(nmlen, M_SMBNODENAME, M_WAITOK);
74
bcopy(name, cp, nmlen - 1);
75
cp[nmlen - 1] = 0;
76
return cp;
77
}
78
79
static void
80
smbfs_name_free(u_char *name)
81
{
82
83
free(name, M_SMBNODENAME);
84
}
85
86
static int __inline
87
smbfs_vnode_cmp(struct vnode *vp, void *_sc)
88
{
89
struct smbnode *np;
90
struct smbcmp *sc;
91
92
np = (struct smbnode *) vp->v_data;
93
sc = (struct smbcmp *) _sc;
94
if (np->n_parent != sc->n_parent || np->n_nmlen != sc->n_nmlen ||
95
bcmp(sc->n_name, np->n_name, sc->n_nmlen) != 0)
96
return 1;
97
return 0;
98
}
99
100
static int
101
smbfs_node_alloc(struct mount *mp, struct vnode *dvp, const char *dirnm,
102
int dirlen, const char *name, int nmlen, char sep,
103
struct smbfattr *fap, struct vnode **vpp)
104
{
105
struct vattr vattr;
106
struct thread *td = curthread; /* XXX */
107
struct smbmount *smp = VFSTOSMBFS(mp);
108
struct smbnode *np, *dnp;
109
struct vnode *vp, *vp2;
110
struct smbcmp sc;
111
char *p, *rpath;
112
int error, rplen;
113
114
sc.n_parent = dvp;
115
sc.n_nmlen = nmlen;
116
sc.n_name = name;
117
if (smp->sm_root != NULL && dvp == NULL) {
118
SMBERROR("do not allocate root vnode twice!\n");
119
return EINVAL;
120
}
121
if (nmlen == 2 && bcmp(name, "..", 2) == 0) {
122
if (dvp == NULL)
123
return EINVAL;
124
vp = VTOSMB(VTOSMB(dvp)->n_parent)->n_vnode;
125
error = vget(vp, LK_EXCLUSIVE);
126
if (error == 0)
127
*vpp = vp;
128
return error;
129
} else if (nmlen == 1 && name[0] == '.') {
130
SMBERROR("do not call me with dot!\n");
131
return EINVAL;
132
}
133
dnp = dvp ? VTOSMB(dvp) : NULL;
134
if (dnp == NULL && dvp != NULL) {
135
vn_printf(dvp, "smbfs_node_alloc: dead parent vnode ");
136
return EINVAL;
137
}
138
error = vfs_hash_get(mp, smbfs_hash(name, nmlen), LK_EXCLUSIVE, td,
139
vpp, smbfs_vnode_cmp, &sc);
140
if (error)
141
return (error);
142
if (*vpp) {
143
np = VTOSMB(*vpp);
144
/* Force cached attributes to be refreshed if stale. */
145
(void)VOP_GETATTR(*vpp, &vattr, td->td_ucred);
146
/*
147
* If the file type on the server is inconsistent with
148
* what it was when we created the vnode, kill the
149
* bogus vnode now and fall through to the code below
150
* to create a new one with the right type.
151
*/
152
if (((*vpp)->v_type == VDIR &&
153
(np->n_dosattr & SMB_FA_DIR) == 0) ||
154
((*vpp)->v_type == VREG &&
155
(np->n_dosattr & SMB_FA_DIR) != 0)) {
156
vgone(*vpp);
157
vput(*vpp);
158
}
159
else {
160
SMBVDEBUG("vnode taken from the hashtable\n");
161
return (0);
162
}
163
}
164
/*
165
* If we don't have node attributes, then it is an explicit lookup
166
* for an existing vnode.
167
*/
168
if (fap == NULL)
169
return ENOENT;
170
171
error = getnewvnode("smbfs", mp, &smbfs_vnodeops, vpp);
172
if (error)
173
return (error);
174
vp = *vpp;
175
np = malloc(sizeof *np, M_SMBNODE, M_WAITOK | M_ZERO);
176
rplen = dirlen;
177
if (sep != '\0')
178
rplen++;
179
rplen += nmlen;
180
rpath = malloc(rplen + 1, M_SMBNODENAME, M_WAITOK);
181
p = rpath;
182
bcopy(dirnm, p, dirlen);
183
p += dirlen;
184
if (sep != '\0')
185
*p++ = sep;
186
if (name != NULL) {
187
bcopy(name, p, nmlen);
188
p += nmlen;
189
}
190
*p = '\0';
191
MPASS(p == rpath + rplen);
192
lockmgr(vp->v_vnlock, LK_EXCLUSIVE, NULL);
193
/* Vnode initialization */
194
vp->v_type = fap->fa_attr & SMB_FA_DIR ? VDIR : VREG;
195
vp->v_data = np;
196
np->n_vnode = vp;
197
np->n_mount = VFSTOSMBFS(mp);
198
np->n_rpath = rpath;
199
np->n_rplen = rplen;
200
np->n_nmlen = nmlen;
201
np->n_name = smbfs_name_alloc(name, nmlen);
202
np->n_ino = fap->fa_ino;
203
if (dvp) {
204
ASSERT_VOP_LOCKED(dvp, "smbfs_node_alloc");
205
np->n_parent = dvp;
206
np->n_parentino = VTOSMB(dvp)->n_ino;
207
if (/*vp->v_type == VDIR &&*/ (dvp->v_vflag & VV_ROOT) == 0) {
208
vref(dvp);
209
np->n_flag |= NREFPARENT;
210
}
211
} else if (vp->v_type == VREG)
212
SMBERROR("new vnode '%s' born without parent ?\n", np->n_name);
213
error = insmntque(vp, mp);
214
if (error) {
215
free(np, M_SMBNODE);
216
return (error);
217
}
218
vn_set_state(vp, VSTATE_CONSTRUCTED);
219
error = vfs_hash_insert(vp, smbfs_hash(name, nmlen), LK_EXCLUSIVE,
220
td, &vp2, smbfs_vnode_cmp, &sc);
221
if (error)
222
return (error);
223
if (vp2 != NULL)
224
*vpp = vp2;
225
return (0);
226
}
227
228
int
229
smbfs_nget(struct mount *mp, struct vnode *dvp, const char *name, int nmlen,
230
struct smbfattr *fap, struct vnode **vpp)
231
{
232
struct smbnode *dnp;
233
struct vnode *vp;
234
int error, sep;
235
236
dnp = (dvp) ? VTOSMB(dvp) : NULL;
237
sep = 0;
238
if (dnp != NULL) {
239
sep = SMBFS_DNP_SEP(dnp);
240
error = smbfs_node_alloc(mp, dvp, dnp->n_rpath, dnp->n_rplen,
241
name, nmlen, sep, fap, &vp);
242
} else
243
error = smbfs_node_alloc(mp, NULL, "\\", 1, name, nmlen,
244
sep, fap, &vp);
245
if (error)
246
return error;
247
MPASS(vp != NULL);
248
if (fap)
249
smbfs_attr_cacheenter(vp, fap);
250
*vpp = vp;
251
return 0;
252
}
253
254
/*
255
* Free smbnode, and give vnode back to system
256
*/
257
int
258
smbfs_reclaim(struct vop_reclaim_args *ap)
259
{
260
struct vnode *vp = ap->a_vp;
261
struct vnode *dvp;
262
struct smbnode *np = VTOSMB(vp);
263
struct smbmount *smp = VTOSMBFS(vp);
264
265
SMBVDEBUG("%s,%d\n", np->n_name, vrefcnt(vp));
266
267
KASSERT((np->n_flag & NOPEN) == 0, ("file not closed before reclaim"));
268
269
dvp = (np->n_parent && (np->n_flag & NREFPARENT)) ?
270
np->n_parent : NULL;
271
272
/*
273
* Remove the vnode from its hash chain.
274
*/
275
vfs_hash_remove(vp);
276
if (np->n_name)
277
smbfs_name_free(np->n_name);
278
if (np->n_rpath)
279
free(np->n_rpath, M_SMBNODENAME);
280
free(np, M_SMBNODE);
281
vp->v_data = NULL;
282
if (dvp != NULL) {
283
vrele(dvp);
284
/*
285
* Indicate that we released something; see comment
286
* in smbfs_unmount().
287
*/
288
smp->sm_didrele = 1;
289
}
290
return 0;
291
}
292
293
int
294
smbfs_inactive(struct vop_inactive_args *ap)
295
{
296
struct thread *td = curthread;
297
struct ucred *cred = td->td_ucred;
298
struct vnode *vp = ap->a_vp;
299
struct smbnode *np = VTOSMB(vp);
300
struct smb_cred *scred;
301
struct vattr va;
302
303
SMBVDEBUG("%s: %d\n", VTOSMB(vp)->n_name, vrefcnt(vp));
304
if ((np->n_flag & NOPEN) != 0) {
305
scred = smbfs_malloc_scred();
306
smb_makescred(scred, td, cred);
307
smbfs_vinvalbuf(vp, td);
308
if (vp->v_type == VREG) {
309
VOP_GETATTR(vp, &va, cred);
310
smbfs_smb_close(np->n_mount->sm_share, np->n_fid,
311
&np->n_mtime, scred);
312
} else if (vp->v_type == VDIR) {
313
if (np->n_dirseq != NULL) {
314
smbfs_findclose(np->n_dirseq, scred);
315
np->n_dirseq = NULL;
316
}
317
}
318
np->n_flag &= ~NOPEN;
319
smbfs_attr_cacheremove(vp);
320
smbfs_free_scred(scred);
321
}
322
if (np->n_flag & NGONE)
323
vrecycle(vp);
324
return (0);
325
}
326
/*
327
* routines to maintain vnode attributes cache
328
* smbfs_attr_cacheenter: unpack np.i to vattr structure
329
*/
330
void
331
smbfs_attr_cacheenter(struct vnode *vp, struct smbfattr *fap)
332
{
333
struct smbnode *np = VTOSMB(vp);
334
335
if (vp->v_type == VREG) {
336
if (np->n_size != fap->fa_size) {
337
np->n_size = fap->fa_size;
338
vnode_pager_setsize(vp, np->n_size);
339
}
340
} else if (vp->v_type == VDIR) {
341
np->n_size = 16384; /* should be a better way ... */
342
} else
343
return;
344
np->n_mtime = fap->fa_mtime;
345
np->n_dosattr = fap->fa_attr;
346
np->n_attrage = time_second;
347
return;
348
}
349
350
int
351
smbfs_attr_cachelookup(struct vnode *vp, struct vattr *va)
352
{
353
struct smbnode *np = VTOSMB(vp);
354
struct smbmount *smp = VTOSMBFS(vp);
355
int diff;
356
357
diff = time_second - np->n_attrage;
358
if (diff > 2) /* XXX should be configurable */
359
return ENOENT;
360
va->va_type = vp->v_type; /* vnode type (for create) */
361
va->va_flags = 0; /* flags defined for file */
362
if (vp->v_type == VREG) {
363
va->va_mode = smp->sm_file_mode; /* files access mode and type */
364
if (np->n_dosattr & SMB_FA_RDONLY) {
365
va->va_mode &= ~(S_IWUSR|S_IWGRP|S_IWOTH);
366
va->va_flags |= UF_READONLY;
367
}
368
} else if (vp->v_type == VDIR) {
369
va->va_mode = smp->sm_dir_mode; /* files access mode and type */
370
} else
371
return EINVAL;
372
va->va_size = np->n_size;
373
va->va_nlink = 1; /* number of references to file */
374
va->va_uid = smp->sm_uid; /* owner user id */
375
va->va_gid = smp->sm_gid; /* owner group id */
376
va->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
377
va->va_fileid = np->n_ino; /* file id */
378
if (va->va_fileid == 0)
379
va->va_fileid = 2;
380
va->va_blocksize = SSTOVC(smp->sm_share)->vc_txmax;
381
va->va_mtime = np->n_mtime;
382
va->va_atime = va->va_ctime = va->va_mtime; /* time file changed */
383
va->va_gen = VNOVAL; /* generation number of file */
384
if (np->n_dosattr & SMB_FA_HIDDEN)
385
va->va_flags |= UF_HIDDEN;
386
if (np->n_dosattr & SMB_FA_SYSTEM)
387
va->va_flags |= UF_SYSTEM;
388
/*
389
* We don't set the archive bit for directories.
390
*/
391
if ((vp->v_type != VDIR) && (np->n_dosattr & SMB_FA_ARCHIVE))
392
va->va_flags |= UF_ARCHIVE;
393
va->va_rdev = NODEV; /* device the special file represents */
394
va->va_bytes = va->va_size; /* bytes of disk space held by file */
395
va->va_filerev = 0; /* file modification number */
396
va->va_vaflags = 0; /* operations flags */
397
return 0;
398
}
399
400