*** NO COMMENTS ***
1 /*
2 * Copyright (c) 2000-2001 Boris Popov
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
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.
19 *
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
30 * SUCH DAMAGE.
31 *
32 * $Id: smbfs_vnops.c,v 1.128.36.1 2005/05/27 02:35:28 lindak Exp $
33 */
34
35 /*
36 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
37 */
38
39 #include <sys/systm.h>
40 #include <sys/cred.h>
41 #include <sys/vnode.h>
42 #include <sys/vfs.h>
43 #include <sys/filio.h>
44 #include <sys/uio.h>
45 #include <sys/dirent.h>
46 #include <sys/errno.h>
47 #include <sys/sunddi.h>
48 #include <sys/sysmacros.h>
49 #include <sys/kmem.h>
50 #include <sys/cmn_err.h>
51 #include <sys/vfs_opreg.h>
52 #include <sys/policy.h>
53
54 #include <netsmb/smb_osdep.h>
55 #include <netsmb/smb.h>
56 #include <netsmb/smb_conn.h>
57 #include <netsmb/smb_subr.h>
58
59 #include <smbfs/smbfs.h>
60 #include <smbfs/smbfs_node.h>
61 #include <smbfs/smbfs_subr.h>
62
63 #include <sys/fs/smbfs_ioctl.h>
64 #include <fs/fs_subr.h>
65
66 /*
67 * We assign directory offsets like the NFS client, where the
68 * offset increments by _one_ after each directory entry.
69 * Further, the entries "." and ".." are always at offsets
70 * zero and one (respectively) and the "real" entries from
71 * the server appear at offsets starting with two. This
72 * macro is used to initialize the n_dirofs field after
73 * setting n_dirseq with a _findopen call.
74 */
75 #define FIRST_DIROFS 2
76
77 /*
78 * These characters are illegal in NTFS file names.
79 * ref: http://support.microsoft.com/kb/147438
80 *
81 * Careful! The check in the XATTR case skips the
82 * first character to allow colon in XATTR names.
83 */
84 static const char illegal_chars[] = {
85 ':', /* colon - keep this first! */
86 '\\', /* back slash */
87 '/', /* slash */
88 '*', /* asterisk */
89 '?', /* question mark */
90 '"', /* double quote */
91 '<', /* less than sign */
92 '>', /* greater than sign */
93 '|', /* vertical bar */
94 0
95 };
96
97 /*
98 * Turning this on causes nodes to be created in the cache
99 * during directory listings, normally avoiding a second
100 * OtW attribute fetch just after a readdir.
101 */
102 int smbfs_fastlookup = 1;
103
104 /* local static function defines */
105
106 static int smbfslookup_cache(vnode_t *, char *, int, vnode_t **,
107 cred_t *);
108 static int smbfslookup(vnode_t *dvp, char *nm, vnode_t **vpp, cred_t *cr,
109 int cache_ok, caller_context_t *);
110 static int smbfsrename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm,
111 cred_t *cr, caller_context_t *);
112 static int smbfssetattr(vnode_t *, struct vattr *, int, cred_t *);
113 static int smbfs_accessx(void *, int, cred_t *);
114 static int smbfs_readvdir(vnode_t *vp, uio_t *uio, cred_t *cr, int *eofp,
115 caller_context_t *);
116 static void smbfs_rele_fid(smbnode_t *, struct smb_cred *);
117
118 /*
119 * These are the vnode ops routines which implement the vnode interface to
120 * the networked file system. These routines just take their parameters,
121 * make them look networkish by putting the right info into interface structs,
122 * and then calling the appropriate remote routine(s) to do the work.
123 *
124 * Note on directory name lookup cacheing: If we detect a stale fhandle,
125 * we purge the directory cache relative to that vnode. This way, the
126 * user won't get burned by the cache repeatedly. See <smbfs/smbnode.h> for
127 * more details on smbnode locking.
128 */
129
130 static int smbfs_open(vnode_t **, int, cred_t *, caller_context_t *);
131 static int smbfs_close(vnode_t *, int, int, offset_t, cred_t *,
132 caller_context_t *);
133 static int smbfs_read(vnode_t *, struct uio *, int, cred_t *,
134 caller_context_t *);
135 static int smbfs_write(vnode_t *, struct uio *, int, cred_t *,
136 caller_context_t *);
137 static int smbfs_ioctl(vnode_t *, int, intptr_t, int, cred_t *, int *,
138 caller_context_t *);
139 static int smbfs_getattr(vnode_t *, struct vattr *, int, cred_t *,
140 caller_context_t *);
141 static int smbfs_setattr(vnode_t *, struct vattr *, int, cred_t *,
142 caller_context_t *);
143 static int smbfs_access(vnode_t *, int, int, cred_t *, caller_context_t *);
144 static int smbfs_fsync(vnode_t *, int, cred_t *, caller_context_t *);
145 static void smbfs_inactive(vnode_t *, cred_t *, caller_context_t *);
146 static int smbfs_lookup(vnode_t *, char *, vnode_t **, struct pathname *,
147 int, vnode_t *, cred_t *, caller_context_t *,
148 int *, pathname_t *);
149 static int smbfs_create(vnode_t *, char *, struct vattr *, enum vcexcl,
150 int, vnode_t **, cred_t *, int, caller_context_t *,
151 vsecattr_t *);
152 static int smbfs_remove(vnode_t *, char *, cred_t *, caller_context_t *,
153 int);
154 static int smbfs_rename(vnode_t *, char *, vnode_t *, char *, cred_t *,
155 caller_context_t *, int);
156 static int smbfs_mkdir(vnode_t *, char *, struct vattr *, vnode_t **,
157 cred_t *, caller_context_t *, int, vsecattr_t *);
158 static int smbfs_rmdir(vnode_t *, char *, vnode_t *, cred_t *,
159 caller_context_t *, int);
160 static int smbfs_readdir(vnode_t *, struct uio *, cred_t *, int *,
161 caller_context_t *, int);
162 static int smbfs_rwlock(vnode_t *, int, caller_context_t *);
163 static void smbfs_rwunlock(vnode_t *, int, caller_context_t *);
164 static int smbfs_seek(vnode_t *, offset_t, offset_t *, caller_context_t *);
165 static int smbfs_frlock(vnode_t *, int, struct flock64 *, int, offset_t,
166 struct flk_callback *, cred_t *, caller_context_t *);
167 static int smbfs_space(vnode_t *, int, struct flock64 *, int, offset_t,
168 cred_t *, caller_context_t *);
169 static int smbfs_pathconf(vnode_t *, int, ulong_t *, cred_t *,
170 caller_context_t *);
171 static int smbfs_setsecattr(vnode_t *, vsecattr_t *, int, cred_t *,
172 caller_context_t *);
173 static int smbfs_getsecattr(vnode_t *, vsecattr_t *, int, cred_t *,
174 caller_context_t *);
175 static int smbfs_shrlock(vnode_t *, int, struct shrlock *, int, cred_t *,
176 caller_context_t *);
177
178 static int smbfs_map(vnode_t *vp, offset_t off, struct as *as, caddr_t *addrp,
179 size_t len, uchar_t prot, uchar_t maxprot, uint_t flags, cred_t *cr,
180 caller_context_t *ct);
181
182 static int smbfs_addmap(vnode_t *vp, offset_t off, struct as *as, caddr_t addr,
183 size_t len, uchar_t prot, uchar_t maxprot, uint_t flags, cred_t *cr,
184 caller_context_t *ct);
185
186 static int smbfs_delmap(vnode_t *vp, offset_t off, struct as *as, caddr_t addr,
187 size_t len, uint_t prot, uint_t maxprot, uint_t flags, cred_t *cr,
188 caller_context_t *ct);
189
190 static int smbfs_putpage(vnode_t *vp, offset_t off, size_t len, int flags,
191 cred_t *cr, caller_context_t *ct);
192
193 static int smbfs_putapage(vnode_t *vp, page_t *pp, u_offset_t *offp, size_t *lenp,
194 int flags, cred_t *cr);
195
196 static int up_mapin(uio_t *uiop, page_t *pp);
197
198 static int up_mapout(uio_t *uiop, page_t *pp);
199
200 static int smbfs_getpage(vnode_t *vp, offset_t off, size_t len, uint_t *protp, page_t *pl[], size_t plsz, struct seg *seg, caddr_t addr,
201 enum seg_rw rw, cred_t *cr, caller_context_t *ct);
202
203 static int smbfs_getapage(vnode_t *vp, u_offset_t off, size_t len,
204 uint_t *protp, page_t *pl[], size_t plsz, struct seg *seg, caddr_t addr, enum seg_rw rw, cred_t *cr);
205
206
207
208 /* Dummy function to use until correct function is ported in */
209 int noop_vnodeop() {
210 return (0);
211 }
212
213 struct vnodeops *smbfs_vnodeops = NULL;
214
215 /*
216 * Most unimplemented ops will return ENOSYS because of fs_nosys().
217 * The only ops where that won't work are ACCESS (due to open(2)
218 * failures) and ... (anything else left?)
219 */
220 const fs_operation_def_t smbfs_vnodeops_template[] = {
221 { VOPNAME_OPEN, { .vop_open = smbfs_open } },
222 { VOPNAME_CLOSE, { .vop_close = smbfs_close } },
223 { VOPNAME_READ, { .vop_read = smbfs_read } },
224 { VOPNAME_WRITE, { .vop_write = smbfs_write } },
225 { VOPNAME_IOCTL, { .vop_ioctl = smbfs_ioctl } },
226 { VOPNAME_GETATTR, { .vop_getattr = smbfs_getattr } },
227 { VOPNAME_SETATTR, { .vop_setattr = smbfs_setattr } },
228 { VOPNAME_ACCESS, { .vop_access = smbfs_access } },
229 { VOPNAME_LOOKUP, { .vop_lookup = smbfs_lookup } },
230 { VOPNAME_CREATE, { .vop_create = smbfs_create } },
231 { VOPNAME_REMOVE, { .vop_remove = smbfs_remove } },
232 { VOPNAME_LINK, { .error = fs_nosys } }, /* smbfs_link, */
233 { VOPNAME_RENAME, { .vop_rename = smbfs_rename } },
234 { VOPNAME_MKDIR, { .vop_mkdir = smbfs_mkdir } },
235 { VOPNAME_RMDIR, { .vop_rmdir = smbfs_rmdir } },
236 { VOPNAME_READDIR, { .vop_readdir = smbfs_readdir } },
237 { VOPNAME_SYMLINK, { .error = fs_nosys } }, /* smbfs_symlink, */
238 { VOPNAME_READLINK, { .error = fs_nosys } }, /* smbfs_readlink, */
239 { VOPNAME_FSYNC, { .vop_fsync = smbfs_fsync } },
240 { VOPNAME_INACTIVE, { .vop_inactive = smbfs_inactive } },
241 { VOPNAME_FID, { .error = fs_nosys } }, /* smbfs_fid, */
242 { VOPNAME_RWLOCK, { .vop_rwlock = smbfs_rwlock } },
243 { VOPNAME_RWUNLOCK, { .vop_rwunlock = smbfs_rwunlock } },
244 { VOPNAME_SEEK, { .vop_seek = smbfs_seek } },
245 { VOPNAME_FRLOCK, { .vop_frlock = smbfs_frlock } },
246 { VOPNAME_SPACE, { .vop_space = smbfs_space } },
247 { VOPNAME_REALVP, { .error = fs_nosys } }, /* smbfs_realvp, */
248 { VOPNAME_GETPAGE, { .vop_getpage = smbfs_getpage } }, /* smbfs_getpage, */
249 { VOPNAME_PUTPAGE, { .vop_putpage = smbfs_putpage } }, /* smbfs_putpage, */
250 { VOPNAME_MAP, { .vop_map = smbfs_map } }, /* smbfs_map, */
251 { VOPNAME_ADDMAP, { .vop_addmap = smbfs_addmap } }, /* smbfs_addmap, */
252 { VOPNAME_DELMAP, { .vop_delmap = smbfs_delmap } }, /* smbfs_delmap, */
253 { VOPNAME_DUMP, { .error = fs_nosys } }, /* smbfs_dump, */
254 { VOPNAME_PATHCONF, { .vop_pathconf = smbfs_pathconf } },
255 { VOPNAME_PAGEIO, { .error = fs_nosys } }, /* smbfs_pageio, */
256 { VOPNAME_SETSECATTR, { .vop_setsecattr = smbfs_setsecattr } },
257 { VOPNAME_GETSECATTR, { .vop_getsecattr = smbfs_getsecattr } },
258 { VOPNAME_SHRLOCK, { .vop_shrlock = smbfs_shrlock } },
259 { NULL, NULL }
260 };
261
262 /*
263 * XXX
264 * When new and relevant functionality is enabled, we should be
265 * calling vfs_set_feature() to inform callers that pieces of
266 * functionality are available, per PSARC 2007/227.
267 */
268 /* ARGSUSED */
269 static int
270 smbfs_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
271 {
272 smbnode_t *np;
273 vnode_t *vp;
274 smbfattr_t fa;
275 u_int32_t rights, rightsrcvd;
276 u_int16_t fid, oldfid;
277 int oldgenid;
278 struct smb_cred scred;
279 smbmntinfo_t *smi;
280 smb_share_t *ssp;
281 cred_t *oldcr;
282 int tmperror;
283 int error = 0;
284
285 vp = *vpp;
286 np = VTOSMB(vp);
287 smi = VTOSMI(vp);
288 ssp = smi->smi_share;
289
290 if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
291 return (EIO);
292
293 if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
294 return (EIO);
295
296 if (vp->v_type != VREG && vp->v_type != VDIR) { /* XXX VLNK? */
297 SMBVDEBUG("open eacces vtype=%d\n", vp->v_type);
298 return (EACCES);
299 }
300
301 /*
302 * Get exclusive access to n_fid and related stuff.
303 * No returns after this until out.
304 */
305 if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, SMBINTR(vp)))
306 return (EINTR);
307 smb_credinit(&scred, cr);
308
309 /*
310 * Keep track of the vnode type at first open.
311 * It may change later, and we need close to do
312 * cleanup for the type we opened. Also deny
313 * open of new types until old type is closed.
314 * XXX: Per-open instance nodes whould help.
315 */
316 if (np->n_ovtype == VNON) {
317 ASSERT(np->n_dirrefs == 0);
318 ASSERT(np->n_fidrefs == 0);
319 } else if (np->n_ovtype != vp->v_type) {
320 SMBVDEBUG("open n_ovtype=%d v_type=%d\n",
321 np->n_ovtype, vp->v_type);
322 error = EACCES;
323 goto out;
324 }
325
326 /*
327 * Directory open. See smbfs_readvdir()
328 */
329 if (vp->v_type == VDIR) {
330 if (np->n_dirseq == NULL) {
331 /* first open */
332 error = smbfs_smb_findopen(np, "*", 1,
333 SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR,
334 &scred, &np->n_dirseq);
335 if (error != 0)
336 goto out;
337 }
338 np->n_dirofs = FIRST_DIROFS;
339 np->n_dirrefs++;
340 goto have_fid;
341 }
342
343 /*
344 * If caller specified O_TRUNC/FTRUNC, then be sure to set
345 * FWRITE (to drive successful setattr(size=0) after open)
346 */
347 if (flag & FTRUNC)
348 flag |= FWRITE;
349
350 /*
351 * If we already have it open, and the FID is still valid,
352 * check whether the rights are sufficient for FID reuse.
353 */
354 if (np->n_fidrefs > 0 &&
355 np->n_vcgenid == ssp->ss_vcgenid) {
356 int upgrade = 0;
357
358 if ((flag & FWRITE) &&
359 !(np->n_rights & SA_RIGHT_FILE_WRITE_DATA))
360 upgrade = 1;
361 if ((flag & FREAD) &&
362 !(np->n_rights & SA_RIGHT_FILE_READ_DATA))
363 upgrade = 1;
364 if (!upgrade) {
365 /*
366 * the existing open is good enough
367 */
368 np->n_fidrefs++;
369 goto have_fid;
370 }
371 }
372 rights = np->n_fidrefs ? np->n_rights : 0;
373
374 /*
375 * we always ask for READ_CONTROL so we can always get the
376 * owner/group IDs to satisfy a stat. Ditto attributes.
377 */
378 rights |= (STD_RIGHT_READ_CONTROL_ACCESS |
379 SA_RIGHT_FILE_READ_ATTRIBUTES);
380 if ((flag & FREAD))
381 rights |= SA_RIGHT_FILE_READ_DATA;
382 if ((flag & FWRITE))
383 rights |= SA_RIGHT_FILE_WRITE_DATA |
384 SA_RIGHT_FILE_APPEND_DATA |
385 SA_RIGHT_FILE_WRITE_ATTRIBUTES;
386
387 bzero(&fa, sizeof (fa));
388 error = smbfs_smb_open(np,
389 NULL, 0, 0, /* name nmlen xattr */
390 rights, &scred,
391 &fid, &rightsrcvd, &fa);
392 if (error)
393 goto out;
394 smbfs_attrcache_fa(vp, &fa);
395
396 /*
397 * We have a new FID and access rights.
398 */
399 oldfid = np->n_fid;
400 oldgenid = np->n_vcgenid;
401 np->n_fid = fid;
402 np->n_vcgenid = ssp->ss_vcgenid;
403 np->n_rights = rightsrcvd;
404 np->n_fidrefs++;
405 if (np->n_fidrefs > 1 &&
406 oldgenid == ssp->ss_vcgenid) {
407 /*
408 * We already had it open (presumably because
409 * it was open with insufficient rights.)
410 * Close old wire-open.
411 */
412 tmperror = smbfs_smb_close(ssp,
413 oldfid, NULL, &scred);
414 if (tmperror)
415 SMBVDEBUG("error %d closing %s\n",
416 tmperror, np->n_rpath);
417 }
418
419 /*
420 * This thread did the open.
421 * Save our credentials too.
422 */
423 mutex_enter(&np->r_statelock);
424 oldcr = np->r_cred;
425 np->r_cred = cr;
426 crhold(cr);
427 if (oldcr)
428 crfree(oldcr);
429 mutex_exit(&np->r_statelock);
430
431 have_fid:
432 /*
433 * Keep track of the vnode type at first open.
434 * (see comments above)
435 */
436 if (np->n_ovtype == VNON)
437 np->n_ovtype = vp->v_type;
438
439 out:
440 smb_credrele(&scred);
441 smbfs_rw_exit(&np->r_lkserlock);
442 return (error);
443 }
444
445 /*ARGSUSED*/
446 static int
447 smbfs_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr,
448 caller_context_t *ct)
449 {
450 smbnode_t *np;
451 smbmntinfo_t *smi;
452 struct smb_cred scred;
453
454 np = VTOSMB(vp);
455 smi = VTOSMI(vp);
456
457 /*
458 * Don't "bail out" for VFS_UNMOUNTED here,
459 * as we want to do cleanup, etc.
460 */
461
462 /*
463 * zone_enter(2) prevents processes from changing zones with SMBFS files
464 * open; if we happen to get here from the wrong zone we can't do
465 * anything over the wire.
466 */
467 if (smi->smi_zone_ref.zref_zone != curproc->p_zone) {
468 /*
469 * We could attempt to clean up locks, except we're sure
470 * that the current process didn't acquire any locks on
471 * the file: any attempt to lock a file belong to another zone
472 * will fail, and one can't lock an SMBFS file and then change
473 * zones, as that fails too.
474 *
475 * Returning an error here is the sane thing to do. A
476 * subsequent call to VN_RELE() which translates to a
477 * smbfs_inactive() will clean up state: if the zone of the
478 * vnode's origin is still alive and kicking, an async worker
479 * thread will handle the request (from the correct zone), and
480 * everything (minus the final smbfs_getattr_otw() call) should
481 * be OK. If the zone is going away smbfs_async_inactive() will
482 * throw away cached pages inline.
483 */
484 return (EIO);
485 }
486
487 /*
488 * If we are using local locking for this filesystem, then
489 * release all of the SYSV style record locks. Otherwise,
490 * we are doing network locking and we need to release all
491 * of the network locks. All of the locks held by this
492 * process on this file are released no matter what the
493 * incoming reference count is.
494 */
495 if (smi->smi_flags & SMI_LLOCK) {
496 pid_t pid = ddi_get_pid();
497 cleanlocks(vp, pid, 0);
498 cleanshares(vp, pid);
499 }
500
501 /*
502 * This (passed in) count is the ref. count from the
503 * user's file_t before the closef call (fio.c).
504 * We only care when the reference goes away.
505 */
506 if (count > 1)
507 return (0);
508
509 /*
510 * Decrement the reference count for the FID
511 * and possibly do the OtW close.
512 *
513 * Exclusive lock for modifying n_fid stuff.
514 * Don't want this one ever interruptible.
515 */
516 (void) smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, 0);
517 smb_credinit(&scred, cr);
518
519 smbfs_rele_fid(np, &scred);
520
521 smb_credrele(&scred);
522 smbfs_rw_exit(&np->r_lkserlock);
523
524 return (0);
525 }
526
527 /*
528 * Helper for smbfs_close. Decrement the reference count
529 * for an SMB-level file or directory ID, and when the last
530 * reference for the fid goes away, do the OtW close.
531 * Also called in smbfs_inactive (defensive cleanup).
532 */
533 static void
534 smbfs_rele_fid(smbnode_t *np, struct smb_cred *scred)
535 {
536 smb_share_t *ssp;
537 cred_t *oldcr;
538 struct smbfs_fctx *fctx;
539 int error;
540 uint16_t ofid;
541
542 ssp = np->n_mount->smi_share;
543 error = 0;
544
545 /* Make sure we serialize for n_dirseq use. */
546 ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_WRITER));
547
548 /*
549 * Note that vp->v_type may change if a remote node
550 * is deleted and recreated as a different type, and
551 * our getattr may change v_type accordingly.
552 * Now use n_ovtype to keep track of the v_type
553 * we had during open (see comments above).
554 */
555 switch (np->n_ovtype) {
556 case VDIR:
557 ASSERT(np->n_dirrefs > 0);
558 if (--np->n_dirrefs)
559 return;
560 if ((fctx = np->n_dirseq) != NULL) {
561 np->n_dirseq = NULL;
562 np->n_dirofs = 0;
563 error = smbfs_smb_findclose(fctx, scred);
564 }
565 break;
566
567 case VREG:
568 ASSERT(np->n_fidrefs > 0);
569 if (--np->n_fidrefs)
570 return;
571 if ((ofid = np->n_fid) != SMB_FID_UNUSED) {
572 np->n_fid = SMB_FID_UNUSED;
573 /* After reconnect, n_fid is invalid */
574 if (np->n_vcgenid == ssp->ss_vcgenid) {
575 error = smbfs_smb_close(
576 ssp, ofid, NULL, scred);
577 }
578 }
579 break;
580
581 default:
582 SMBVDEBUG("bad n_ovtype %d\n", np->n_ovtype);
583 break;
584 }
585 if (error) {
586 SMBVDEBUG("error %d closing %s\n",
587 error, np->n_rpath);
588 }
589
590 /* Allow next open to use any v_type. */
591 np->n_ovtype = VNON;
592
593 /*
594 * Other "last close" stuff.
595 */
596 mutex_enter(&np->r_statelock);
597 if (np->n_flag & NATTRCHANGED)
598 smbfs_attrcache_rm_locked(np);
599 oldcr = np->r_cred;
600 np->r_cred = NULL;
601 mutex_exit(&np->r_statelock);
602 if (oldcr != NULL)
603 crfree(oldcr);
604 }
605
606 /* ARGSUSED */
607 static int
608 smbfs_read(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr,
609 caller_context_t *ct)
610 {
611 struct smb_cred scred;
612 struct vattr va;
613 smbnode_t *np;
614 smbmntinfo_t *smi;
615 smb_share_t *ssp;
616 offset_t endoff;
617 ssize_t past_eof;
618 int error;
619
620 np = VTOSMB(vp);
621 smi = VTOSMI(vp);
622 ssp = smi->smi_share;
623
624 if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
625 return (EIO);
626
627 if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
628 return (EIO);
629
630 ASSERT(smbfs_rw_lock_held(&np->r_rwlock, RW_READER));
631
632 if (vp->v_type != VREG)
633 return (EISDIR);
634
635 if (uiop->uio_resid == 0)
636 return (0);
637
638 /*
639 * Like NFS3, just check for 63-bit overflow.
640 * Our SMB layer takes care to return EFBIG
641 * when it has to fallback to a 32-bit call.
642 */
643 endoff = uiop->uio_loffset + uiop->uio_resid;
644 if (uiop->uio_loffset < 0 || endoff < 0)
645 return (EINVAL);
646
647 /* get vnode attributes from server */
648 va.va_mask = AT_SIZE | AT_MTIME;
649 if (error = smbfsgetattr(vp, &va, cr))
650 return (error);
651
652 /* Update mtime with mtime from server here? */
653
654 /* if offset is beyond EOF, read nothing */
655 if (uiop->uio_loffset >= va.va_size)
656 return (0);
657
658 /*
659 * Limit the read to the remaining file size.
660 * Do this by temporarily reducing uio_resid
661 * by the amount the lies beyoned the EOF.
662 */
663 if (endoff > va.va_size) {
664 past_eof = (ssize_t)(endoff - va.va_size);
665 uiop->uio_resid -= past_eof;
666 } else
667 past_eof = 0;
668
669 /* Shared lock for n_fid use in smb_rwuio */
670 if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
671 return (EINTR);
672 smb_credinit(&scred, cr);
673
674 /* After reconnect, n_fid is invalid */
675 if (np->n_vcgenid != ssp->ss_vcgenid)
676 error = ESTALE;
677 else
678 error = smb_rwuio(ssp, np->n_fid, UIO_READ,
679 uiop, &scred, smb_timo_read);
680
681 smb_credrele(&scred);
682 smbfs_rw_exit(&np->r_lkserlock);
683
684 /* undo adjustment of resid */
685 uiop->uio_resid += past_eof;
686
687 return (error);
688 }
689
690
691 /* ARGSUSED */
692 static int
693 smbfs_write(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr,
694 caller_context_t *ct)
695 {
696 struct smb_cred scred;
697 struct vattr va;
698 smbnode_t *np;
699 smbmntinfo_t *smi;
700 smb_share_t *ssp;
701 offset_t endoff, limit;
702 ssize_t past_limit;
703 int error, timo;
704
705 np = VTOSMB(vp);
706 smi = VTOSMI(vp);
707 ssp = smi->smi_share;
708
709 if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
710 return (EIO);
711
712 if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
713 return (EIO);
714
715 ASSERT(smbfs_rw_lock_held(&np->r_rwlock, RW_WRITER));
716
717 if (vp->v_type != VREG)
718 return (EISDIR);
719
720 if (uiop->uio_resid == 0)
721 return (0);
722
723 /*
724 * Handle ioflag bits: (FAPPEND|FSYNC|FDSYNC)
725 */
726 if (ioflag & (FAPPEND | FSYNC)) {
727 if (np->n_flag & NMODIFIED) {
728 smbfs_attrcache_remove(np);
729 /* XXX: smbfs_vinvalbuf? */
730 }
731 }
732 if (ioflag & FAPPEND) {
733 /*
734 * File size can be changed by another client
735 */
736 va.va_mask = AT_SIZE;
737 if (error = smbfsgetattr(vp, &va, cr))
738 return (error);
739 uiop->uio_loffset = va.va_size;
740 }
741
742 /*
743 * Like NFS3, just check for 63-bit overflow.
744 */
745 endoff = uiop->uio_loffset + uiop->uio_resid;
746 if (uiop->uio_loffset < 0 || endoff < 0)
747 return (EINVAL);
748
749 /*
750 * Check to make sure that the process will not exceed
751 * its limit on file size. It is okay to write up to
752 * the limit, but not beyond. Thus, the write which
753 * reaches the limit will be short and the next write
754 * will return an error.
755 *
756 * So if we're starting at or beyond the limit, EFBIG.
757 * Otherwise, temporarily reduce resid to the amount
758 * the falls after the limit.
759 */
760 limit = uiop->uio_llimit;
761 if (limit == RLIM64_INFINITY || limit > MAXOFFSET_T)
762 limit = MAXOFFSET_T;
763 if (uiop->uio_loffset >= limit)
764 return (EFBIG);
765 if (endoff > limit) {
766 past_limit = (ssize_t)(endoff - limit);
767 uiop->uio_resid -= past_limit;
768 } else
769 past_limit = 0;
770
771 /* Timeout: longer for append. */
772 timo = smb_timo_write;
773 if (endoff > np->r_size)
774 timo = smb_timo_append;
775
776 /* Shared lock for n_fid use in smb_rwuio */
777 if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
778 return (EINTR);
779 smb_credinit(&scred, cr);
780
781 /* After reconnect, n_fid is invalid */
782 if (np->n_vcgenid != ssp->ss_vcgenid)
783 error = ESTALE;
784 else
785 error = smb_rwuio(ssp, np->n_fid, UIO_WRITE,
786 uiop, &scred, timo);
787
788 if (error == 0) {
789 mutex_enter(&np->r_statelock);
790 np->n_flag |= (NFLUSHWIRE | NATTRCHANGED);
791 if (uiop->uio_loffset > (offset_t)np->r_size)
792 np->r_size = (len_t)uiop->uio_loffset;
793 mutex_exit(&np->r_statelock);
794 if (ioflag & (FSYNC|FDSYNC)) {
795 /* Don't error the I/O if this fails. */
796 (void) smbfs_smb_flush(np, &scred);
797 }
798 }
799
800 smb_credrele(&scred);
801 smbfs_rw_exit(&np->r_lkserlock);
802
803 /* undo adjustment of resid */
804 uiop->uio_resid += past_limit;
805
806 return (error);
807 }
808
809
810 /* ARGSUSED */
811 static int
812 smbfs_ioctl(vnode_t *vp, int cmd, intptr_t arg, int flag,
813 cred_t *cr, int *rvalp, caller_context_t *ct)
814 {
815 int error;
816 smbmntinfo_t *smi;
817
818 smi = VTOSMI(vp);
819
820 if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
821 return (EIO);
822
823 if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
824 return (EIO);
825
826 switch (cmd) {
827 /* First three from ZFS. XXX - need these? */
828
829 case _FIOFFS:
830 error = smbfs_fsync(vp, 0, cr, ct);
831 break;
832
833 /*
834 * The following two ioctls are used by bfu.
835 * Silently ignore to avoid bfu errors.
836 */
837 case _FIOGDIO:
838 case _FIOSDIO:
839 error = 0;
840 break;
841
842 #ifdef NOT_YET /* XXX - from the NFS code. */
843 case _FIODIRECTIO:
844 error = smbfs_directio(vp, (int)arg, cr);
845 #endif
846
847 /*
848 * Allow get/set with "raw" security descriptor (SD) data.
849 * Useful for testing, diagnosing idmap problems, etc.
850 */
851 case SMBFSIO_GETSD:
852 error = smbfs_acl_iocget(vp, arg, flag, cr);
853 break;
854
855 case SMBFSIO_SETSD:
856 error = smbfs_acl_iocset(vp, arg, flag, cr);
857 break;
858
859 default:
860 error = ENOTTY;
861 break;
862 }
863
864 return (error);
865 }
866
867
868 /*
869 * Return either cached or remote attributes. If get remote attr
870 * use them to check and invalidate caches, then cache the new attributes.
871 *
872 * XXX
873 * This op should eventually support PSARC 2007/315, Extensible Attribute
874 * Interfaces, for richer metadata.
875 */
876 /* ARGSUSED */
877 static int
878 smbfs_getattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr,
879 caller_context_t *ct)
880 {
881 smbnode_t *np;
882 smbmntinfo_t *smi;
883
884 smi = VTOSMI(vp);
885
886 if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
887 return (EIO);
888
889 if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
890 return (EIO);
891
892 /*
893 * If it has been specified that the return value will
894 * just be used as a hint, and we are only being asked
895 * for size, fsid or rdevid, then return the client's
896 * notion of these values without checking to make sure
897 * that the attribute cache is up to date.
898 * The whole point is to avoid an over the wire GETATTR
899 * call.
900 */
901 np = VTOSMB(vp);
902 if (flags & ATTR_HINT) {
903 if (vap->va_mask ==
904 (vap->va_mask & (AT_SIZE | AT_FSID | AT_RDEV))) {
905 mutex_enter(&np->r_statelock);
906 if (vap->va_mask | AT_SIZE)
907 vap->va_size = np->r_size;
908 if (vap->va_mask | AT_FSID)
909 vap->va_fsid = vp->v_vfsp->vfs_dev;
910 if (vap->va_mask | AT_RDEV)
911 vap->va_rdev = vp->v_rdev;
912 mutex_exit(&np->r_statelock);
913 return (0);
914 }
915 }
916
917 return (smbfsgetattr(vp, vap, cr));
918 }
919
920 /* smbfsgetattr() in smbfs_client.c */
921
922 /*
923 * XXX
924 * This op should eventually support PSARC 2007/315, Extensible Attribute
925 * Interfaces, for richer metadata.
926 */
927 /*ARGSUSED4*/
928 static int
929 smbfs_setattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr,
930 caller_context_t *ct)
931 {
932 vfs_t *vfsp;
933 smbmntinfo_t *smi;
934 int error;
935 uint_t mask;
936 struct vattr oldva;
937
938 vfsp = vp->v_vfsp;
939 smi = VFTOSMI(vfsp);
940
941 if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
942 return (EIO);
943
944 if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED)
945 return (EIO);
946
947 mask = vap->va_mask;
948 if (mask & AT_NOSET)
949 return (EINVAL);
950
951 if (vfsp->vfs_flag & VFS_RDONLY)
952 return (EROFS);
953
954 /*
955 * This is a _local_ access check so that only the owner of
956 * this mount can set attributes. With ACLs enabled, the
957 * file owner can be different from the mount owner, and we
958 * need to check the _mount_ owner here. See _access_rwx
959 */
960 bzero(&oldva, sizeof (oldva));
961 oldva.va_mask = AT_TYPE | AT_MODE;
962 error = smbfsgetattr(vp, &oldva, cr);
963 if (error)
964 return (error);
965 oldva.va_mask |= AT_UID | AT_GID;
966 oldva.va_uid = smi->smi_uid;
967 oldva.va_gid = smi->smi_gid;
968
969 error = secpolicy_vnode_setattr(cr, vp, vap, &oldva, flags,
970 smbfs_accessx, vp);
971 if (error)
972 return (error);
973
974 if (mask & (AT_UID | AT_GID)) {
975 if (smi->smi_flags & SMI_ACL)
976 error = smbfs_acl_setids(vp, vap, cr);
977 else
978 error = ENOSYS;
979 if (error != 0) {
980 SMBVDEBUG("error %d seting UID/GID on %s",
981 error, VTOSMB(vp)->n_rpath);
982 /*
983 * It might be more correct to return the
984 * error here, but that causes complaints
985 * when root extracts a cpio archive, etc.
986 * So ignore this error, and go ahead with
987 * the rest of the setattr work.
988 */
989 }
990 }
991
992 return (smbfssetattr(vp, vap, flags, cr));
993 }
994
995 /*
996 * Mostly from Darwin smbfs_setattr()
997 * but then modified a lot.
998 */
999 /* ARGSUSED */
1000 static int
1001 smbfssetattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr)
1002 {
1003 int error = 0;
1004 smbnode_t *np = VTOSMB(vp);
1005 uint_t mask = vap->va_mask;
1006 struct timespec *mtime, *atime;
1007 struct smb_cred scred;
1008 int cerror, modified = 0;
1009 unsigned short fid;
1010 int have_fid = 0;
1011 uint32_t rights = 0;
1012
1013 ASSERT(curproc->p_zone == VTOSMI(vp)->smi_zone_ref.zref_zone);
1014
1015 /*
1016 * There are no settable attributes on the XATTR dir,
1017 * so just silently ignore these. On XATTR files,
1018 * you can set the size but nothing else.
1019 */
1020 if (vp->v_flag & V_XATTRDIR)
1021 return (0);
1022 if (np->n_flag & N_XATTR) {
1023 if (mask & AT_TIMES)
1024 SMBVDEBUG("ignore set time on xattr\n");
1025 mask &= AT_SIZE;
1026 }
1027
1028 /*
1029 * If our caller is trying to set multiple attributes, they
1030 * can make no assumption about what order they are done in.
1031 * Here we try to do them in order of decreasing likelihood
1032 * of failure, just to minimize the chance we'll wind up
1033 * with a partially complete request.
1034 */
1035
1036 /* Shared lock for (possible) n_fid use. */
1037 if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
1038 return (EINTR);
1039 smb_credinit(&scred, cr);
1040
1041 /*
1042 * Will we need an open handle for this setattr?
1043 * If so, what rights will we need?
1044 */
1045 if (mask & (AT_ATIME | AT_MTIME)) {
1046 rights |=
1047 SA_RIGHT_FILE_WRITE_ATTRIBUTES;
1048 }
1049 if (mask & AT_SIZE) {
1050 rights |=
1051 SA_RIGHT_FILE_WRITE_DATA |
1052 SA_RIGHT_FILE_APPEND_DATA;
1053 }
1054
1055 /*
1056 * Only SIZE really requires a handle, but it's
1057 * simpler and more reliable to set via a handle.
1058 * Some servers like NT4 won't set times by path.
1059 * Also, we're usually setting everything anyway.
1060 */
1061 if (mask & (AT_SIZE | AT_ATIME | AT_MTIME)) {
1062 error = smbfs_smb_tmpopen(np, rights, &scred, &fid);
1063 if (error) {
1064 SMBVDEBUG("error %d opening %s\n",
1065 error, np->n_rpath);
1066 goto out;
1067 }
1068 have_fid = 1;
1069 }
1070
1071 /*
1072 * If the server supports the UNIX extensions, right here is where
1073 * we'd support changes to uid, gid, mode, and possibly va_flags.
1074 * For now we claim to have made any such changes.
1075 */
1076
1077 if (mask & AT_SIZE) {
1078 /*
1079 * If the new file size is less than what the client sees as
1080 * the file size, then just change the size and invalidate
1081 * the pages.
1082 * I am commenting this code at present because the function
1083 * smbfs_putapage() is not yet implemented.
1084 */
1085
1086 /*
1087 * Set the file size to vap->va_size.
1088 */
1089 ASSERT(have_fid);
1090 error = smbfs_smb_setfsize(np, fid, vap->va_size, &scred);
1091 if (error) {
1092 SMBVDEBUG("setsize error %d file %s\n",
1093 error, np->n_rpath);
1094 } else {
1095 /*
1096 * Darwin had code here to zero-extend.
1097 * Tests indicate the server will zero-fill,
1098 * so looks like we don't need to do this.
1099 * Good thing, as this could take forever.
1100 *
1101 * XXX: Reportedly, writing one byte of zero
1102 * at the end offset avoids problems here.
1103 */
1104 mutex_enter(&np->r_statelock);
1105 np->r_size = vap->va_size;
1106 mutex_exit(&np->r_statelock);
1107 modified = 1;
1108 }
1109 }
1110
1111 /*
1112 * XXX: When Solaris has create_time, set that too.
1113 * Note: create_time is different from ctime.
1114 */
1115 mtime = ((mask & AT_MTIME) ? &vap->va_mtime : 0);
1116 atime = ((mask & AT_ATIME) ? &vap->va_atime : 0);
1117
1118 if (mtime || atime) {
1119 /*
1120 * Always use the handle-based set attr call now.
1121 * Not trying to set DOS attributes here so pass zero.
1122 */
1123 ASSERT(have_fid);
1124 error = smbfs_smb_setfattr(np, fid,
1125 0, mtime, atime, &scred);
1126 if (error) {
1127 SMBVDEBUG("set times error %d file %s\n",
1128 error, np->n_rpath);
1129 } else {
1130 modified = 1;
1131 }
1132 }
1133
1134 out:
1135 if (modified) {
1136 /*
1137 * Invalidate attribute cache in case the server
1138 * doesn't set exactly the attributes we asked.
1139 */
1140 smbfs_attrcache_remove(np);
1141 }
1142
1143 if (have_fid) {
1144 cerror = smbfs_smb_tmpclose(np, fid, &scred);
1145 if (cerror)
1146 SMBVDEBUG("error %d closing %s\n",
1147 cerror, np->n_rpath);
1148 }
1149
1150 smb_credrele(&scred);
1151 smbfs_rw_exit(&np->r_lkserlock);
1152
1153 return (error);
1154 }
1155
1156 /*
1157 * smbfs_access_rwx()
1158 * Common function for smbfs_access, etc.
1159 *
1160 * The security model implemented by the FS is unusual
1161 * due to the current "single user mounts" restriction:
1162 * All access under a given mount point uses the CIFS
1163 * credentials established by the owner of the mount.
1164 *
1165 * Most access checking is handled by the CIFS server,
1166 * but we need sufficient Unix access checks here to
1167 * prevent other local Unix users from having access
1168 * to objects under this mount that the uid/gid/mode
1169 * settings in the mount would not allow.
1170 *
1171 * With this model, there is a case where we need the
1172 * ability to do an access check before we have the
1173 * vnode for an object. This function takes advantage
1174 * of the fact that the uid/gid/mode is per mount, and
1175 * avoids the need for a vnode.
1176 *
1177 * We still (sort of) need a vnode when we call
1178 * secpolicy_vnode_access, but that only uses
1179 * the vtype field, so we can use a pair of fake
1180 * vnodes that have only v_type filled in.
1181 *
1182 * XXX: Later, add a new secpolicy_vtype_access()
1183 * that takes the vtype instead of a vnode, and
1184 * get rid of the tmpl_vxxx fake vnodes below.
1185 */
1186 static int
1187 smbfs_access_rwx(vfs_t *vfsp, int vtype, int mode, cred_t *cr)
1188 {
1189 /* See the secpolicy call below. */
1190 static const vnode_t tmpl_vdir = { .v_type = VDIR };
1191 static const vnode_t tmpl_vreg = { .v_type = VREG };
1192 vattr_t va;
1193 vnode_t *tvp;
1194 struct smbmntinfo *smi = VFTOSMI(vfsp);
1195 int shift = 0;
1196
1197 /*
1198 * Build our (fabricated) vnode attributes.
1199 * XXX: Could make these templates in the
1200 * per-mount struct and use them here.
1201 */
1202 bzero(&va, sizeof (va));
1203 va.va_mask = AT_TYPE | AT_MODE | AT_UID | AT_GID;
1204 va.va_type = vtype;
1205 va.va_mode = (vtype == VDIR) ?
1206 smi->smi_dmode : smi->smi_fmode;
1207 va.va_uid = smi->smi_uid;
1208 va.va_gid = smi->smi_gid;
1209
1210 /*
1211 * Disallow write attempts on read-only file systems,
1212 * unless the file is a device or fifo node. Note:
1213 * Inline vn_is_readonly and IS_DEVVP here because
1214 * we may not have a vnode ptr. Original expr. was:
1215 * (mode & VWRITE) && vn_is_readonly(vp) && !IS_DEVVP(vp))
1216 */
1217 if ((mode & VWRITE) &&
1218 (vfsp->vfs_flag & VFS_RDONLY) &&
1219 !(vtype == VCHR || vtype == VBLK || vtype == VFIFO))
1220 return (EROFS);
1221
1222 /*
1223 * Disallow attempts to access mandatory lock files.
1224 * Similarly, expand MANDLOCK here.
1225 * XXX: not sure we need this.
1226 */
1227 if ((mode & (VWRITE | VREAD | VEXEC)) &&
1228 va.va_type == VREG && MANDMODE(va.va_mode))
1229 return (EACCES);
1230
1231 /*
1232 * Access check is based on only
1233 * one of owner, group, public.
1234 * If not owner, then check group.
1235 * If not a member of the group,
1236 * then check public access.
1237 */
1238 if (crgetuid(cr) != va.va_uid) {
1239 shift += 3;
1240 if (!groupmember(va.va_gid, cr))
1241 shift += 3;
1242 }
1243
1244 /*
1245 * We need a vnode for secpolicy_vnode_access,
1246 * but the only thing it looks at is v_type,
1247 * so pass one of the templates above.
1248 */
1249 tvp = (va.va_type == VDIR) ?
1250 (vnode_t *)&tmpl_vdir :
1251 (vnode_t *)&tmpl_vreg;
1252
1253 return (secpolicy_vnode_access2(cr, tvp, va.va_uid,
1254 va.va_mode << shift, mode));
1255 }
1256
1257 /*
1258 * See smbfs_setattr
1259 */
1260 static int
1261 smbfs_accessx(void *arg, int mode, cred_t *cr)
1262 {
1263 vnode_t *vp = arg;
1264 /*
1265 * Note: The caller has checked the current zone,
1266 * the SMI_DEAD and VFS_UNMOUNTED flags, etc.
1267 */
1268 return (smbfs_access_rwx(vp->v_vfsp, vp->v_type, mode, cr));
1269 }
1270
1271 /*
1272 * XXX
1273 * This op should support PSARC 2007/403, Modified Access Checks for CIFS
1274 */
1275 /* ARGSUSED */
1276 static int
1277 smbfs_access(vnode_t *vp, int mode, int flags, cred_t *cr, caller_context_t *ct)
1278 {
1279 vfs_t *vfsp;
1280 smbmntinfo_t *smi;
1281
1282 vfsp = vp->v_vfsp;
1283 smi = VFTOSMI(vfsp);
1284
1285 if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
1286 return (EIO);
1287
1288 if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED)
1289 return (EIO);
1290
1291 return (smbfs_access_rwx(vfsp, vp->v_type, mode, cr));
1292 }
1293
1294
1295 /*
1296 * Flush local dirty pages to stable storage on the server.
1297 *
1298 * If FNODSYNC is specified, then there is nothing to do because
1299 * metadata changes are not cached on the client before being
1300 * sent to the server.
1301 */
1302 /* ARGSUSED */
1303 static int
1304 smbfs_fsync(vnode_t *vp, int syncflag, cred_t *cr, caller_context_t *ct)
1305 {
1306 int error = 0;
1307 smbmntinfo_t *smi;
1308 smbnode_t *np;
1309 struct smb_cred scred;
1310
1311 np = VTOSMB(vp);
1312 smi = VTOSMI(vp);
1313
1314 if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
1315 return (EIO);
1316
1317 if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
1318 return (EIO);
1319
1320 if ((syncflag & FNODSYNC) || IS_SWAPVP(vp))
1321 return (0);
1322
1323 if ((syncflag & (FSYNC|FDSYNC)) == 0)
1324 return (0);
1325
1326 /* Shared lock for n_fid use in _flush */
1327 if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
1328 return (EINTR);
1329 smb_credinit(&scred, cr);
1330
1331 error = smbfs_smb_flush(np, &scred);
1332
1333 smb_credrele(&scred);
1334 smbfs_rw_exit(&np->r_lkserlock);
1335
1336 return (error);
1337 }
1338
1339 /*
1340 * Last reference to vnode went away.
1341 */
1342 /* ARGSUSED */
1343 static void
1344 smbfs_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
1345 {
1346 smbnode_t *np;
1347 struct smb_cred scred;
1348
1349 /*
1350 * Don't "bail out" for VFS_UNMOUNTED here,
1351 * as we want to do cleanup, etc.
1352 * See also pcfs_inactive
1353 */
1354
1355 np = VTOSMB(vp);
1356
1357 /*
1358 * If this is coming from the wrong zone, we let someone in the right
1359 * zone take care of it asynchronously. We can get here due to
1360 * VN_RELE() being called from pageout() or fsflush(). This call may
1361 * potentially turn into an expensive no-op if, for instance, v_count
1362 * gets incremented in the meantime, but it's still correct.
1363 */
1364
1365 /*
1366 * Defend against the possibility that higher-level callers
1367 * might not correctly balance open and close calls. If we
1368 * get here with open references remaining, it means there
1369 * was a missing VOP_CLOSE somewhere. If that happens, do
1370 * the close here so we don't "leak" FIDs on the server.
1371 *
1372 * Exclusive lock for modifying n_fid stuff.
1373 * Don't want this one ever interruptible.
1374 */
1375 (void) smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, 0);
1376 smb_credinit(&scred, cr);
1377
1378 switch (np->n_ovtype) {
1379 case VNON:
1380 /* not open (OK) */
1381 break;
1382
1383 case VDIR:
1384 if (np->n_dirrefs == 0)
1385 break;
1386 SMBVDEBUG("open dir: refs %d path %s\n",
1387 np->n_dirrefs, np->n_rpath);
1388 /* Force last close. */
1389 np->n_dirrefs = 1;
1390 smbfs_rele_fid(np, &scred);
1391 break;
1392
1393 case VREG:
1394 if (np->n_fidrefs == 0)
1395 break;
1396 SMBVDEBUG("open file: refs %d id 0x%x path %s\n",
1397 np->n_fidrefs, np->n_fid, np->n_rpath);
1398 /* Force last close. */
1399 np->n_fidrefs = 1;
1400 smbfs_rele_fid(np, &scred);
1401 break;
1402
1403 default:
1404 SMBVDEBUG("bad n_ovtype %d\n", np->n_ovtype);
1405 np->n_ovtype = VNON;
1406 break;
1407 }
1408
1409 smb_credrele(&scred);
1410 smbfs_rw_exit(&np->r_lkserlock);
1411
1412 smbfs_addfree(np);
1413 }
1414
1415 /*
1416 * Remote file system operations having to do with directory manipulation.
1417 */
1418 /* ARGSUSED */
1419 static int
1420 smbfs_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, struct pathname *pnp,
1421 int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct,
1422 int *direntflags, pathname_t *realpnp)
1423 {
1424 vfs_t *vfs;
1425 smbmntinfo_t *smi;
1426 smbnode_t *dnp;
1427 int error;
1428
1429 vfs = dvp->v_vfsp;
1430 smi = VFTOSMI(vfs);
1431
1432 if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
1433 return (EPERM);
1434
1435 if (smi->smi_flags & SMI_DEAD || vfs->vfs_flag & VFS_UNMOUNTED)
1436 return (EIO);
1437
1438 dnp = VTOSMB(dvp);
1439
1440 /*
1441 * Are we looking up extended attributes? If so, "dvp" is
1442 * the file or directory for which we want attributes, and
1443 * we need a lookup of the (faked up) attribute directory
1444 * before we lookup the rest of the path.
1445 */
1446 if (flags & LOOKUP_XATTR) {
1447 /*
1448 * Require the xattr mount option.
1449 */
1450 if ((vfs->vfs_flag & VFS_XATTR) == 0)
1451 return (EINVAL);
1452
1453 error = smbfs_get_xattrdir(dvp, vpp, cr, flags);
1454 return (error);
1455 }
1456
1457 if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_READER, SMBINTR(dvp)))
1458 return (EINTR);
1459
1460 error = smbfslookup(dvp, nm, vpp, cr, 1, ct);
1461
1462 smbfs_rw_exit(&dnp->r_rwlock);
1463
1464 return (error);
1465 }
1466
1467 /* ARGSUSED */
1468 static int
1469 smbfslookup(vnode_t *dvp, char *nm, vnode_t **vpp, cred_t *cr,
1470 int cache_ok, caller_context_t *ct)
1471 {
1472 int error;
1473 int supplen; /* supported length */
1474 vnode_t *vp;
1475 smbnode_t *np;
1476 smbnode_t *dnp;
1477 smbmntinfo_t *smi;
1478 /* struct smb_vc *vcp; */
1479 const char *ill;
1480 const char *name = (const char *)nm;
1481 int nmlen = strlen(nm);
1482 int rplen;
1483 struct smb_cred scred;
1484 struct smbfattr fa;
1485
1486 smi = VTOSMI(dvp);
1487 dnp = VTOSMB(dvp);
1488
1489 ASSERT(curproc->p_zone == smi->smi_zone_ref.zref_zone);
1490
1491 #ifdef NOT_YET
1492 vcp = SSTOVC(smi->smi_share);
1493
1494 /* XXX: Should compute this once and store it in smbmntinfo_t */
1495 supplen = (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN2_0) ? 255 : 12;
1496 #else
1497 supplen = 255;
1498 #endif
1499
1500 /*
1501 * RWlock must be held, either reader or writer.
1502 * XXX: Can we check without looking directly
1503 * inside the struct smbfs_rwlock_t?
1504 */
1505 ASSERT(dnp->r_rwlock.count != 0);
1506
1507 /*
1508 * If lookup is for "", just return dvp.
1509 * No need to perform any access checks.
1510 */
1511 if (nmlen == 0) {
1512 VN_HOLD(dvp);
1513 *vpp = dvp;
1514 return (0);
1515 }
1516
1517 /*
1518 * Can't do lookups in non-directories.
1519 */
1520 if (dvp->v_type != VDIR)
1521 return (ENOTDIR);
1522
1523 /*
1524 * Need search permission in the directory.
1525 */
1526 error = smbfs_access(dvp, VEXEC, 0, cr, ct);
1527 if (error)
1528 return (error);
1529
1530 /*
1531 * If lookup is for ".", just return dvp.
1532 * Access check was done above.
1533 */
1534 if (nmlen == 1 && name[0] == '.') {
1535 VN_HOLD(dvp);
1536 *vpp = dvp;
1537 return (0);
1538 }
1539
1540 /*
1541 * Now some sanity checks on the name.
1542 * First check the length.
1543 */
1544 if (nmlen > supplen)
1545 return (ENAMETOOLONG);
1546
1547 /*
1548 * Avoid surprises with characters that are
1549 * illegal in Windows file names.
1550 * Todo: CATIA mappings XXX
1551 */
1552 ill = illegal_chars;
1553 if (dnp->n_flag & N_XATTR)
1554 ill++; /* allow colon */
1555 if (strpbrk(nm, ill))
1556 return (EINVAL);
1557
1558 /*
1559 * Special handling for lookup of ".."
1560 *
1561 * We keep full pathnames (as seen on the server)
1562 * so we can just trim off the last component to
1563 * get the full pathname of the parent. Note:
1564 * We don't actually copy and modify, but just
1565 * compute the trimmed length and pass that with
1566 * the current dir path (not null terminated).
1567 *
1568 * We don't go over-the-wire to get attributes
1569 * for ".." because we know it's a directory,
1570 * and we can just leave the rest "stale"
1571 * until someone does a getattr.
1572 */
1573 if (nmlen == 2 && name[0] == '.' && name[1] == '.') {
1574 if (dvp->v_flag & VROOT) {
1575 /*
1576 * Already at the root. This can happen
1577 * with directory listings at the root,
1578 * which lookup "." and ".." to get the
1579 * inode numbers. Let ".." be the same
1580 * as "." in the FS root.
1581 */
1582 VN_HOLD(dvp);
1583 *vpp = dvp;
1584 return (0);
1585 }
1586
1587 /*
1588 * Special case for XATTR directory
1589 */
1590 if (dvp->v_flag & V_XATTRDIR) {
1591 error = smbfs_xa_parent(dvp, vpp);
1592 return (error);
1593 }
1594
1595 /*
1596 * Find the parent path length.
1597 */
1598 rplen = dnp->n_rplen;
1599 ASSERT(rplen > 0);
1600 while (--rplen >= 0) {
1601 if (dnp->n_rpath[rplen] == '\\')
1602 break;
1603 }
1604 if (rplen <= 0) {
1605 /* Found our way to the root. */
1606 vp = SMBTOV(smi->smi_root);
1607 VN_HOLD(vp);
1608 *vpp = vp;
1609 return (0);
1610 }
1611 np = smbfs_node_findcreate(smi,
1612 dnp->n_rpath, rplen, NULL, 0, 0,
1613 &smbfs_fattr0); /* force create */
1614 ASSERT(np != NULL);
1615 vp = SMBTOV(np);
1616 vp->v_type = VDIR;
1617
1618 /* Success! */
1619 *vpp = vp;
1620 return (0);
1621 }
1622
1623 /*
1624 * Normal lookup of a name under this directory.
1625 * Note we handled "", ".", ".." above.
1626 */
1627 if (cache_ok) {
1628 /*
1629 * The caller indicated that it's OK to use a
1630 * cached result for this lookup, so try to
1631 * reclaim a node from the smbfs node cache.
1632 */
1633 error = smbfslookup_cache(dvp, nm, nmlen, &vp, cr);
1634 if (error)
1635 return (error);
1636 if (vp != NULL) {
1637 /* hold taken in lookup_cache */
1638 *vpp = vp;
1639 return (0);
1640 }
1641 }
1642
1643 /*
1644 * OK, go over-the-wire to get the attributes,
1645 * then create the node.
1646 */
1647 smb_credinit(&scred, cr);
1648 /* Note: this can allocate a new "name" */
1649 error = smbfs_smb_lookup(dnp, &name, &nmlen, &fa, &scred);
1650 smb_credrele(&scred);
1651 if (error == ENOTDIR) {
1652 /*
1653 * Lookup failed because this directory was
1654 * removed or renamed by another client.
1655 * Remove any cached attributes under it.
1656 */
1657 smbfs_attrcache_remove(dnp);
1658 smbfs_attrcache_prune(dnp);
1659 }
1660 if (error)
1661 goto out;
1662
1663 error = smbfs_nget(dvp, name, nmlen, &fa, &vp);
1664 if (error)
1665 goto out;
1666
1667 /* Success! */
1668 *vpp = vp;
1669
1670 out:
1671 /* smbfs_smb_lookup may have allocated name. */
1672 if (name != nm)
1673 smbfs_name_free(name, nmlen);
1674
1675 return (error);
1676 }
1677
1678 /*
1679 * smbfslookup_cache
1680 *
1681 * Try to reclaim a node from the smbfs node cache.
1682 * Some statistics for DEBUG.
1683 *
1684 * This mechanism lets us avoid many of the five (or more)
1685 * OtW lookup calls per file seen with "ls -l" if we search
1686 * the smbfs node cache for recently inactive(ated) nodes.
1687 */
1688 #ifdef DEBUG
1689 int smbfs_lookup_cache_calls = 0;
1690 int smbfs_lookup_cache_error = 0;
1691 int smbfs_lookup_cache_miss = 0;
1692 int smbfs_lookup_cache_stale = 0;
1693 int smbfs_lookup_cache_hits = 0;
1694 #endif /* DEBUG */
1695
1696 /* ARGSUSED */
1697 static int
1698 smbfslookup_cache(vnode_t *dvp, char *nm, int nmlen,
1699 vnode_t **vpp, cred_t *cr)
1700 {
1701 struct vattr va;
1702 smbnode_t *dnp;
1703 smbnode_t *np;
1704 vnode_t *vp;
1705 int error;
1706 char sep;
1707
1708 dnp = VTOSMB(dvp);
1709 *vpp = NULL;
1710
1711 #ifdef DEBUG
1712 smbfs_lookup_cache_calls++;
1713 #endif
1714
1715 /*
1716 * First make sure we can get attributes for the
1717 * directory. Cached attributes are OK here.
1718 * If we removed or renamed the directory, this
1719 * will return ENOENT. If someone else removed
1720 * this directory or file, we'll find out when we
1721 * try to open or get attributes.
1722 */
1723 va.va_mask = AT_TYPE | AT_MODE;
1724 error = smbfsgetattr(dvp, &va, cr);
1725 if (error) {
1726 #ifdef DEBUG
1727 smbfs_lookup_cache_error++;
1728 #endif
1729 return (error);
1730 }
1731
1732 /*
1733 * Passing NULL smbfattr here so we will
1734 * just look, not create.
1735 */
1736 sep = SMBFS_DNP_SEP(dnp);
1737 np = smbfs_node_findcreate(dnp->n_mount,
1738 dnp->n_rpath, dnp->n_rplen,
1739 nm, nmlen, sep, NULL);
1740 if (np == NULL) {
1741 #ifdef DEBUG
1742 smbfs_lookup_cache_miss++;
1743 #endif
1744 return (0);
1745 }
1746
1747 /*
1748 * Found it. Attributes still valid?
1749 */
1750 vp = SMBTOV(np);
1751 if (np->r_attrtime <= gethrtime()) {
1752 /* stale */
1753 #ifdef DEBUG
1754 smbfs_lookup_cache_stale++;
1755 #endif
1756 VN_RELE(vp);
1757 return (0);
1758 }
1759
1760 /*
1761 * Success!
1762 * Caller gets hold from smbfs_node_findcreate
1763 */
1764 #ifdef DEBUG
1765 smbfs_lookup_cache_hits++;
1766 #endif
1767 *vpp = vp;
1768 return (0);
1769 }
1770
1771 /*
1772 * XXX
1773 * vsecattr_t is new to build 77, and we need to eventually support
1774 * it in order to create an ACL when an object is created.
1775 *
1776 * This op should support the new FIGNORECASE flag for case-insensitive
1777 * lookups, per PSARC 2007/244.
1778 */
1779 /* ARGSUSED */
1780 static int
1781 smbfs_create(vnode_t *dvp, char *nm, struct vattr *va, enum vcexcl exclusive,
1782 int mode, vnode_t **vpp, cred_t *cr, int lfaware, caller_context_t *ct,
1783 vsecattr_t *vsecp)
1784 {
1785 int error;
1786 int cerror;
1787 vfs_t *vfsp;
1788 vnode_t *vp;
1789 #ifdef NOT_YET
1790 smbnode_t *np;
1791 #endif
1792 smbnode_t *dnp;
1793 smbmntinfo_t *smi;
1794 struct vattr vattr;
1795 struct smbfattr fattr;
1796 struct smb_cred scred;
1797 const char *name = (const char *)nm;
1798 int nmlen = strlen(nm);
1799 uint32_t disp;
1800 uint16_t fid;
1801 int xattr;
1802
1803 vfsp = dvp->v_vfsp;
1804 smi = VFTOSMI(vfsp);
1805 dnp = VTOSMB(dvp);
1806 vp = NULL;
1807
1808 if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
1809 return (EPERM);
1810
1811 if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED)
1812 return (EIO);
1813
1814 /*
1815 * Note: this may break mknod(2) calls to create a directory,
1816 * but that's obscure use. Some other filesystems do this.
1817 * XXX: Later, redirect VDIR type here to _mkdir.
1818 */
1819 if (va->va_type != VREG)
1820 return (EINVAL);
1821
1822 /*
1823 * If the pathname is "", just use dvp, no checks.
1824 * Do this outside of the rwlock (like zfs).
1825 */
1826 if (nmlen == 0) {
1827 VN_HOLD(dvp);
1828 *vpp = dvp;
1829 return (0);
1830 }
1831
1832 /* Don't allow "." or ".." through here. */
1833 if ((nmlen == 1 && name[0] == '.') ||
1834 (nmlen == 2 && name[0] == '.' && name[1] == '.'))
1835 return (EISDIR);
1836
1837 /*
1838 * We make a copy of the attributes because the caller does not
1839 * expect us to change what va points to.
1840 */
1841 vattr = *va;
1842
1843 if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp)))
1844 return (EINTR);
1845 smb_credinit(&scred, cr);
1846
1847 /*
1848 * XXX: Do we need r_lkserlock too?
1849 * No use of any shared fid or fctx...
1850 */
1851
1852 /*
1853 * NFS needs to go over the wire, just to be sure whether the
1854 * file exists or not. Using a cached result is dangerous in
1855 * this case when making a decision regarding existence.
1856 *
1857 * The SMB protocol does NOT really need to go OTW here
1858 * thanks to the expressive NTCREATE disposition values.
1859 * Unfortunately, to do Unix access checks correctly,
1860 * we need to know if the object already exists.
1861 * When the object does not exist, we need VWRITE on
1862 * the directory. Note: smbfslookup() checks VEXEC.
1863 */
1864 error = smbfslookup(dvp, nm, &vp, cr, 0, ct);
1865 if (error == 0) {
1866 /*
1867 * The file already exists. Error?
1868 * NB: have a hold from smbfslookup
1869 */
1870 if (exclusive == EXCL) {
1871 error = EEXIST;
1872 VN_RELE(vp);
1873 goto out;
1874 }
1875 /*
1876 * Verify requested access.
1877 */
1878 error = smbfs_access(vp, mode, 0, cr, ct);
1879 if (error) {
1880 VN_RELE(vp);
1881 goto out;
1882 }
1883
1884 /*
1885 * Truncate (if requested).
1886 */
1887 if ((vattr.va_mask & AT_SIZE) && vattr.va_size == 0) {
1888 vattr.va_mask = AT_SIZE;
1889 error = smbfssetattr(vp, &vattr, 0, cr);
1890 if (error) {
1891 VN_RELE(vp);
1892 goto out;
1893 }
1894 }
1895 /* Success! */
1896 #ifdef NOT_YET
1897 vnevent_create(vp, ct);
1898 #endif
1899 *vpp = vp;
1900 goto out;
1901 }
1902
1903 /*
1904 * The file did not exist. Need VWRITE in the directory.
1905 */
1906 error = smbfs_access(dvp, VWRITE, 0, cr, ct);
1907 if (error)
1908 goto out;
1909
1910 /*
1911 * Now things get tricky. We also need to check the
1912 * requested open mode against the file we may create.
1913 * See comments at smbfs_access_rwx
1914 */
1915 error = smbfs_access_rwx(vfsp, VREG, mode, cr);
1916 if (error)
1917 goto out;
1918
1919 /*
1920 * Now the code derived from Darwin,
1921 * but with greater use of NT_CREATE
1922 * disposition options. Much changed.
1923 *
1924 * Create (or open) a new child node.
1925 * Note we handled "." and ".." above.
1926 */
1927
1928 if (exclusive == EXCL)
1929 disp = NTCREATEX_DISP_CREATE;
1930 else {
1931 /* Truncate regular files if requested. */
1932 if ((va->va_type == VREG) &&
1933 (va->va_mask & AT_SIZE) &&
1934 (va->va_size == 0))
1935 disp = NTCREATEX_DISP_OVERWRITE_IF;
1936 else
1937 disp = NTCREATEX_DISP_OPEN_IF;
1938 }
1939 xattr = (dnp->n_flag & N_XATTR) ? 1 : 0;
1940 error = smbfs_smb_create(dnp,
1941 name, nmlen, xattr,
1942 disp, &scred, &fid);
1943 if (error)
1944 goto out;
1945
1946 /*
1947 * XXX: Missing some code here to deal with
1948 * the case where we opened an existing file,
1949 * it's size is larger than 32-bits, and we're
1950 * setting the size from a process that's not
1951 * aware of large file offsets. i.e.
1952 * from the NFS3 code:
1953 */
1954 #if NOT_YET /* XXX */
1955 if ((vattr.va_mask & AT_SIZE) &&
1956 vp->v_type == VREG) {
1957 np = VTOSMB(vp);
1958 /*
1959 * Check here for large file handled
1960 * by LF-unaware process (as
1961 * ufs_create() does)
1962 */
1963 if (!(lfaware & FOFFMAX)) {
1964 mutex_enter(&np->r_statelock);
1965 if (np->r_size > MAXOFF32_T)
1966 error = EOVERFLOW;
1967 mutex_exit(&np->r_statelock);
1968 }
1969 if (!error) {
1970 vattr.va_mask = AT_SIZE;
1971 error = smbfssetattr(vp,
1972 &vattr, 0, cr);
1973 }
1974 }
1975 #endif /* XXX */
1976 /*
1977 * Should use the fid to get/set the size
1978 * while we have it opened here. See above.
1979 */
1980
1981 cerror = smbfs_smb_close(smi->smi_share, fid, NULL, &scred);
1982 if (cerror)
1983 SMBVDEBUG("error %d closing %s\\%s\n",
1984 cerror, dnp->n_rpath, name);
1985
1986 /*
1987 * In the open case, the name may differ a little
1988 * from what we passed to create (case, etc.)
1989 * so call lookup to get the (opened) name.
1990 *
1991 * XXX: Could avoid this extra lookup if the
1992 * "createact" result from NT_CREATE says we
1993 * created the object.
1994 */
1995 error = smbfs_smb_lookup(dnp, &name, &nmlen, &fattr, &scred);
1996 if (error)
1997 goto out;
1998
1999 /* update attr and directory cache */
2000 smbfs_attr_touchdir(dnp);
2001
2002 error = smbfs_nget(dvp, name, nmlen, &fattr, &vp);
2003 if (error)
2004 goto out;
2005
2006 /* XXX invalidate pages if we truncated? */
2007
2008 /* Success! */
2009 *vpp = vp;
2010 error = 0;
2011
2012 out:
2013 smb_credrele(&scred);
2014 smbfs_rw_exit(&dnp->r_rwlock);
2015 if (name != nm)
2016 smbfs_name_free(name, nmlen);
2017 return (error);
2018 }
2019
2020 /*
2021 * XXX
2022 * This op should support the new FIGNORECASE flag for case-insensitive
2023 * lookups, per PSARC 2007/244.
2024 */
2025 /* ARGSUSED */
2026 static int
2027 smbfs_remove(vnode_t *dvp, char *nm, cred_t *cr, caller_context_t *ct,
2028 int flags)
2029 {
2030 int error;
2031 vnode_t *vp;
2032 smbnode_t *np;
2033 smbnode_t *dnp;
2034 struct smb_cred scred;
2035 /* enum smbfsstat status; */
2036 smbmntinfo_t *smi;
2037
2038 smi = VTOSMI(dvp);
2039
2040 if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
2041 return (EPERM);
2042
2043 if (smi->smi_flags & SMI_DEAD || dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
2044 return (EIO);
2045
2046 dnp = VTOSMB(dvp);
2047 if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp)))
2048 return (EINTR);
2049 smb_credinit(&scred, cr);
2050
2051 /*
2052 * Verify access to the dirctory.
2053 */
2054 error = smbfs_access(dvp, VWRITE|VEXEC, 0, cr, ct);
2055 if (error)
2056 goto out;
2057
2058 /*
2059 * NOTE: the darwin code gets the "vp" passed in so it looks
2060 * like the "vp" has probably been "lookup"ed by the VFS layer.
2061 * It looks like we will need to lookup the vp to check the
2062 * caches and check if the object being deleted is a directory.
2063 */
2064 error = smbfslookup(dvp, nm, &vp, cr, 0, ct);
2065 if (error)
2066 goto out;
2067
2068 /* Never allow link/unlink directories on CIFS. */
2069 if (vp->v_type == VDIR) {
2070 VN_RELE(vp);
2071 error = EPERM;
2072 goto out;
2073 }
2074
2075 /*
2076 * Now we have the real reference count on the vnode
2077 * Do we have the file open?
2078 */
2079 np = VTOSMB(vp);
2080 mutex_enter(&np->r_statelock);
2081 if ((vp->v_count > 1) && (np->n_fidrefs > 0)) {
2082 /*
2083 * NFS does a rename on remove here.
2084 * Probably not applicable for SMB.
2085 * Like Darwin, just return EBUSY.
2086 *
2087 * XXX: Todo - Use Trans2rename, and
2088 * if that fails, ask the server to
2089 * set the delete-on-close flag.
2090 */
2091 mutex_exit(&np->r_statelock);
2092 error = EBUSY;
2093 } else {
2094 smbfs_attrcache_rm_locked(np);
2095 mutex_exit(&np->r_statelock);
2096
2097 error = smbfs_smb_delete(np, &scred, NULL, 0, 0);
2098
2099 /*
2100 * If the file should no longer exist, discard
2101 * any cached attributes under this node.
2102 */
2103 switch (error) {
2104 case 0:
2105 case ENOENT:
2106 case ENOTDIR:
2107 smbfs_attrcache_prune(np);
2108 break;
2109 }
2110 }
2111
2112 VN_RELE(vp);
2113
2114 out:
2115 smb_credrele(&scred);
2116 smbfs_rw_exit(&dnp->r_rwlock);
2117
2118 return (error);
2119 }
2120
2121
2122 /*
2123 * XXX
2124 * This op should support the new FIGNORECASE flag for case-insensitive
2125 * lookups, per PSARC 2007/244.
2126 */
2127 /* ARGSUSED */
2128 static int
2129 smbfs_rename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr,
2130 caller_context_t *ct, int flags)
2131 {
2132 /* vnode_t *realvp; */
2133
2134 if (curproc->p_zone != VTOSMI(odvp)->smi_zone_ref.zref_zone ||
2135 curproc->p_zone != VTOSMI(ndvp)->smi_zone_ref.zref_zone)
2136 return (EPERM);
2137
2138 if (VTOSMI(odvp)->smi_flags & SMI_DEAD ||
2139 VTOSMI(ndvp)->smi_flags & SMI_DEAD ||
2140 odvp->v_vfsp->vfs_flag & VFS_UNMOUNTED ||
2141 ndvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
2142 return (EIO);
2143
2144 return (smbfsrename(odvp, onm, ndvp, nnm, cr, ct));
2145 }
2146
2147 /*
2148 * smbfsrename does the real work of renaming in SMBFS
2149 */
2150 /* ARGSUSED */
2151 static int
2152 smbfsrename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr,
2153 caller_context_t *ct)
2154 {
2155 int error;
2156 int nvp_locked = 0;
2157 vnode_t *nvp = NULL;
2158 vnode_t *ovp = NULL;
2159 smbnode_t *onp;
2160 smbnode_t *nnp;
2161 smbnode_t *odnp;
2162 smbnode_t *ndnp;
2163 struct smb_cred scred;
2164 /* enum smbfsstat status; */
2165
2166 ASSERT(curproc->p_zone == VTOSMI(odvp)->smi_zone_ref.zref_zone);
2167
2168 if (strcmp(onm, ".") == 0 || strcmp(onm, "..") == 0 ||
2169 strcmp(nnm, ".") == 0 || strcmp(nnm, "..") == 0)
2170 return (EINVAL);
2171
2172 /*
2173 * Check that everything is on the same filesystem.
2174 * vn_rename checks the fsid's, but in case we don't
2175 * fill those in correctly, check here too.
2176 */
2177 if (odvp->v_vfsp != ndvp->v_vfsp)
2178 return (EXDEV);
2179
2180 odnp = VTOSMB(odvp);
2181 ndnp = VTOSMB(ndvp);
2182
2183 /*
2184 * Avoid deadlock here on old vs new directory nodes
2185 * by always taking the locks in order of address.
2186 * The order is arbitrary, but must be consistent.
2187 */
2188 if (odnp < ndnp) {
2189 if (smbfs_rw_enter_sig(&odnp->r_rwlock, RW_WRITER,
2190 SMBINTR(odvp)))
2191 return (EINTR);
2192 if (smbfs_rw_enter_sig(&ndnp->r_rwlock, RW_WRITER,
2193 SMBINTR(ndvp))) {
2194 smbfs_rw_exit(&odnp->r_rwlock);
2195 return (EINTR);
2196 }
2197 } else {
2198 if (smbfs_rw_enter_sig(&ndnp->r_rwlock, RW_WRITER,
2199 SMBINTR(ndvp)))
2200 return (EINTR);
2201 if (smbfs_rw_enter_sig(&odnp->r_rwlock, RW_WRITER,
2202 SMBINTR(odvp))) {
2203 smbfs_rw_exit(&ndnp->r_rwlock);
2204 return (EINTR);
2205 }
2206 }
2207 smb_credinit(&scred, cr);
2208 /*
2209 * No returns after this point (goto out)
2210 */
2211
2212 /*
2213 * Need write access on source and target.
2214 * Server takes care of most checks.
2215 */
2216 error = smbfs_access(odvp, VWRITE|VEXEC, 0, cr, ct);
2217 if (error)
2218 goto out;
2219 if (odvp != ndvp) {
2220 error = smbfs_access(ndvp, VWRITE, 0, cr, ct);
2221 if (error)
2222 goto out;
2223 }
2224
2225 /*
2226 * Lookup the source name. Must already exist.
2227 */
2228 error = smbfslookup(odvp, onm, &ovp, cr, 0, ct);
2229 if (error)
2230 goto out;
2231
2232 /*
2233 * Lookup the target file. If it exists, it needs to be
2234 * checked to see whether it is a mount point and whether
2235 * it is active (open).
2236 */
2237 error = smbfslookup(ndvp, nnm, &nvp, cr, 0, ct);
2238 if (!error) {
2239 /*
2240 * Target (nvp) already exists. Check that it
2241 * has the same type as the source. The server
2242 * will check this also, (and more reliably) but
2243 * this lets us return the correct error codes.
2244 */
2245 if (ovp->v_type == VDIR) {
2246 if (nvp->v_type != VDIR) {
2247 error = ENOTDIR;
2248 goto out;
2249 }
2250 } else {
2251 if (nvp->v_type == VDIR) {
2252 error = EISDIR;
2253 goto out;
2254 }
2255 }
2256
2257 /*
2258 * POSIX dictates that when the source and target
2259 * entries refer to the same file object, rename
2260 * must do nothing and exit without error.
2261 */
2262 if (ovp == nvp) {
2263 error = 0;
2264 goto out;
2265 }
2266
2267 /*
2268 * Also must ensure the target is not a mount point,
2269 * and keep mount/umount away until we're done.
2270 */
2271 if (vn_vfsrlock(nvp)) {
2272 error = EBUSY;
2273 goto out;
2274 }
2275 nvp_locked = 1;
2276 if (vn_mountedvfs(nvp) != NULL) {
2277 error = EBUSY;
2278 goto out;
2279 }
2280
2281 /*
2282 * CIFS gives a SHARING_VIOLATION error when
2283 * trying to rename onto an exising object,
2284 * so try to remove the target first.
2285 * (Only for files, not directories.)
2286 */
2287 if (nvp->v_type == VDIR) {
2288 error = EEXIST;
2289 goto out;
2290 }
2291
2292 /*
2293 * Nodes that are "not active" here have v_count=2
2294 * because vn_renameat (our caller) did a lookup on
2295 * both the source and target before this call.
2296 * Otherwise this similar to smbfs_remove.
2297 */
2298 nnp = VTOSMB(nvp);
2299 mutex_enter(&nnp->r_statelock);
2300 if ((nvp->v_count > 2) && (nnp->n_fidrefs > 0)) {
2301 /*
2302 * The target file exists, is not the same as
2303 * the source file, and is active. Other FS
2304 * implementations unlink the target here.
2305 * For SMB, we don't assume we can remove an
2306 * open file. Return an error instead.
2307 */
2308 mutex_exit(&nnp->r_statelock);
2309 error = EBUSY;
2310 goto out;
2311 }
2312
2313 /*
2314 * Target file is not active. Try to remove it.
2315 */
2316 smbfs_attrcache_rm_locked(nnp);
2317 mutex_exit(&nnp->r_statelock);
2318
2319 error = smbfs_smb_delete(nnp, &scred, NULL, 0, 0);
2320
2321 /*
2322 * Similar to smbfs_remove
2323 */
2324 switch (error) {
2325 case 0:
2326 case ENOENT:
2327 case ENOTDIR:
2328 smbfs_attrcache_prune(nnp);
2329 break;
2330 }
2331
2332 if (error)
2333 goto out;
2334 /*
2335 * OK, removed the target file. Continue as if
2336 * lookup target had failed (nvp == NULL).
2337 */
2338 vn_vfsunlock(nvp);
2339 nvp_locked = 0;
2340 VN_RELE(nvp);
2341 nvp = NULL;
2342 } /* nvp */
2343
2344 onp = VTOSMB(ovp);
2345 smbfs_attrcache_remove(onp);
2346
2347 error = smbfs_smb_rename(onp, ndnp, nnm, strlen(nnm), &scred);
2348
2349 /*
2350 * If the old name should no longer exist,
2351 * discard any cached attributes under it.
2352 */
2353 if (error == 0)
2354 smbfs_attrcache_prune(onp);
2355
2356 out:
2357 if (nvp) {
2358 if (nvp_locked)
2359 vn_vfsunlock(nvp);
2360 VN_RELE(nvp);
2361 }
2362 if (ovp)
2363 VN_RELE(ovp);
2364
2365 smb_credrele(&scred);
2366 smbfs_rw_exit(&odnp->r_rwlock);
2367 smbfs_rw_exit(&ndnp->r_rwlock);
2368
2369 return (error);
2370 }
2371
2372 /*
2373 * XXX
2374 * vsecattr_t is new to build 77, and we need to eventually support
2375 * it in order to create an ACL when an object is created.
2376 *
2377 * This op should support the new FIGNORECASE flag for case-insensitive
2378 * lookups, per PSARC 2007/244.
2379 */
2380 /* ARGSUSED */
2381 static int
2382 smbfs_mkdir(vnode_t *dvp, char *nm, struct vattr *va, vnode_t **vpp,
2383 cred_t *cr, caller_context_t *ct, int flags, vsecattr_t *vsecp)
2384 {
2385 vnode_t *vp;
2386 struct smbnode *dnp = VTOSMB(dvp);
2387 struct smbmntinfo *smi = VTOSMI(dvp);
2388 struct smb_cred scred;
2389 struct smbfattr fattr;
2390 const char *name = (const char *) nm;
2391 int nmlen = strlen(name);
2392 int error, hiderr;
2393
2394 if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
2395 return (EPERM);
2396
2397 if (smi->smi_flags & SMI_DEAD || dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
2398 return (EIO);
2399
2400 if ((nmlen == 1 && name[0] == '.') ||
2401 (nmlen == 2 && name[0] == '.' && name[1] == '.'))
2402 return (EEXIST);
2403
2404 /* Only plain files are allowed in V_XATTRDIR. */
2405 if (dvp->v_flag & V_XATTRDIR)
2406 return (EINVAL);
2407
2408 if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp)))
2409 return (EINTR);
2410 smb_credinit(&scred, cr);
2411
2412 /*
2413 * XXX: Do we need r_lkserlock too?
2414 * No use of any shared fid or fctx...
2415 */
2416
2417 /*
2418 * Require write access in the containing directory.
2419 */
2420 error = smbfs_access(dvp, VWRITE, 0, cr, ct);
2421 if (error)
2422 goto out;
2423
2424 error = smbfs_smb_mkdir(dnp, name, nmlen, &scred);
2425 if (error)
2426 goto out;
2427
2428 error = smbfs_smb_lookup(dnp, &name, &nmlen, &fattr, &scred);
2429 if (error)
2430 goto out;
2431
2432 smbfs_attr_touchdir(dnp);
2433
2434 error = smbfs_nget(dvp, name, nmlen, &fattr, &vp);
2435 if (error)
2436 goto out;
2437
2438 if (name[0] == '.')
2439 if ((hiderr = smbfs_smb_hideit(VTOSMB(vp), NULL, 0, &scred)))
2440 SMBVDEBUG("hide failure %d\n", hiderr);
2441
2442 /* Success! */
2443 *vpp = vp;
2444 error = 0;
2445 out:
2446 smb_credrele(&scred);
2447 smbfs_rw_exit(&dnp->r_rwlock);
2448
2449 if (name != nm)
2450 smbfs_name_free(name, nmlen);
2451
2452 return (error);
2453 }
2454
2455 /*
2456 * XXX
2457 * This op should support the new FIGNORECASE flag for case-insensitive
2458 * lookups, per PSARC 2007/244.
2459 */
2460 /* ARGSUSED */
2461 static int
2462 smbfs_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr,
2463 caller_context_t *ct, int flags)
2464 {
2465 vnode_t *vp = NULL;
2466 int vp_locked = 0;
2467 struct smbmntinfo *smi = VTOSMI(dvp);
2468 struct smbnode *dnp = VTOSMB(dvp);
2469 struct smbnode *np;
2470 struct smb_cred scred;
2471 int error;
2472
2473 if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
2474 return (EPERM);
2475
2476 if (smi->smi_flags & SMI_DEAD || dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
2477 return (EIO);
2478
2479 if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp)))
2480 return (EINTR);
2481 smb_credinit(&scred, cr);
2482
2483 /*
2484 * Require w/x access in the containing directory.
2485 * Server handles all other access checks.
2486 */
2487 error = smbfs_access(dvp, VEXEC|VWRITE, 0, cr, ct);
2488 if (error)
2489 goto out;
2490
2491 /*
2492 * First lookup the entry to be removed.
2493 */
2494 error = smbfslookup(dvp, nm, &vp, cr, 0, ct);
2495 if (error)
2496 goto out;
2497 np = VTOSMB(vp);
2498
2499 /*
2500 * Disallow rmdir of "." or current dir, or the FS root.
2501 * Also make sure it's a directory, not a mount point,
2502 * and lock to keep mount/umount away until we're done.
2503 */
2504 if ((vp == dvp) || (vp == cdir) || (vp->v_flag & VROOT)) {
2505 error = EINVAL;
2506 goto out;
2507 }
2508 if (vp->v_type != VDIR) {
2509 error = ENOTDIR;
2510 goto out;
2511 }
2512 if (vn_vfsrlock(vp)) {
2513 error = EBUSY;
2514 goto out;
2515 }
2516 vp_locked = 1;
2517 if (vn_mountedvfs(vp) != NULL) {
2518 error = EBUSY;
2519 goto out;
2520 }
2521
2522 smbfs_attrcache_remove(np);
2523 error = smbfs_smb_rmdir(np, &scred);
2524
2525 /*
2526 * Similar to smbfs_remove
2527 */
2528 switch (error) {
2529 case 0:
2530 case ENOENT:
2531 case ENOTDIR:
2532 smbfs_attrcache_prune(np);
2533 break;
2534 }
2535
2536 if (error)
2537 goto out;
2538
2539 mutex_enter(&np->r_statelock);
2540 dnp->n_flag |= NMODIFIED;
2541 mutex_exit(&np->r_statelock);
2542 smbfs_attr_touchdir(dnp);
2543 smbfs_rmhash(np);
2544
2545 out:
2546 if (vp) {
2547 if (vp_locked)
2548 vn_vfsunlock(vp);
2549 VN_RELE(vp);
2550 }
2551 smb_credrele(&scred);
2552 smbfs_rw_exit(&dnp->r_rwlock);
2553
2554 return (error);
2555 }
2556
2557
2558 /* ARGSUSED */
2559 static int
2560 smbfs_readdir(vnode_t *vp, struct uio *uiop, cred_t *cr, int *eofp,
2561 caller_context_t *ct, int flags)
2562 {
2563 struct smbnode *np = VTOSMB(vp);
2564 int error = 0;
2565 smbmntinfo_t *smi;
2566
2567 smi = VTOSMI(vp);
2568
2569 if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
2570 return (EIO);
2571
2572 if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
2573 return (EIO);
2574
2575 /*
2576 * Require read access in the directory.
2577 */
2578 error = smbfs_access(vp, VREAD, 0, cr, ct);
2579 if (error)
2580 return (error);
2581
2582 ASSERT(smbfs_rw_lock_held(&np->r_rwlock, RW_READER));
2583
2584 /*
2585 * XXX: Todo readdir cache here
2586 * Note: NFS code is just below this.
2587 *
2588 * I am serializing the entire readdir opreation
2589 * now since we have not yet implemented readdir
2590 * cache. This fix needs to be revisited once
2591 * we implement readdir cache.
2592 */
2593 if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, SMBINTR(vp)))
2594 return (EINTR);
2595
2596 error = smbfs_readvdir(vp, uiop, cr, eofp, ct);
2597
2598 smbfs_rw_exit(&np->r_lkserlock);
2599
2600 return (error);
2601 }
2602
2603 /* ARGSUSED */
2604 static int
2605 smbfs_readvdir(vnode_t *vp, uio_t *uio, cred_t *cr, int *eofp,
2606 caller_context_t *ct)
2607 {
2608 /*
2609 * Note: "limit" tells the SMB-level FindFirst/FindNext
2610 * functions how many directory entries to request in
2611 * each OtW call. It needs to be large enough so that
2612 * we don't make lots of tiny OtW requests, but there's
2613 * no point making it larger than the maximum number of
2614 * OtW entries that would fit in a maximum sized trans2
2615 * response (64k / 48). Beyond that, it's just tuning.
2616 * WinNT used 512, Win2k used 1366. We use 1000.
2617 */
2618 static const int limit = 1000;
2619 /* Largest possible dirent size. */
2620 static const size_t dbufsiz = DIRENT64_RECLEN(SMB_MAXFNAMELEN);
2621 struct smb_cred scred;
2622 vnode_t *newvp;
2623 struct smbnode *np = VTOSMB(vp);
2624 struct smbfs_fctx *ctx;
2625 struct dirent64 *dp;
2626 ssize_t save_resid;
2627 offset_t save_offset; /* 64 bits */
2628 int offset; /* yes, 32 bits */
2629 int nmlen, error;
2630 ushort_t reclen;
2631
2632 ASSERT(curproc->p_zone == VTOSMI(vp)->smi_zone_ref.zref_zone);
2633
2634 /* Make sure we serialize for n_dirseq use. */
2635 ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_WRITER));
2636
2637 /*
2638 * Make sure smbfs_open filled in n_dirseq
2639 */
2640 if (np->n_dirseq == NULL)
2641 return (EBADF);
2642
2643 /* Check for overflow of (32-bit) directory offset. */
2644 if (uio->uio_loffset < 0 || uio->uio_loffset > INT32_MAX ||
2645 (uio->uio_loffset + uio->uio_resid) > INT32_MAX)
2646 return (EINVAL);
2647
2648 /* Require space for at least one dirent. */
2649 if (uio->uio_resid < dbufsiz)
2650 return (EINVAL);
2651
2652 SMBVDEBUG("dirname='%s'\n", np->n_rpath);
2653 smb_credinit(&scred, cr);
2654 dp = kmem_alloc(dbufsiz, KM_SLEEP);
2655
2656 save_resid = uio->uio_resid;
2657 save_offset = uio->uio_loffset;
2658 offset = uio->uio_offset;
2659 SMBVDEBUG("in: offset=%d, resid=%d\n",
2660 (int)uio->uio_offset, (int)uio->uio_resid);
2661 error = 0;
2662
2663 /*
2664 * Generate the "." and ".." entries here so we can
2665 * (1) make sure they appear (but only once), and
2666 * (2) deal with getting their I numbers which the
2667 * findnext below does only for normal names.
2668 */
2669 while (offset < FIRST_DIROFS) {
2670 /*
2671 * Tricky bit filling in the first two:
2672 * offset 0 is ".", offset 1 is ".."
2673 * so strlen of these is offset+1.
2674 */
2675 reclen = DIRENT64_RECLEN(offset + 1);
2676 if (uio->uio_resid < reclen)
2677 goto out;
2678 bzero(dp, reclen);
2679 dp->d_reclen = reclen;
2680 dp->d_name[0] = '.';
2681 dp->d_name[1] = '.';
2682 dp->d_name[offset + 1] = '\0';
2683 /*
2684 * Want the real I-numbers for the "." and ".."
2685 * entries. For these two names, we know that
2686 * smbfslookup can get the nodes efficiently.
2687 */
2688 error = smbfslookup(vp, dp->d_name, &newvp, cr, 1, ct);
2689 if (error) {
2690 dp->d_ino = np->n_ino + offset; /* fiction */
2691 } else {
2692 dp->d_ino = VTOSMB(newvp)->n_ino;
2693 VN_RELE(newvp);
2694 }
2695 /*
2696 * Note: d_off is the offset that a user-level program
2697 * should seek to for reading the NEXT directory entry.
2698 * See libc: readdir, telldir, seekdir
2699 */
2700 dp->d_off = offset + 1;
2701 error = uiomove(dp, reclen, UIO_READ, uio);
2702 if (error)
2703 goto out;
2704 /*
2705 * Note: uiomove updates uio->uio_offset,
2706 * but we want it to be our "cookie" value,
2707 * which just counts dirents ignoring size.
2708 */
2709 uio->uio_offset = ++offset;
2710 }
2711
2712 /*
2713 * If there was a backward seek, we have to reopen.
2714 */
2715 if (offset < np->n_dirofs) {
2716 SMBVDEBUG("Reopening search %d:%d\n",
2717 offset, np->n_dirofs);
2718 error = smbfs_smb_findopen(np, "*", 1,
2719 SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR,
2720 &scred, &ctx);
2721 if (error) {
2722 SMBVDEBUG("can not open search, error = %d", error);
2723 goto out;
2724 }
2725 /* free the old one */
2726 (void) smbfs_smb_findclose(np->n_dirseq, &scred);
2727 /* save the new one */
2728 np->n_dirseq = ctx;
2729 np->n_dirofs = FIRST_DIROFS;
2730 } else {
2731 ctx = np->n_dirseq;
2732 }
2733
2734 /*
2735 * Skip entries before the requested offset.
2736 */
2737 while (np->n_dirofs < offset) {
2738 error = smbfs_smb_findnext(ctx, limit, &scred);
2739 if (error != 0)
2740 goto out;
2741 np->n_dirofs++;
2742 }
2743
2744 /*
2745 * While there's room in the caller's buffer:
2746 * get a directory entry from SMB,
2747 * convert to a dirent, copyout.
2748 * We stop when there is no longer room for a
2749 * maximum sized dirent because we must decide
2750 * before we know anything about the next entry.
2751 */
2752 while (uio->uio_resid >= dbufsiz) {
2753 error = smbfs_smb_findnext(ctx, limit, &scred);
2754 if (error != 0)
2755 goto out;
2756 np->n_dirofs++;
2757
2758 /* Sanity check the name length. */
2759 nmlen = ctx->f_nmlen;
2760 if (nmlen > SMB_MAXFNAMELEN) {
2761 nmlen = SMB_MAXFNAMELEN;
2762 SMBVDEBUG("Truncating name: %s\n", ctx->f_name);
2763 }
2764 if (smbfs_fastlookup) {
2765 /* See comment at smbfs_fastlookup above. */
2766 if (smbfs_nget(vp, ctx->f_name, nmlen,
2767 &ctx->f_attr, &newvp) == 0)
2768 VN_RELE(newvp);
2769 }
2770
2771 reclen = DIRENT64_RECLEN(nmlen);
2772 bzero(dp, reclen);
2773 dp->d_reclen = reclen;
2774 bcopy(ctx->f_name, dp->d_name, nmlen);
2775 dp->d_name[nmlen] = '\0';
2776 dp->d_ino = ctx->f_inum;
2777 dp->d_off = offset + 1; /* See d_off comment above */
2778 error = uiomove(dp, reclen, UIO_READ, uio);
2779 if (error)
2780 goto out;
2781 /* See comment re. uio_offset above. */
2782 uio->uio_offset = ++offset;
2783 }
2784
2785 out:
2786 /*
2787 * When we come to the end of a directory, the
2788 * SMB-level functions return ENOENT, but the
2789 * caller is not expecting an error return.
2790 *
2791 * Also note that we must delay the call to
2792 * smbfs_smb_findclose(np->n_dirseq, ...)
2793 * until smbfs_close so that all reads at the
2794 * end of the directory will return no data.
2795 */
2796 if (error == ENOENT) {
2797 error = 0;
2798 if (eofp)
2799 *eofp = 1;
2800 }
2801 /*
2802 * If we encountered an error (i.e. "access denied")
2803 * from the FindFirst call, we will have copied out
2804 * the "." and ".." entries leaving offset == 2.
2805 * In that case, restore the original offset/resid
2806 * so the caller gets no data with the error.
2807 */
2808 if (error != 0 && offset == FIRST_DIROFS) {
2809 uio->uio_loffset = save_offset;
2810 uio->uio_resid = save_resid;
2811 }
2812 SMBVDEBUG("out: offset=%d, resid=%d\n",
2813 (int)uio->uio_offset, (int)uio->uio_resid);
2814
2815 kmem_free(dp, dbufsiz);
2816 smb_credrele(&scred);
2817 return (error);
2818 }
2819
2820
2821 /*
2822 * The pair of functions VOP_RWLOCK, VOP_RWUNLOCK
2823 * are optional functions that are called by:
2824 * getdents, before/after VOP_READDIR
2825 * pread, before/after ... VOP_READ
2826 * pwrite, before/after ... VOP_WRITE
2827 * (other places)
2828 *
2829 * Careful here: None of the above check for any
2830 * error returns from VOP_RWLOCK / VOP_RWUNLOCK!
2831 * In fact, the return value from _rwlock is NOT
2832 * an error code, but V_WRITELOCK_TRUE / _FALSE.
2833 *
2834 * Therefore, it's up to _this_ code to make sure
2835 * the lock state remains balanced, which means
2836 * we can't "bail out" on interrupts, etc.
2837 */
2838
2839 /* ARGSUSED2 */
2840 static int
2841 smbfs_rwlock(vnode_t *vp, int write_lock, caller_context_t *ctp)
2842 {
2843 smbnode_t *np = VTOSMB(vp);
2844
2845 if (!write_lock) {
2846 (void) smbfs_rw_enter_sig(&np->r_rwlock, RW_READER, FALSE);
2847 return (V_WRITELOCK_FALSE);
2848 }
2849
2850
2851 (void) smbfs_rw_enter_sig(&np->r_rwlock, RW_WRITER, FALSE);
2852 return (V_WRITELOCK_TRUE);
2853 }
2854
2855 /* ARGSUSED */
2856 static void
2857 smbfs_rwunlock(vnode_t *vp, int write_lock, caller_context_t *ctp)
2858 {
2859 smbnode_t *np = VTOSMB(vp);
2860
2861 smbfs_rw_exit(&np->r_rwlock);
2862 }
2863
2864
2865 /* ARGSUSED */
2866 static int
2867 smbfs_seek(vnode_t *vp, offset_t ooff, offset_t *noffp, caller_context_t *ct)
2868 {
2869 smbmntinfo_t *smi;
2870
2871 smi = VTOSMI(vp);
2872
2873 if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
2874 return (EPERM);
2875
2876 if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
2877 return (EIO);
2878
2879 /*
2880 * Because we stuff the readdir cookie into the offset field
2881 * someone may attempt to do an lseek with the cookie which
2882 * we want to succeed.
2883 */
2884 if (vp->v_type == VDIR)
2885 return (0);
2886
2887 /* Like NFS3, just check for 63-bit overflow. */
2888 if (*noffp < 0)
2889 return (EINVAL);
2890
2891 return (0);
2892 }
2893
2894
2895 /*
2896 * XXX
2897 * This op may need to support PSARC 2007/440, nbmand changes for CIFS Service.
2898 */
2899 static int
2900 smbfs_frlock(vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
2901 offset_t offset, struct flk_callback *flk_cbp, cred_t *cr,
2902 caller_context_t *ct)
2903 {
2904 if (curproc->p_zone != VTOSMI(vp)->smi_zone_ref.zref_zone)
2905 return (EIO);
2906
2907 if (VTOSMI(vp)->smi_flags & SMI_LLOCK)
2908 return (fs_frlock(vp, cmd, bfp, flag, offset, flk_cbp, cr, ct));
2909 else
2910 return (ENOSYS);
2911 }
2912
2913 /*
2914 * Free storage space associated with the specified vnode. The portion
2915 * to be freed is specified by bfp->l_start and bfp->l_len (already
2916 * normalized to a "whence" of 0).
2917 *
2918 * Called by fcntl(fd, F_FREESP, lkp) for libc:ftruncate, etc.
2919 */
2920 /* ARGSUSED */
2921 static int
2922 smbfs_space(vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
2923 offset_t offset, cred_t *cr, caller_context_t *ct)
2924 {
2925 int error;
2926 smbmntinfo_t *smi;
2927
2928 smi = VTOSMI(vp);
2929
2930 if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
2931 return (EIO);
2932
2933 if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
2934 return (EIO);
2935
2936 /* Caller (fcntl) has checked v_type */
2937 ASSERT(vp->v_type == VREG);
2938 if (cmd != F_FREESP)
2939 return (EINVAL);
2940
2941 /*
2942 * Like NFS3, no 32-bit offset checks here.
2943 * Our SMB layer takes care to return EFBIG
2944 * when it has to fallback to a 32-bit call.
2945 */
2946
2947 error = convoff(vp, bfp, 0, offset);
2948 if (!error) {
2949 ASSERT(bfp->l_start >= 0);
2950 if (bfp->l_len == 0) {
2951 struct vattr va;
2952
2953 /*
2954 * ftruncate should not change the ctime and
2955 * mtime if we truncate the file to its
2956 * previous size.
2957 */
2958 va.va_mask = AT_SIZE;
2959 error = smbfsgetattr(vp, &va, cr);
2960 if (error || va.va_size == bfp->l_start)
2961 return (error);
2962 va.va_mask = AT_SIZE;
2963 va.va_size = bfp->l_start;
2964 error = smbfssetattr(vp, &va, 0, cr);
2965 } else
2966 error = EINVAL;
2967 }
2968
2969 return (error);
2970 }
2971
2972 /* ARGSUSED */
2973 static int
2974 smbfs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr,
2975 caller_context_t *ct)
2976 {
2977 vfs_t *vfs;
2978 smbmntinfo_t *smi;
2979 struct smb_share *ssp;
2980
2981 vfs = vp->v_vfsp;
2982 smi = VFTOSMI(vfs);
2983
2984 if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
2985 return (EIO);
2986
2987 if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
2988 return (EIO);
2989
2990 switch (cmd) {
2991 case _PC_FILESIZEBITS:
2992 ssp = smi->smi_share;
2993 if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_LARGE_FILES)
2994 *valp = 64;
2995 else
2996 *valp = 32;
2997 break;
2998
2999 case _PC_LINK_MAX:
3000 /* We only ever report one link to an object */
3001 *valp = 1;
3002 break;
3003
3004 case _PC_ACL_ENABLED:
3005 /*
3006 * Always indicate that ACLs are enabled and
3007 * that we support ACE_T format, otherwise
3008 * libsec will ask for ACLENT_T format data
3009 * which we don't support.
3010 */
3011 *valp = _ACL_ACE_ENABLED;
3012 break;
3013
3014 case _PC_SYMLINK_MAX: /* No symlinks until we do Unix extensions */
3015 *valp = 0;
3016 break;
3017
3018 case _PC_XATTR_EXISTS:
3019 if (vfs->vfs_flag & VFS_XATTR) {
3020 *valp = smbfs_xa_exists(vp, cr);
3021 break;
3022 }
3023 return (EINVAL);
3024
3025 case _PC_TIMESTAMP_RESOLUTION:
3026 /*
3027 * Windows times are tenths of microseconds
3028 * (multiples of 100 nanoseconds).
3029 */
3030 *valp = 100L;
3031 break;
3032
3033 default:
3034 return (fs_pathconf(vp, cmd, valp, cr, ct));
3035 }
3036 return (0);
3037 }
3038
3039 /* ARGSUSED */
3040 static int
3041 smbfs_getsecattr(vnode_t *vp, vsecattr_t *vsa, int flag, cred_t *cr,
3042 caller_context_t *ct)
3043 {
3044 vfs_t *vfsp;
3045 smbmntinfo_t *smi;
3046 int error;
3047 uint_t mask;
3048
3049 vfsp = vp->v_vfsp;
3050 smi = VFTOSMI(vfsp);
3051
3052 if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
3053 return (EIO);
3054
3055 if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED)
3056 return (EIO);
3057
3058 /*
3059 * Our _pathconf indicates _ACL_ACE_ENABLED,
3060 * so we should only see VSA_ACE, etc here.
3061 * Note: vn_create asks for VSA_DFACLCNT,
3062 * and it expects ENOSYS and empty data.
3063 */
3064 mask = vsa->vsa_mask & (VSA_ACE | VSA_ACECNT |
3065 VSA_ACE_ACLFLAGS | VSA_ACE_ALLTYPES);
3066 if (mask == 0)
3067 return (ENOSYS);
3068
3069 if (smi->smi_flags & SMI_ACL)
3070 error = smbfs_acl_getvsa(vp, vsa, flag, cr);
3071 else
3072 error = ENOSYS;
3073
3074 if (error == ENOSYS)
3075 error = fs_fab_acl(vp, vsa, flag, cr, ct);
3076
3077 return (error);
3078 }
3079
3080 /* ARGSUSED */
3081 static int
3082 smbfs_setsecattr(vnode_t *vp, vsecattr_t *vsa, int flag, cred_t *cr,
3083 caller_context_t *ct)
3084 {
3085 vfs_t *vfsp;
3086 smbmntinfo_t *smi;
3087 int error;
3088 uint_t mask;
3089
3090 vfsp = vp->v_vfsp;
3091 smi = VFTOSMI(vfsp);
3092
3093 if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
3094 return (EIO);
3095
3096 if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED)
3097 return (EIO);
3098
3099 /*
3100 * Our _pathconf indicates _ACL_ACE_ENABLED,
3101 * so we should only see VSA_ACE, etc here.
3102 */
3103 mask = vsa->vsa_mask & (VSA_ACE | VSA_ACECNT);
3104 if (mask == 0)
3105 return (ENOSYS);
3106
3107 if (vfsp->vfs_flag & VFS_RDONLY)
3108 return (EROFS);
3109
3110 /*
3111 * Allow only the mount owner to do this.
3112 * See comments at smbfs_access_rwx.
3113 */
3114 error = secpolicy_vnode_setdac(cr, smi->smi_uid);
3115 if (error != 0)
3116 return (error);
3117
3118 if (smi->smi_flags & SMI_ACL)
3119 error = smbfs_acl_setvsa(vp, vsa, flag, cr);
3120 else
3121 error = ENOSYS;
3122
3123 return (error);
3124 }
3125
3126
3127 /*
3128 * XXX
3129 * This op should eventually support PSARC 2007/268.
3130 */
3131 static int
3132 smbfs_shrlock(vnode_t *vp, int cmd, struct shrlock *shr, int flag, cred_t *cr,
3133 caller_context_t *ct)
3134 {
3135 if (curproc->p_zone != VTOSMI(vp)->smi_zone_ref.zref_zone)
3136 return (EIO);
3137
3138 if (VTOSMI(vp)->smi_flags & SMI_LLOCK)
3139 return (fs_shrlock(vp, cmd, shr, flag, cr, ct));
3140 else
3141 return (ENOSYS);
3142 }
3143
3144
3145
3146
3147 static int smbfs_map(vnode_t *vp, offset_t off, struct as *as, caddr_t *addrp,
3148 size_t len, uchar_t prot, uchar_t maxprot, uint_t flags, cred_t *cr,
3149 caller_context_t *ct) {
3150 smbnode_t *np;
3151 smbmntinfo_t *smi;
3152 struct vattr va;
3153 segvn_crargs_t vn_a;
3154 int error;
3155
3156 np = VTOSMB(vp);
3157 smi = VTOSMI(vp);
3158
3159 if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
3160 return (EIO);
3161
3162 if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
3163 return (EIO);
3164
3165 if (vp->v_flag & VNOMAP || vp->v_flag & VNOCACHE)
3166 return (EAGAIN);
3167
3168 if (vp->v_type != VREG)
3169 return (ENODEV);
3170
3171 va.va_mask = AT_ALL;
3172
3173 if (error = smbfsgetattr(vp, &va, cr))
3174 return (error);
3175
3176 if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, SMBINTR(vp)))
3177 return (EINTR);
3178
3179 if (MANDLOCK(vp, va.va_mode)) {
3180 error = EAGAIN;
3181 goto out;
3182 }
3183
3184 as_rangelock(as);
3185 error = choose_addr(as, addrp, len, off, ADDR_VACALIGN, flags);
3186
3187 if (error != 0) {
3188 as_rangeunlock(as);
3189 goto out;
3190 }
3191
3192 vn_a.vp = vp;
3193 vn_a.offset = (u_offset_t) off;
3194 vn_a.type = flags & MAP_TYPE;
3195 vn_a.prot = (uchar_t) prot;
3196 vn_a.maxprot = (uchar_t) maxprot;
3197 vn_a.cred = cr;
3198 vn_a.amp = NULL;
3199 vn_a.flags = flags & ~MAP_TYPE;
3200 vn_a.szc = 0;
3201 vn_a.lgrp_mem_policy_flags = 0;
3202
3203 error = as_map(as, *addrp, len, segvn_create, &vn_a);
3204
3205 as_rangeunlock(as);
3206
3207 out:
3208 smbfs_rw_exit(&np->r_lkserlock);
3209
3210 return (error);
3211 }
3212
3213 static int smbfs_addmap(vnode_t *vp, offset_t off, struct as *as, caddr_t addr,
3214 size_t len, uchar_t prot, uchar_t maxprot, uint_t flags, cred_t *cr,
3215 caller_context_t *ct) {
3216 atomic_add_long((ulong_t *) & VTOSMB(vp)->r_mapcnt, btopr(len));
3217 return (0);
3218 }
3219
3220 static int smbfs_delmap(vnode_t *vp, offset_t off, struct as *as, caddr_t addr,
3221 size_t len, uint_t prot, uint_t maxprot, uint_t flags, cred_t *cr,
3222 caller_context_t *ct) {
3223 atomic_add_long((ulong_t *) & VTOSMB(vp)->r_mapcnt, -btopr(len));
3224 return (0);
3225 }
3226
3227 static int smbfs_putpage(vnode_t *vp, offset_t off, size_t len, int flags,
3228 cred_t *cr, caller_context_t *ct) {
3229
3230 smbnode_t *np;
3231 size_t io_len;
3232 u_offset_t io_off;
3233 u_offset_t eoff;
3234 int error = 0;
3235 page_t *pp;
3236
3237 np = VTOSMB(vp);
3238
3239 if (len == 0) {
3240 error = pvn_vplist_dirty(vp, off, smbfs_putapage, flags, cr);
3241 } else {
3242
3243 eoff = off + len;
3244
3245 mutex_enter(&np->r_statelock);
3246 if (eoff > np->r_size)
3247 eoff = np->r_size;
3248 mutex_exit(&np->r_statelock);
3249
3250 for (io_off = off; io_off < eoff; io_off += io_len) {
3251 if ((flags & B_INVAL) || (flags & B_ASYNC) == 0) {
3252 pp = page_lookup(vp, io_off,
3253 (flags & (B_INVAL | B_FREE) ? SE_EXCL : SE_SHARED));
3254 } else {
3255 pp = page_lookup_nowait(vp, io_off,
3256 (flags & B_FREE) ? SE_EXCL : SE_SHARED);
3257 }
3258
3259 if (pp == NULL || !pvn_getdirty(pp, flags))
3260 io_len = PAGESIZE;
3261 else {
3262 error = smbfs_putapage(vp, pp, &io_off, &io_len, flags, cr);
3263 }
3264 }
3265
3266 }
3267
3268 return (error);
3269 }
3270
3271 static int smbfs_putapage(vnode_t *vp, page_t *pp, u_offset_t *offp, size_t *lenp,
3272 int flags, cred_t *cr) {
3273
3274 struct smb_cred scred;
3275 smbnode_t *np;
3276 smbmntinfo_t *smi;
3277 smb_share_t *ssp;
3278 uio_t uio;
3279 iovec_t uiov;
3280
3281 u_offset_t off;
3282 size_t len;
3283 int error, timo;
3284
3285 np = VTOSMB(vp);
3286 smi = VTOSMI(vp);
3287 ssp = smi->smi_share;
3288
3289 off = pp->p_offset;
3290 len = PAGESIZE;
3291
3292 if (off >= np->r_size) {
3293 error = 0;
3294 goto out;
3295 } else if (off + len > np->r_size) {
3296 int npages = btopr(np->r_size - off);
3297 page_t *trunc;
3298
3299 page_list_break(&pp, &trunc, npages);
3300 if (trunc)
3301 pvn_write_done(trunc, flags);
3302 len = np->r_size - off;
3303 }
3304
3305 timo = smb_timo_write;
3306
3307 if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
3308 return (EINTR);
3309 smb_credinit(&scred, cr);
3310
3311 if (np->n_vcgenid != ssp->ss_vcgenid)
3312 error = ESTALE;
3313 else {
3314 uiov.iov_base = 0;
3315 uiov.iov_len = 0;
3316 uio.uio_iov = &uiov;
3317 uio.uio_iovcnt = 1;
3318 uio.uio_loffset = off;
3319 uio.uio_resid = len;
3320 uio.uio_segflg = UIO_SYSSPACE;
3321 uio.uio_llimit = MAXOFFSET_T;
3322 error = up_mapin(&uio, pp);
3323 if (error == 0) {
3324 error = smb_rwuio(ssp, np->n_fid, UIO_WRITE, &uio, &scred, timo);
3325 if (error == 0) {
3326 mutex_enter(&np->r_statelock);
3327 np->n_flag |= (NFLUSHWIRE | NATTRCHANGED);
3328 mutex_exit(&np->r_statelock);
3329 (void) smbfs_smb_flush(np, &scred);
3330 }
3331 up_mapout(&uio, pp);
3332 }
3333 }
3334 smb_credrele(&scred);
3335 smbfs_rw_exit(&np->r_lkserlock);
3336
3337 out:
3338 pvn_write_done(pp, B_WRITE | flags);
3339
3340 return (error);
3341 }
3342
3343 static int up_mapin(uio_t *uiop, page_t *pp) {
3344 u_offset_t off;
3345 size_t size;
3346 pgcnt_t npages;
3347 caddr_t kaddr;
3348
3349 off = (uintptr_t) uiop->uio_loffset & PAGEOFFSET;
3350 size = P2ROUNDUP(uiop->uio_resid + off, PAGESIZE);
3351 npages = btop(size);
3352
3353 if (npages == 1 && kpm_enable) {
3354 kaddr = hat_kpm_mapin(pp, NULL);
3355 uiop->uio_iov->iov_base = kaddr;
3356 uiop->uio_iov->iov_len = PAGESIZE;
3357 return (0);
3358 }
3359 return (EFAULT);
3360 }
3361
3362 static int up_mapout(uio_t *uiop, page_t *pp) {
3363 u_offset_t off;
3364 size_t size;
3365 pgcnt_t npages;
3366 caddr_t kaddr;
3367
3368 kaddr = uiop->uio_iov->iov_base;
3369 off = (uintptr_t) kaddr & PAGEOFFSET;
3370 size = P2ROUNDUP(uiop->uio_iov->iov_len + off, PAGESIZE);
3371 npages = btop(size);
3372
3373 if (npages == 1 && kpm_enable) {
3374 kaddr = (caddr_t) ((uintptr_t) kaddr & MMU_PAGEMASK);
3375 hat_kpm_mapout(pp, NULL, kaddr);
3376 uiop->uio_iov->iov_base = 0;
3377 uiop->uio_iov->iov_len = 0;
3378 return (0);
3379 }
3380 return (EFAULT);
3381 }
3382
3383 static int smbfs_getpage(vnode_t *vp, offset_t off, size_t len, uint_t *protp,
3384 page_t *pl[], size_t plsz, struct seg *seg, caddr_t addr,
3385 enum seg_rw rw, cred_t *cr, caller_context_t *ct) {
3386 int error;
3387 smbnode_t *np;
3388
3389 np = VTOSMB(vp);
3390
3391 mutex_enter(&np->r_statelock);
3392 if (off + len > np->r_size + PAGEOFFSET && seg != segkmap) {
3393 mutex_exit(&np->r_statelock);
3394 return (EFAULT);
3395 }
3396 mutex_exit(&np->r_statelock);
3397
3398 if (len <= PAGESIZE) {
3399 error = smbfs_getapage(vp, off, len, protp, pl, plsz, seg, addr, rw,
3400 cr);
3401 } else {
3402 error = pvn_getpages(smbfs_getapage, vp, off, len, protp, pl, plsz, seg,
3403 addr, rw, cr);
3404 }
3405 return (error);
3406 }
3407
3408 static int smbfs_getapage(vnode_t *vp, u_offset_t off, size_t len,
3409 uint_t *protp, page_t *pl[], size_t plsz, struct seg *seg, caddr_t addr,
3410 enum seg_rw rw, cred_t *cr) {
3411
3412 smbnode_t *np;
3413 smbmntinfo_t *smi;
3414 smb_share_t *ssp;
3415 smb_cred_t scred;
3416
3417 page_t *pagefound, *pp;
3418 uio_t uio;
3419 iovec_t uiov;
3420
3421 int error = 0, timo;
3422
3423 np = VTOSMB(vp);
3424 smi = VTOSMI(vp);
3425 ssp = smi->smi_share;
3426
3427 if (len > PAGESIZE)
3428 return (EFAULT);
3429 len = PAGESIZE;
3430
3431 if (pl == NULL)
3432 return (EFAULT);
3433
3434 if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
3435 return EINTR;
3436
3437 smb_credinit(&scred, cr);
3438
3439 again:
3440 if ((pagefound = page_exists(vp, off)) == NULL) {
3441 if ((pp = page_create_va(vp, off, PAGESIZE, PG_WAIT | PG_EXCL, seg, addr)) == NULL)
3442 goto again;
3443 if (rw == S_CREATE) {
3444 goto out;
3445 } else {
3446 timo = smb_timo_read;
3447
3448 uiov.iov_base = 0;
3449 uiov.iov_len = 0;
3450 uio.uio_iov = &uiov;
3451 uio.uio_iovcnt = 1;
3452 uio.uio_loffset = off;
3453 uio.uio_resid = len;
3454 uio.uio_segflg = UIO_SYSSPACE;
3455 uio.uio_llimit = MAXOFFSET_T;
3456 error = up_mapin(&uio, pp);
3457 if (error == 0) {
3458 error = smb_rwuio(ssp, np->n_fid, UIO_READ, &uio, &scred, timo);
3459 up_mapout(&uio, pp);
3460 }
3461 }
3462 } else {
3463 se_t se = rw == S_CREATE ? SE_EXCL : SE_SHARED;
3464 if ((pp = page_lookup(vp, off, se)) == NULL) {
3465 goto again;
3466 }
3467 }
3468
3469 out:
3470 if (pp) {
3471 pvn_plist_init(pp, pl, plsz, off, PAGESIZE, rw);
3472 }
3473
3474 smb_credrele(&scred);
3475 smbfs_rw_exit(&np->r_lkserlock);
3476
3477 return (error);
3478 }
--- EOF ---