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