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