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