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