Print this page
7378 exported_lock held during nfs4 compound processing
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/fs/nfs/nfs4_srv.c
+++ new/usr/src/uts/common/fs/nfs/nfs4_srv.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright 2016 Nexenta Systems, Inc. All rights reserved.
24 24 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
25 25 * Copyright (c) 2012 by Delphix. All rights reserved.
26 26 */
27 27
28 28 /*
29 29 * Copyright (c) 1983,1984,1985,1986,1987,1988,1989 AT&T.
30 30 * All Rights Reserved
31 31 */
32 32
33 33 #include <sys/param.h>
34 34 #include <sys/types.h>
35 35 #include <sys/systm.h>
36 36 #include <sys/cred.h>
37 37 #include <sys/buf.h>
38 38 #include <sys/vfs.h>
39 39 #include <sys/vfs_opreg.h>
40 40 #include <sys/vnode.h>
41 41 #include <sys/uio.h>
42 42 #include <sys/errno.h>
43 43 #include <sys/sysmacros.h>
44 44 #include <sys/statvfs.h>
45 45 #include <sys/kmem.h>
46 46 #include <sys/dirent.h>
47 47 #include <sys/cmn_err.h>
48 48 #include <sys/debug.h>
49 49 #include <sys/systeminfo.h>
50 50 #include <sys/flock.h>
51 51 #include <sys/pathname.h>
52 52 #include <sys/nbmlock.h>
53 53 #include <sys/share.h>
54 54 #include <sys/atomic.h>
55 55 #include <sys/policy.h>
56 56 #include <sys/fem.h>
57 57 #include <sys/sdt.h>
58 58 #include <sys/ddi.h>
59 59 #include <sys/zone.h>
60 60
61 61 #include <fs/fs_reparse.h>
62 62
63 63 #include <rpc/types.h>
64 64 #include <rpc/auth.h>
65 65 #include <rpc/rpcsec_gss.h>
66 66 #include <rpc/svc.h>
67 67
68 68 #include <nfs/nfs.h>
69 69 #include <nfs/export.h>
70 70 #include <nfs/nfs_cmd.h>
71 71 #include <nfs/lm.h>
72 72 #include <nfs/nfs4.h>
73 73
74 74 #include <sys/strsubr.h>
75 75 #include <sys/strsun.h>
76 76
77 77 #include <inet/common.h>
78 78 #include <inet/ip.h>
79 79 #include <inet/ip6.h>
80 80
81 81 #include <sys/tsol/label.h>
82 82 #include <sys/tsol/tndb.h>
83 83
84 84 #define RFS4_MAXLOCK_TRIES 4 /* Try to get the lock this many times */
85 85 static int rfs4_maxlock_tries = RFS4_MAXLOCK_TRIES;
86 86 #define RFS4_LOCK_DELAY 10 /* Milliseconds */
87 87 static clock_t rfs4_lock_delay = RFS4_LOCK_DELAY;
88 88 extern struct svc_ops rdma_svc_ops;
89 89 extern int nfs_loaned_buffers;
90 90 /* End of Tunables */
91 91
92 92 static int rdma_setup_read_data4(READ4args *, READ4res *);
93 93
94 94 /*
95 95 * Used to bump the stateid4.seqid value and show changes in the stateid
96 96 */
97 97 #define next_stateid(sp) (++(sp)->bits.chgseq)
98 98
99 99 /*
100 100 * RFS4_MINLEN_ENTRY4: XDR-encoded size of smallest possible dirent.
101 101 * This is used to return NFS4ERR_TOOSMALL when clients specify
102 102 * maxcount that isn't large enough to hold the smallest possible
103 103 * XDR encoded dirent.
104 104 *
105 105 * sizeof cookie (8 bytes) +
106 106 * sizeof name_len (4 bytes) +
107 107 * sizeof smallest (padded) name (4 bytes) +
108 108 * sizeof bitmap4_len (12 bytes) + NOTE: we always encode len=2 bm4
109 109 * sizeof attrlist4_len (4 bytes) +
110 110 * sizeof next boolean (4 bytes)
111 111 *
112 112 * RFS4_MINLEN_RDDIR4: XDR-encoded size of READDIR op reply containing
113 113 * the smallest possible entry4 (assumes no attrs requested).
114 114 * sizeof nfsstat4 (4 bytes) +
115 115 * sizeof verifier4 (8 bytes) +
116 116 * sizeof entry4list bool (4 bytes) +
117 117 * sizeof entry4 (36 bytes) +
118 118 * sizeof eof bool (4 bytes)
119 119 *
120 120 * RFS4_MINLEN_RDDIR_BUF: minimum length of buffer server will provide to
121 121 * VOP_READDIR. Its value is the size of the maximum possible dirent
122 122 * for solaris. The DIRENT64_RECLEN macro returns the size of dirent
123 123 * required for a given name length. MAXNAMELEN is the maximum
124 124 * filename length allowed in Solaris. The first two DIRENT64_RECLEN()
125 125 * macros are to allow for . and .. entries -- just a minor tweak to try
126 126 * and guarantee that buffer we give to VOP_READDIR will be large enough
127 127 * to hold ., .., and the largest possible solaris dirent64.
128 128 */
129 129 #define RFS4_MINLEN_ENTRY4 36
130 130 #define RFS4_MINLEN_RDDIR4 (4 + NFS4_VERIFIER_SIZE + 4 + RFS4_MINLEN_ENTRY4 + 4)
131 131 #define RFS4_MINLEN_RDDIR_BUF \
132 132 (DIRENT64_RECLEN(1) + DIRENT64_RECLEN(2) + DIRENT64_RECLEN(MAXNAMELEN))
133 133
134 134 /*
135 135 * It would be better to pad to 4 bytes since that's what XDR would do,
136 136 * but the dirents UFS gives us are already padded to 8, so just take
137 137 * what we're given. Dircount is only a hint anyway. Currently the
138 138 * solaris kernel is ASCII only, so there's no point in calling the
139 139 * UTF8 functions.
140 140 *
141 141 * dirent64: named padded to provide 8 byte struct alignment
142 142 * d_ino(8) + d_off(8) + d_reclen(2) + d_name(namelen + null(1) + pad)
143 143 *
144 144 * cookie: uint64_t + utf8namelen: uint_t + utf8name padded to 8 bytes
145 145 *
146 146 */
147 147 #define DIRENT64_TO_DIRCOUNT(dp) \
148 148 (3 * BYTES_PER_XDR_UNIT + DIRENT64_NAMELEN((dp)->d_reclen))
149 149
150 150 time_t rfs4_start_time; /* Initialized in rfs4_srvrinit */
151 151
152 152 static sysid_t lockt_sysid; /* dummy sysid for all LOCKT calls */
153 153
154 154 u_longlong_t nfs4_srv_caller_id;
155 155 uint_t nfs4_srv_vkey = 0;
156 156
157 157 verifier4 Write4verf;
158 158 verifier4 Readdir4verf;
159 159
160 160 void rfs4_init_compound_state(struct compound_state *);
161 161
162 162 static void nullfree(caddr_t);
163 163 static void rfs4_op_inval(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
164 164 struct compound_state *);
165 165 static void rfs4_op_access(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
166 166 struct compound_state *);
167 167 static void rfs4_op_close(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
168 168 struct compound_state *);
169 169 static void rfs4_op_commit(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
170 170 struct compound_state *);
171 171 static void rfs4_op_create(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
172 172 struct compound_state *);
173 173 static void rfs4_op_create_free(nfs_resop4 *resop);
174 174 static void rfs4_op_delegreturn(nfs_argop4 *, nfs_resop4 *,
175 175 struct svc_req *, struct compound_state *);
176 176 static void rfs4_op_delegpurge(nfs_argop4 *, nfs_resop4 *,
177 177 struct svc_req *, struct compound_state *);
178 178 static void rfs4_op_getattr(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
179 179 struct compound_state *);
180 180 static void rfs4_op_getattr_free(nfs_resop4 *);
181 181 static void rfs4_op_getfh(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
182 182 struct compound_state *);
183 183 static void rfs4_op_getfh_free(nfs_resop4 *);
184 184 static void rfs4_op_illegal(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
185 185 struct compound_state *);
186 186 static void rfs4_op_link(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
187 187 struct compound_state *);
188 188 static void rfs4_op_lock(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
189 189 struct compound_state *);
190 190 static void lock_denied_free(nfs_resop4 *);
191 191 static void rfs4_op_locku(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
192 192 struct compound_state *);
193 193 static void rfs4_op_lockt(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
194 194 struct compound_state *);
195 195 static void rfs4_op_lookup(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
196 196 struct compound_state *);
197 197 static void rfs4_op_lookupp(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
198 198 struct compound_state *);
199 199 static void rfs4_op_openattr(nfs_argop4 *argop, nfs_resop4 *resop,
200 200 struct svc_req *req, struct compound_state *cs);
201 201 static void rfs4_op_nverify(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
202 202 struct compound_state *);
203 203 static void rfs4_op_open(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
204 204 struct compound_state *);
205 205 static void rfs4_op_open_confirm(nfs_argop4 *, nfs_resop4 *,
206 206 struct svc_req *, struct compound_state *);
207 207 static void rfs4_op_open_downgrade(nfs_argop4 *, nfs_resop4 *,
208 208 struct svc_req *, struct compound_state *);
209 209 static void rfs4_op_putfh(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
210 210 struct compound_state *);
211 211 static void rfs4_op_putpubfh(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
212 212 struct compound_state *);
213 213 static void rfs4_op_putrootfh(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
214 214 struct compound_state *);
215 215 static void rfs4_op_read(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
216 216 struct compound_state *);
217 217 static void rfs4_op_read_free(nfs_resop4 *);
218 218 static void rfs4_op_readdir_free(nfs_resop4 *resop);
219 219 static void rfs4_op_readlink(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
220 220 struct compound_state *);
221 221 static void rfs4_op_readlink_free(nfs_resop4 *);
222 222 static void rfs4_op_release_lockowner(nfs_argop4 *, nfs_resop4 *,
223 223 struct svc_req *, struct compound_state *);
224 224 static void rfs4_op_remove(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
225 225 struct compound_state *);
226 226 static void rfs4_op_rename(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
227 227 struct compound_state *);
228 228 static void rfs4_op_renew(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
229 229 struct compound_state *);
230 230 static void rfs4_op_restorefh(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
231 231 struct compound_state *);
232 232 static void rfs4_op_savefh(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
233 233 struct compound_state *);
234 234 static void rfs4_op_setattr(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
235 235 struct compound_state *);
236 236 static void rfs4_op_verify(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
237 237 struct compound_state *);
238 238 static void rfs4_op_write(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
239 239 struct compound_state *);
240 240 static void rfs4_op_setclientid(nfs_argop4 *, nfs_resop4 *,
241 241 struct svc_req *, struct compound_state *);
242 242 static void rfs4_op_setclientid_confirm(nfs_argop4 *, nfs_resop4 *,
243 243 struct svc_req *req, struct compound_state *);
244 244 static void rfs4_op_secinfo(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
245 245 struct compound_state *);
246 246 static void rfs4_op_secinfo_free(nfs_resop4 *);
247 247
248 248 static nfsstat4 check_open_access(uint32_t,
249 249 struct compound_state *, struct svc_req *);
250 250 nfsstat4 rfs4_client_sysid(rfs4_client_t *, sysid_t *);
251 251 void rfs4_ss_clid(rfs4_client_t *);
252 252
253 253 /*
254 254 * translation table for attrs
255 255 */
256 256 struct nfs4_ntov_table {
257 257 union nfs4_attr_u *na;
258 258 uint8_t amap[NFS4_MAXNUM_ATTRS];
259 259 int attrcnt;
260 260 bool_t vfsstat;
261 261 };
262 262
263 263 static void nfs4_ntov_table_init(struct nfs4_ntov_table *ntovp);
264 264 static void nfs4_ntov_table_free(struct nfs4_ntov_table *ntovp,
265 265 struct nfs4_svgetit_arg *sargp);
266 266
267 267 static nfsstat4 do_rfs4_set_attrs(bitmap4 *resp, fattr4 *fattrp,
268 268 struct compound_state *cs, struct nfs4_svgetit_arg *sargp,
269 269 struct nfs4_ntov_table *ntovp, nfs4_attr_cmd_t cmd);
270 270
271 271 fem_t *deleg_rdops;
272 272 fem_t *deleg_wrops;
273 273
274 274 rfs4_servinst_t *rfs4_cur_servinst = NULL; /* current server instance */
275 275 kmutex_t rfs4_servinst_lock; /* protects linked list */
276 276 int rfs4_seen_first_compound; /* set first time we see one */
277 277
278 278 /*
279 279 * NFS4 op dispatch table
280 280 */
281 281
282 282 struct rfsv4disp {
283 283 void (*dis_proc)(); /* proc to call */
284 284 void (*dis_resfree)(); /* frees space allocated by proc */
285 285 int dis_flags; /* RPC_IDEMPOTENT, etc... */
286 286 };
287 287
288 288 static struct rfsv4disp rfsv4disptab[] = {
289 289 /*
290 290 * NFS VERSION 4
291 291 */
292 292
293 293 /* RFS_NULL = 0 */
294 294 {rfs4_op_illegal, nullfree, 0},
295 295
296 296 /* UNUSED = 1 */
297 297 {rfs4_op_illegal, nullfree, 0},
298 298
299 299 /* UNUSED = 2 */
300 300 {rfs4_op_illegal, nullfree, 0},
301 301
302 302 /* OP_ACCESS = 3 */
303 303 {rfs4_op_access, nullfree, RPC_IDEMPOTENT},
304 304
305 305 /* OP_CLOSE = 4 */
306 306 {rfs4_op_close, nullfree, 0},
307 307
308 308 /* OP_COMMIT = 5 */
309 309 {rfs4_op_commit, nullfree, RPC_IDEMPOTENT},
310 310
311 311 /* OP_CREATE = 6 */
312 312 {rfs4_op_create, nullfree, 0},
313 313
314 314 /* OP_DELEGPURGE = 7 */
315 315 {rfs4_op_delegpurge, nullfree, 0},
316 316
317 317 /* OP_DELEGRETURN = 8 */
318 318 {rfs4_op_delegreturn, nullfree, 0},
319 319
320 320 /* OP_GETATTR = 9 */
321 321 {rfs4_op_getattr, rfs4_op_getattr_free, RPC_IDEMPOTENT},
322 322
323 323 /* OP_GETFH = 10 */
324 324 {rfs4_op_getfh, rfs4_op_getfh_free, RPC_ALL},
325 325
326 326 /* OP_LINK = 11 */
327 327 {rfs4_op_link, nullfree, 0},
328 328
329 329 /* OP_LOCK = 12 */
330 330 {rfs4_op_lock, lock_denied_free, 0},
331 331
332 332 /* OP_LOCKT = 13 */
333 333 {rfs4_op_lockt, lock_denied_free, 0},
334 334
335 335 /* OP_LOCKU = 14 */
336 336 {rfs4_op_locku, nullfree, 0},
337 337
338 338 /* OP_LOOKUP = 15 */
339 339 {rfs4_op_lookup, nullfree, (RPC_IDEMPOTENT | RPC_PUBLICFH_OK)},
340 340
341 341 /* OP_LOOKUPP = 16 */
342 342 {rfs4_op_lookupp, nullfree, (RPC_IDEMPOTENT | RPC_PUBLICFH_OK)},
343 343
344 344 /* OP_NVERIFY = 17 */
345 345 {rfs4_op_nverify, nullfree, RPC_IDEMPOTENT},
346 346
347 347 /* OP_OPEN = 18 */
348 348 {rfs4_op_open, rfs4_free_reply, 0},
349 349
350 350 /* OP_OPENATTR = 19 */
351 351 {rfs4_op_openattr, nullfree, 0},
352 352
353 353 /* OP_OPEN_CONFIRM = 20 */
354 354 {rfs4_op_open_confirm, nullfree, 0},
355 355
356 356 /* OP_OPEN_DOWNGRADE = 21 */
357 357 {rfs4_op_open_downgrade, nullfree, 0},
358 358
359 359 /* OP_OPEN_PUTFH = 22 */
360 360 {rfs4_op_putfh, nullfree, RPC_ALL},
361 361
362 362 /* OP_PUTPUBFH = 23 */
363 363 {rfs4_op_putpubfh, nullfree, RPC_ALL},
364 364
365 365 /* OP_PUTROOTFH = 24 */
366 366 {rfs4_op_putrootfh, nullfree, RPC_ALL},
367 367
368 368 /* OP_READ = 25 */
369 369 {rfs4_op_read, rfs4_op_read_free, RPC_IDEMPOTENT},
370 370
371 371 /* OP_READDIR = 26 */
372 372 {rfs4_op_readdir, rfs4_op_readdir_free, RPC_IDEMPOTENT},
373 373
374 374 /* OP_READLINK = 27 */
375 375 {rfs4_op_readlink, rfs4_op_readlink_free, RPC_IDEMPOTENT},
376 376
377 377 /* OP_REMOVE = 28 */
378 378 {rfs4_op_remove, nullfree, 0},
379 379
380 380 /* OP_RENAME = 29 */
381 381 {rfs4_op_rename, nullfree, 0},
382 382
383 383 /* OP_RENEW = 30 */
384 384 {rfs4_op_renew, nullfree, 0},
385 385
386 386 /* OP_RESTOREFH = 31 */
387 387 {rfs4_op_restorefh, nullfree, RPC_ALL},
388 388
389 389 /* OP_SAVEFH = 32 */
390 390 {rfs4_op_savefh, nullfree, RPC_ALL},
391 391
392 392 /* OP_SECINFO = 33 */
393 393 {rfs4_op_secinfo, rfs4_op_secinfo_free, 0},
394 394
395 395 /* OP_SETATTR = 34 */
396 396 {rfs4_op_setattr, nullfree, 0},
397 397
398 398 /* OP_SETCLIENTID = 35 */
399 399 {rfs4_op_setclientid, nullfree, 0},
400 400
401 401 /* OP_SETCLIENTID_CONFIRM = 36 */
402 402 {rfs4_op_setclientid_confirm, nullfree, 0},
403 403
404 404 /* OP_VERIFY = 37 */
405 405 {rfs4_op_verify, nullfree, RPC_IDEMPOTENT},
406 406
407 407 /* OP_WRITE = 38 */
408 408 {rfs4_op_write, nullfree, 0},
409 409
410 410 /* OP_RELEASE_LOCKOWNER = 39 */
411 411 {rfs4_op_release_lockowner, nullfree, 0},
412 412 };
413 413
414 414 static uint_t rfsv4disp_cnt = sizeof (rfsv4disptab) / sizeof (rfsv4disptab[0]);
415 415
416 416 #define OP_ILLEGAL_IDX (rfsv4disp_cnt)
417 417
418 418 #ifdef DEBUG
419 419
420 420 int rfs4_fillone_debug = 0;
421 421 int rfs4_no_stub_access = 1;
422 422 int rfs4_rddir_debug = 0;
423 423
424 424 static char *rfs4_op_string[] = {
425 425 "rfs4_op_null",
426 426 "rfs4_op_1 unused",
427 427 "rfs4_op_2 unused",
428 428 "rfs4_op_access",
429 429 "rfs4_op_close",
430 430 "rfs4_op_commit",
431 431 "rfs4_op_create",
432 432 "rfs4_op_delegpurge",
433 433 "rfs4_op_delegreturn",
434 434 "rfs4_op_getattr",
435 435 "rfs4_op_getfh",
436 436 "rfs4_op_link",
437 437 "rfs4_op_lock",
438 438 "rfs4_op_lockt",
439 439 "rfs4_op_locku",
440 440 "rfs4_op_lookup",
441 441 "rfs4_op_lookupp",
442 442 "rfs4_op_nverify",
443 443 "rfs4_op_open",
444 444 "rfs4_op_openattr",
445 445 "rfs4_op_open_confirm",
446 446 "rfs4_op_open_downgrade",
447 447 "rfs4_op_putfh",
448 448 "rfs4_op_putpubfh",
449 449 "rfs4_op_putrootfh",
450 450 "rfs4_op_read",
451 451 "rfs4_op_readdir",
452 452 "rfs4_op_readlink",
453 453 "rfs4_op_remove",
454 454 "rfs4_op_rename",
455 455 "rfs4_op_renew",
456 456 "rfs4_op_restorefh",
457 457 "rfs4_op_savefh",
458 458 "rfs4_op_secinfo",
459 459 "rfs4_op_setattr",
460 460 "rfs4_op_setclientid",
461 461 "rfs4_op_setclient_confirm",
462 462 "rfs4_op_verify",
463 463 "rfs4_op_write",
464 464 "rfs4_op_release_lockowner",
465 465 "rfs4_op_illegal"
466 466 };
467 467 #endif
468 468
469 469 void rfs4_ss_chkclid(rfs4_client_t *);
470 470
471 471 extern size_t strlcpy(char *dst, const char *src, size_t dstsize);
472 472
473 473 extern void rfs4_free_fs_locations4(fs_locations4 *);
474 474
475 475 #ifdef nextdp
476 476 #undef nextdp
477 477 #endif
478 478 #define nextdp(dp) ((struct dirent64 *)((char *)(dp) + (dp)->d_reclen))
479 479
480 480 static const fs_operation_def_t nfs4_rd_deleg_tmpl[] = {
481 481 VOPNAME_OPEN, { .femop_open = deleg_rd_open },
482 482 VOPNAME_WRITE, { .femop_write = deleg_rd_write },
483 483 VOPNAME_SETATTR, { .femop_setattr = deleg_rd_setattr },
484 484 VOPNAME_RWLOCK, { .femop_rwlock = deleg_rd_rwlock },
485 485 VOPNAME_SPACE, { .femop_space = deleg_rd_space },
486 486 VOPNAME_SETSECATTR, { .femop_setsecattr = deleg_rd_setsecattr },
487 487 VOPNAME_VNEVENT, { .femop_vnevent = deleg_rd_vnevent },
488 488 NULL, NULL
489 489 };
490 490 static const fs_operation_def_t nfs4_wr_deleg_tmpl[] = {
491 491 VOPNAME_OPEN, { .femop_open = deleg_wr_open },
492 492 VOPNAME_READ, { .femop_read = deleg_wr_read },
493 493 VOPNAME_WRITE, { .femop_write = deleg_wr_write },
494 494 VOPNAME_SETATTR, { .femop_setattr = deleg_wr_setattr },
495 495 VOPNAME_RWLOCK, { .femop_rwlock = deleg_wr_rwlock },
496 496 VOPNAME_SPACE, { .femop_space = deleg_wr_space },
497 497 VOPNAME_SETSECATTR, { .femop_setsecattr = deleg_wr_setsecattr },
498 498 VOPNAME_VNEVENT, { .femop_vnevent = deleg_wr_vnevent },
499 499 NULL, NULL
500 500 };
501 501
502 502 int
503 503 rfs4_srvrinit(void)
504 504 {
505 505 timespec32_t verf;
506 506 int error;
507 507 extern void rfs4_attr_init();
508 508 extern krwlock_t rfs4_deleg_policy_lock;
509 509
510 510 /*
511 511 * The following algorithm attempts to find a unique verifier
512 512 * to be used as the write verifier returned from the server
513 513 * to the client. It is important that this verifier change
514 514 * whenever the server reboots. Of secondary importance, it
515 515 * is important for the verifier to be unique between two
516 516 * different servers.
517 517 *
518 518 * Thus, an attempt is made to use the system hostid and the
519 519 * current time in seconds when the nfssrv kernel module is
520 520 * loaded. It is assumed that an NFS server will not be able
521 521 * to boot and then to reboot in less than a second. If the
522 522 * hostid has not been set, then the current high resolution
523 523 * time is used. This will ensure different verifiers each
524 524 * time the server reboots and minimize the chances that two
525 525 * different servers will have the same verifier.
526 526 * XXX - this is broken on LP64 kernels.
527 527 */
528 528 verf.tv_sec = (time_t)zone_get_hostid(NULL);
529 529 if (verf.tv_sec != 0) {
530 530 verf.tv_nsec = gethrestime_sec();
531 531 } else {
532 532 timespec_t tverf;
533 533
534 534 gethrestime(&tverf);
535 535 verf.tv_sec = (time_t)tverf.tv_sec;
536 536 verf.tv_nsec = tverf.tv_nsec;
537 537 }
538 538
539 539 Write4verf = *(uint64_t *)&verf;
540 540
541 541 rfs4_attr_init();
542 542 mutex_init(&rfs4_deleg_lock, NULL, MUTEX_DEFAULT, NULL);
543 543
544 544 /* Used to manage create/destroy of server state */
545 545 mutex_init(&rfs4_state_lock, NULL, MUTEX_DEFAULT, NULL);
546 546
547 547 /* Used to manage access to server instance linked list */
548 548 mutex_init(&rfs4_servinst_lock, NULL, MUTEX_DEFAULT, NULL);
549 549
550 550 /* Used to manage access to rfs4_deleg_policy */
551 551 rw_init(&rfs4_deleg_policy_lock, NULL, RW_DEFAULT, NULL);
552 552
553 553 error = fem_create("deleg_rdops", nfs4_rd_deleg_tmpl, &deleg_rdops);
554 554 if (error != 0) {
555 555 rfs4_disable_delegation();
556 556 } else {
557 557 error = fem_create("deleg_wrops", nfs4_wr_deleg_tmpl,
558 558 &deleg_wrops);
559 559 if (error != 0) {
560 560 rfs4_disable_delegation();
561 561 fem_free(deleg_rdops);
562 562 }
563 563 }
564 564
565 565 nfs4_srv_caller_id = fs_new_caller_id();
566 566
567 567 lockt_sysid = lm_alloc_sysidt();
568 568
569 569 vsd_create(&nfs4_srv_vkey, NULL);
570 570
571 571 return (0);
572 572 }
573 573
574 574 void
575 575 rfs4_srvrfini(void)
576 576 {
577 577 extern krwlock_t rfs4_deleg_policy_lock;
578 578
579 579 if (lockt_sysid != LM_NOSYSID) {
580 580 lm_free_sysidt(lockt_sysid);
581 581 lockt_sysid = LM_NOSYSID;
582 582 }
583 583
584 584 mutex_destroy(&rfs4_deleg_lock);
585 585 mutex_destroy(&rfs4_state_lock);
586 586 rw_destroy(&rfs4_deleg_policy_lock);
587 587
588 588 fem_free(deleg_rdops);
589 589 fem_free(deleg_wrops);
590 590 }
591 591
592 592 void
593 593 rfs4_init_compound_state(struct compound_state *cs)
594 594 {
595 595 bzero(cs, sizeof (*cs));
596 596 cs->cont = TRUE;
597 597 cs->access = CS_ACCESS_DENIED;
598 598 cs->deleg = FALSE;
599 599 cs->mandlock = FALSE;
600 600 cs->fh.nfs_fh4_val = cs->fhbuf;
601 601 }
602 602
603 603 void
604 604 rfs4_grace_start(rfs4_servinst_t *sip)
605 605 {
606 606 rw_enter(&sip->rwlock, RW_WRITER);
607 607 sip->start_time = (time_t)TICK_TO_SEC(ddi_get_lbolt());
608 608 sip->grace_period = rfs4_grace_period;
609 609 rw_exit(&sip->rwlock);
610 610 }
611 611
612 612 /*
613 613 * returns true if the instance's grace period has never been started
614 614 */
615 615 int
616 616 rfs4_servinst_grace_new(rfs4_servinst_t *sip)
617 617 {
618 618 time_t start_time;
619 619
620 620 rw_enter(&sip->rwlock, RW_READER);
621 621 start_time = sip->start_time;
622 622 rw_exit(&sip->rwlock);
623 623
624 624 return (start_time == 0);
625 625 }
626 626
627 627 /*
628 628 * Indicates if server instance is within the
629 629 * grace period.
630 630 */
631 631 int
632 632 rfs4_servinst_in_grace(rfs4_servinst_t *sip)
633 633 {
634 634 time_t grace_expiry;
635 635
636 636 rw_enter(&sip->rwlock, RW_READER);
637 637 grace_expiry = sip->start_time + sip->grace_period;
638 638 rw_exit(&sip->rwlock);
639 639
640 640 return (((time_t)TICK_TO_SEC(ddi_get_lbolt())) < grace_expiry);
641 641 }
642 642
643 643 int
644 644 rfs4_clnt_in_grace(rfs4_client_t *cp)
645 645 {
646 646 ASSERT(rfs4_dbe_refcnt(cp->rc_dbe) > 0);
647 647
648 648 return (rfs4_servinst_in_grace(cp->rc_server_instance));
649 649 }
650 650
651 651 /*
652 652 * reset all currently active grace periods
653 653 */
654 654 void
655 655 rfs4_grace_reset_all(void)
656 656 {
657 657 rfs4_servinst_t *sip;
658 658
659 659 mutex_enter(&rfs4_servinst_lock);
660 660 for (sip = rfs4_cur_servinst; sip != NULL; sip = sip->prev)
661 661 if (rfs4_servinst_in_grace(sip))
662 662 rfs4_grace_start(sip);
663 663 mutex_exit(&rfs4_servinst_lock);
664 664 }
665 665
666 666 /*
667 667 * start any new instances' grace periods
668 668 */
669 669 void
670 670 rfs4_grace_start_new(void)
671 671 {
672 672 rfs4_servinst_t *sip;
673 673
674 674 mutex_enter(&rfs4_servinst_lock);
675 675 for (sip = rfs4_cur_servinst; sip != NULL; sip = sip->prev)
676 676 if (rfs4_servinst_grace_new(sip))
677 677 rfs4_grace_start(sip);
678 678 mutex_exit(&rfs4_servinst_lock);
679 679 }
680 680
681 681 static rfs4_dss_path_t *
682 682 rfs4_dss_newpath(rfs4_servinst_t *sip, char *path, unsigned index)
683 683 {
684 684 size_t len;
685 685 rfs4_dss_path_t *dss_path;
686 686
687 687 dss_path = kmem_alloc(sizeof (rfs4_dss_path_t), KM_SLEEP);
688 688
689 689 /*
690 690 * Take a copy of the string, since the original may be overwritten.
691 691 * Sadly, no strdup() in the kernel.
692 692 */
693 693 /* allow for NUL */
694 694 len = strlen(path) + 1;
695 695 dss_path->path = kmem_alloc(len, KM_SLEEP);
696 696 (void) strlcpy(dss_path->path, path, len);
697 697
698 698 /* associate with servinst */
699 699 dss_path->sip = sip;
700 700 dss_path->index = index;
701 701
702 702 /*
703 703 * Add to list of served paths.
704 704 * No locking required, as we're only ever called at startup.
705 705 */
706 706 if (rfs4_dss_pathlist == NULL) {
707 707 /* this is the first dss_path_t */
708 708
709 709 /* needed for insque/remque */
710 710 dss_path->next = dss_path->prev = dss_path;
711 711
712 712 rfs4_dss_pathlist = dss_path;
713 713 } else {
714 714 insque(dss_path, rfs4_dss_pathlist);
715 715 }
716 716
717 717 return (dss_path);
718 718 }
719 719
720 720 /*
721 721 * Create a new server instance, and make it the currently active instance.
722 722 * Note that starting the grace period too early will reduce the clients'
723 723 * recovery window.
724 724 */
725 725 void
726 726 rfs4_servinst_create(int start_grace, int dss_npaths, char **dss_paths)
727 727 {
728 728 unsigned i;
729 729 rfs4_servinst_t *sip;
730 730 rfs4_oldstate_t *oldstate;
731 731
732 732 sip = kmem_alloc(sizeof (rfs4_servinst_t), KM_SLEEP);
733 733 rw_init(&sip->rwlock, NULL, RW_DEFAULT, NULL);
734 734
735 735 sip->start_time = (time_t)0;
736 736 sip->grace_period = (time_t)0;
737 737 sip->next = NULL;
738 738 sip->prev = NULL;
739 739
740 740 rw_init(&sip->oldstate_lock, NULL, RW_DEFAULT, NULL);
741 741 /*
742 742 * This initial dummy entry is required to setup for insque/remque.
743 743 * It must be skipped over whenever the list is traversed.
744 744 */
745 745 oldstate = kmem_alloc(sizeof (rfs4_oldstate_t), KM_SLEEP);
746 746 /* insque/remque require initial list entry to be self-terminated */
747 747 oldstate->next = oldstate;
748 748 oldstate->prev = oldstate;
749 749 sip->oldstate = oldstate;
750 750
751 751
752 752 sip->dss_npaths = dss_npaths;
753 753 sip->dss_paths = kmem_alloc(dss_npaths *
754 754 sizeof (rfs4_dss_path_t *), KM_SLEEP);
755 755
756 756 for (i = 0; i < dss_npaths; i++) {
757 757 sip->dss_paths[i] = rfs4_dss_newpath(sip, dss_paths[i], i);
758 758 }
759 759
760 760 mutex_enter(&rfs4_servinst_lock);
761 761 if (rfs4_cur_servinst != NULL) {
762 762 /* add to linked list */
763 763 sip->prev = rfs4_cur_servinst;
764 764 rfs4_cur_servinst->next = sip;
765 765 }
766 766 if (start_grace)
767 767 rfs4_grace_start(sip);
768 768 /* make the new instance "current" */
769 769 rfs4_cur_servinst = sip;
770 770
771 771 mutex_exit(&rfs4_servinst_lock);
772 772 }
773 773
774 774 /*
775 775 * In future, we might add a rfs4_servinst_destroy(sip) but, for now, destroy
776 776 * all instances directly.
777 777 */
778 778 void
779 779 rfs4_servinst_destroy_all(void)
780 780 {
781 781 rfs4_servinst_t *sip, *prev, *current;
782 782 #ifdef DEBUG
783 783 int n = 0;
784 784 #endif
785 785
786 786 mutex_enter(&rfs4_servinst_lock);
787 787 ASSERT(rfs4_cur_servinst != NULL);
788 788 current = rfs4_cur_servinst;
789 789 rfs4_cur_servinst = NULL;
790 790 for (sip = current; sip != NULL; sip = prev) {
791 791 prev = sip->prev;
792 792 rw_destroy(&sip->rwlock);
793 793 if (sip->oldstate)
794 794 kmem_free(sip->oldstate, sizeof (rfs4_oldstate_t));
795 795 if (sip->dss_paths)
796 796 kmem_free(sip->dss_paths,
797 797 sip->dss_npaths * sizeof (rfs4_dss_path_t *));
798 798 kmem_free(sip, sizeof (rfs4_servinst_t));
799 799 #ifdef DEBUG
800 800 n++;
801 801 #endif
802 802 }
803 803 mutex_exit(&rfs4_servinst_lock);
804 804 }
805 805
806 806 /*
807 807 * Assign the current server instance to a client_t.
808 808 * Should be called with cp->rc_dbe held.
809 809 */
810 810 void
811 811 rfs4_servinst_assign(rfs4_client_t *cp, rfs4_servinst_t *sip)
812 812 {
813 813 ASSERT(rfs4_dbe_refcnt(cp->rc_dbe) > 0);
814 814
815 815 /*
816 816 * The lock ensures that if the current instance is in the process
817 817 * of changing, we will see the new one.
818 818 */
819 819 mutex_enter(&rfs4_servinst_lock);
820 820 cp->rc_server_instance = sip;
821 821 mutex_exit(&rfs4_servinst_lock);
822 822 }
823 823
824 824 rfs4_servinst_t *
825 825 rfs4_servinst(rfs4_client_t *cp)
826 826 {
827 827 ASSERT(rfs4_dbe_refcnt(cp->rc_dbe) > 0);
828 828
829 829 return (cp->rc_server_instance);
830 830 }
831 831
832 832 /* ARGSUSED */
833 833 static void
834 834 nullfree(caddr_t resop)
835 835 {
836 836 }
837 837
838 838 /*
839 839 * This is a fall-through for invalid or not implemented (yet) ops
840 840 */
841 841 /* ARGSUSED */
842 842 static void
843 843 rfs4_op_inval(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
844 844 struct compound_state *cs)
845 845 {
846 846 *cs->statusp = *((nfsstat4 *)&(resop)->nfs_resop4_u) = NFS4ERR_INVAL;
847 847 }
848 848
849 849 /*
850 850 * Check if the security flavor, nfsnum, is in the flavor_list.
851 851 */
852 852 bool_t
853 853 in_flavor_list(int nfsnum, int *flavor_list, int count)
854 854 {
855 855 int i;
856 856
857 857 for (i = 0; i < count; i++) {
858 858 if (nfsnum == flavor_list[i])
859 859 return (TRUE);
860 860 }
861 861 return (FALSE);
862 862 }
863 863
864 864 /*
↓ open down ↓ |
864 lines elided |
↑ open up ↑ |
865 865 * Used by rfs4_op_secinfo to get the security information from the
866 866 * export structure associated with the component.
867 867 */
868 868 /* ARGSUSED */
869 869 static nfsstat4
870 870 do_rfs4_op_secinfo(struct compound_state *cs, char *nm, SECINFO4res *resp)
871 871 {
872 872 int error, different_export = 0;
873 873 vnode_t *dvp, *vp;
874 874 struct exportinfo *exi = NULL;
875 + struct exportinfo *oexi = NULL;
875 876 fid_t fid;
876 877 uint_t count, i;
877 878 secinfo4 *resok_val;
878 879 struct secinfo *secp;
879 880 seconfig_t *si;
880 881 bool_t did_traverse = FALSE;
881 882 int dotdot, walk;
882 883
883 884 dvp = cs->vp;
884 885 dotdot = (nm[0] == '.' && nm[1] == '.' && nm[2] == '\0');
885 886
886 887 /*
887 888 * If dotdotting, then need to check whether it's above the
888 889 * root of a filesystem, or above an export point.
889 890 */
890 891 if (dotdot) {
891 892
892 893 /*
893 894 * If dotdotting at the root of a filesystem, then
894 895 * need to traverse back to the mounted-on filesystem
895 896 * and do the dotdot lookup there.
896 897 */
897 898 if (cs->vp->v_flag & VROOT) {
898 899
899 900 /*
900 901 * If at the system root, then can
901 902 * go up no further.
902 903 */
903 904 if (VN_CMP(dvp, rootdir))
904 905 return (puterrno4(ENOENT));
905 906
906 907 /*
907 908 * Traverse back to the mounted-on filesystem
908 909 */
909 910 dvp = untraverse(cs->vp);
910 911
911 912 /*
912 913 * Set the different_export flag so we remember
913 914 * to pick up a new exportinfo entry for
914 915 * this new filesystem.
915 916 */
916 917 different_export = 1;
917 918 } else {
918 919
919 920 /*
920 921 * If dotdotting above an export point then set
921 922 * the different_export to get new export info.
922 923 */
923 924 different_export = nfs_exported(cs->exi, cs->vp);
924 925 }
925 926 }
926 927
927 928 /*
928 929 * Get the vnode for the component "nm".
929 930 */
930 931 error = VOP_LOOKUP(dvp, nm, &vp, NULL, 0, NULL, cs->cr,
931 932 NULL, NULL, NULL);
932 933 if (error)
933 934 return (puterrno4(error));
934 935
935 936 /*
936 937 * If the vnode is in a pseudo filesystem, or if the security flavor
937 938 * used in the request is valid but not an explicitly shared flavor,
938 939 * or the access bit indicates that this is a limited access,
939 940 * check whether this vnode is visible.
940 941 */
941 942 if (!different_export &&
942 943 (PSEUDO(cs->exi) || ! is_exported_sec(cs->nfsflavor, cs->exi) ||
943 944 cs->access & CS_ACCESS_LIMITED)) {
944 945 if (! nfs_visible(cs->exi, vp, &different_export)) {
945 946 VN_RELE(vp);
946 947 return (puterrno4(ENOENT));
947 948 }
948 949 }
949 950
950 951 /*
951 952 * If it's a mountpoint, then traverse it.
952 953 */
953 954 if (vn_ismntpt(vp)) {
954 955 if ((error = traverse(&vp)) != 0) {
955 956 VN_RELE(vp);
↓ open down ↓ |
71 lines elided |
↑ open up ↑ |
956 957 return (puterrno4(error));
957 958 }
958 959 /* remember that we had to traverse mountpoint */
959 960 did_traverse = TRUE;
960 961 different_export = 1;
961 962 } else if (vp->v_vfsp != dvp->v_vfsp) {
962 963 /*
963 964 * If vp isn't a mountpoint and the vfs ptrs aren't the same,
964 965 * then vp is probably an LOFS object. We don't need the
965 966 * realvp, we just need to know that we might have crossed
966 - * a server fs boundary and need to call checkexport4.
967 + * a server fs boundary and need to call checkexport.
967 968 * (LOFS lookup hides server fs mountpoints, and actually calls
968 969 * traverse)
969 970 */
970 971 different_export = 1;
971 972 }
972 973
973 974 /*
974 975 * Get the export information for it.
975 976 */
976 977 if (different_export) {
977 978
978 979 bzero(&fid, sizeof (fid));
979 980 fid.fid_len = MAXFIDSZ;
980 981 error = vop_fid_pseudo(vp, &fid);
981 982 if (error) {
982 983 VN_RELE(vp);
983 984 return (puterrno4(error));
984 985 }
985 986
986 987 if (dotdot)
987 - exi = nfs_vptoexi(NULL, vp, cs->cr, &walk, NULL, TRUE);
988 + oexi = nfs_vptoexi(NULL, vp, cs->cr, &walk, NULL, TRUE);
988 989 else
989 - exi = checkexport4(&vp->v_vfsp->vfs_fsid, &fid, vp);
990 + oexi = checkexport(&vp->v_vfsp->vfs_fsid, &fid, vp);
990 991
991 - if (exi == NULL) {
992 + if (oexi == NULL) {
992 993 if (did_traverse == TRUE) {
993 994 /*
994 995 * If this vnode is a mounted-on vnode,
995 996 * but the mounted-on file system is not
996 997 * exported, send back the secinfo for
997 998 * the exported node that the mounted-on
998 999 * vnode lives in.
999 1000 */
1000 1001 exi = cs->exi;
1001 1002 } else {
1002 1003 VN_RELE(vp);
1003 1004 return (puterrno4(EACCES));
1004 1005 }
1006 + } else {
1007 + exi = oexi;
1005 1008 }
1006 1009 } else {
1007 1010 exi = cs->exi;
1008 1011 }
1009 1012 ASSERT(exi != NULL);
1010 1013
1011 1014
1012 1015 /*
1013 1016 * Create the secinfo result based on the security information
1014 1017 * from the exportinfo structure (exi).
1015 1018 *
1016 1019 * Return all flavors for a pseudo node.
1017 1020 * For a real export node, return the flavor that the client
1018 1021 * has access with.
1019 1022 */
1020 - ASSERT(RW_LOCK_HELD(&exported_lock));
1023 + rw_enter(&exported_lock, RW_READER);
1021 1024 if (PSEUDO(exi)) {
1022 1025 count = exi->exi_export.ex_seccnt; /* total sec count */
1023 1026 resok_val = kmem_alloc(count * sizeof (secinfo4), KM_SLEEP);
1024 1027 secp = exi->exi_export.ex_secinfo;
1025 1028
1026 1029 for (i = 0; i < count; i++) {
1027 1030 si = &secp[i].s_secinfo;
1028 1031 resok_val[i].flavor = si->sc_rpcnum;
1029 1032 if (resok_val[i].flavor == RPCSEC_GSS) {
1030 1033 rpcsec_gss_info *info;
1031 1034
1032 1035 info = &resok_val[i].flavor_info;
1033 1036 info->qop = si->sc_qop;
1034 1037 info->service = (rpc_gss_svc_t)si->sc_service;
1035 1038
1036 1039 /* get oid opaque data */
1037 1040 info->oid.sec_oid4_len =
1038 1041 si->sc_gss_mech_type->length;
1039 1042 info->oid.sec_oid4_val = kmem_alloc(
1040 1043 si->sc_gss_mech_type->length, KM_SLEEP);
1041 1044 bcopy(
1042 1045 si->sc_gss_mech_type->elements,
1043 1046 info->oid.sec_oid4_val,
1044 1047 info->oid.sec_oid4_len);
1045 1048 }
1046 1049 }
1047 1050 resp->SECINFO4resok_len = count;
1048 1051 resp->SECINFO4resok_val = resok_val;
1049 1052 } else {
1050 1053 int ret_cnt = 0, k = 0;
1051 1054 int *flavor_list;
1052 1055
1053 1056 count = exi->exi_export.ex_seccnt; /* total sec count */
1054 1057 secp = exi->exi_export.ex_secinfo;
1055 1058
1056 1059 flavor_list = kmem_alloc(count * sizeof (int), KM_SLEEP);
1057 1060 /* find out which flavors to return */
1058 1061 for (i = 0; i < count; i ++) {
1059 1062 int access, flavor, perm;
1060 1063
1061 1064 flavor = secp[i].s_secinfo.sc_nfsnum;
1062 1065 perm = secp[i].s_flags;
1063 1066
1064 1067 access = nfsauth4_secinfo_access(exi, cs->req,
1065 1068 flavor, perm, cs->basecr);
1066 1069
1067 1070 if (! (access & NFSAUTH_DENIED) &&
1068 1071 ! (access & NFSAUTH_WRONGSEC)) {
1069 1072 flavor_list[ret_cnt] = flavor;
1070 1073 ret_cnt++;
1071 1074 }
1072 1075 }
1073 1076
1074 1077 /* Create the returning SECINFO value */
1075 1078 resok_val = kmem_alloc(ret_cnt * sizeof (secinfo4), KM_SLEEP);
1076 1079
1077 1080 for (i = 0; i < count; i++) {
1078 1081 /*
1079 1082 * If the flavor is in the flavor list,
1080 1083 * fill in resok_val.
1081 1084 */
1082 1085 si = &secp[i].s_secinfo;
1083 1086 if (in_flavor_list(si->sc_nfsnum,
1084 1087 flavor_list, ret_cnt)) {
1085 1088 resok_val[k].flavor = si->sc_rpcnum;
1086 1089 if (resok_val[k].flavor == RPCSEC_GSS) {
1087 1090 rpcsec_gss_info *info;
1088 1091
1089 1092 info = &resok_val[k].flavor_info;
1090 1093 info->qop = si->sc_qop;
1091 1094 info->service = (rpc_gss_svc_t)
1092 1095 si->sc_service;
1093 1096
1094 1097 /* get oid opaque data */
1095 1098 info->oid.sec_oid4_len =
1096 1099 si->sc_gss_mech_type->length;
1097 1100 info->oid.sec_oid4_val = kmem_alloc(
1098 1101 si->sc_gss_mech_type->length,
1099 1102 KM_SLEEP);
1100 1103 bcopy(si->sc_gss_mech_type->elements,
1101 1104 info->oid.sec_oid4_val,
1102 1105 info->oid.sec_oid4_len);
↓ open down ↓ |
72 lines elided |
↑ open up ↑ |
1103 1106 }
1104 1107 k++;
1105 1108 }
1106 1109 if (k >= ret_cnt)
1107 1110 break;
1108 1111 }
1109 1112 resp->SECINFO4resok_len = ret_cnt;
1110 1113 resp->SECINFO4resok_val = resok_val;
1111 1114 kmem_free(flavor_list, count * sizeof (int));
1112 1115 }
1113 -
1116 + rw_exit(&exported_lock);
1117 + if (oexi)
1118 + exi_rele(oexi);
1114 1119 VN_RELE(vp);
1115 1120 return (NFS4_OK);
1116 1121 }
1117 1122
1118 1123 /*
1119 1124 * SECINFO (Operation 33): Obtain required security information on
1120 1125 * the component name in the format of (security-mechanism-oid, qop, service)
1121 1126 * triplets.
1122 1127 */
1123 1128 /* ARGSUSED */
1124 1129 static void
1125 1130 rfs4_op_secinfo(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
1126 1131 struct compound_state *cs)
1127 1132 {
1128 1133 SECINFO4args *args = &argop->nfs_argop4_u.opsecinfo;
1129 1134 SECINFO4res *resp = &resop->nfs_resop4_u.opsecinfo;
1130 1135 utf8string *utfnm = &args->name;
1131 1136 uint_t len;
1132 1137 char *nm;
1133 1138 struct sockaddr *ca;
1134 1139 char *name = NULL;
1135 1140 nfsstat4 status = NFS4_OK;
1136 1141
1137 1142 DTRACE_NFSV4_2(op__secinfo__start, struct compound_state *, cs,
1138 1143 SECINFO4args *, args);
1139 1144
1140 1145 /*
1141 1146 * Current file handle (cfh) should have been set before getting
1142 1147 * into this function. If not, return error.
1143 1148 */
1144 1149 if (cs->vp == NULL) {
1145 1150 *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
1146 1151 goto out;
1147 1152 }
1148 1153
1149 1154 if (cs->vp->v_type != VDIR) {
1150 1155 *cs->statusp = resp->status = NFS4ERR_NOTDIR;
1151 1156 goto out;
1152 1157 }
1153 1158
1154 1159 /*
1155 1160 * Verify the component name. If failed, error out, but
1156 1161 * do not error out if the component name is a "..".
1157 1162 * SECINFO will return its parents secinfo data for SECINFO "..".
1158 1163 */
1159 1164 status = utf8_dir_verify(utfnm);
1160 1165 if (status != NFS4_OK) {
1161 1166 if (utfnm->utf8string_len != 2 ||
1162 1167 utfnm->utf8string_val[0] != '.' ||
1163 1168 utfnm->utf8string_val[1] != '.') {
1164 1169 *cs->statusp = resp->status = status;
1165 1170 goto out;
1166 1171 }
1167 1172 }
1168 1173
1169 1174 nm = utf8_to_str(utfnm, &len, NULL);
1170 1175 if (nm == NULL) {
1171 1176 *cs->statusp = resp->status = NFS4ERR_INVAL;
1172 1177 goto out;
1173 1178 }
1174 1179
1175 1180 if (len > MAXNAMELEN) {
1176 1181 *cs->statusp = resp->status = NFS4ERR_NAMETOOLONG;
1177 1182 kmem_free(nm, len);
1178 1183 goto out;
1179 1184 }
1180 1185
1181 1186 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
1182 1187 name = nfscmd_convname(ca, cs->exi, nm, NFSCMD_CONV_INBOUND,
1183 1188 MAXPATHLEN + 1);
1184 1189
1185 1190 if (name == NULL) {
1186 1191 *cs->statusp = resp->status = NFS4ERR_INVAL;
1187 1192 kmem_free(nm, len);
1188 1193 goto out;
1189 1194 }
1190 1195
1191 1196
1192 1197 *cs->statusp = resp->status = do_rfs4_op_secinfo(cs, name, resp);
1193 1198
1194 1199 if (name != nm)
1195 1200 kmem_free(name, MAXPATHLEN + 1);
1196 1201 kmem_free(nm, len);
1197 1202
1198 1203 out:
1199 1204 DTRACE_NFSV4_2(op__secinfo__done, struct compound_state *, cs,
1200 1205 SECINFO4res *, resp);
1201 1206 }
1202 1207
1203 1208 /*
1204 1209 * Free SECINFO result.
1205 1210 */
1206 1211 /* ARGSUSED */
1207 1212 static void
1208 1213 rfs4_op_secinfo_free(nfs_resop4 *resop)
1209 1214 {
1210 1215 SECINFO4res *resp = &resop->nfs_resop4_u.opsecinfo;
1211 1216 int count, i;
1212 1217 secinfo4 *resok_val;
1213 1218
1214 1219 /* If this is not an Ok result, nothing to free. */
1215 1220 if (resp->status != NFS4_OK) {
1216 1221 return;
1217 1222 }
1218 1223
1219 1224 count = resp->SECINFO4resok_len;
1220 1225 resok_val = resp->SECINFO4resok_val;
1221 1226
1222 1227 for (i = 0; i < count; i++) {
1223 1228 if (resok_val[i].flavor == RPCSEC_GSS) {
1224 1229 rpcsec_gss_info *info;
1225 1230
1226 1231 info = &resok_val[i].flavor_info;
1227 1232 kmem_free(info->oid.sec_oid4_val,
1228 1233 info->oid.sec_oid4_len);
1229 1234 }
1230 1235 }
1231 1236 kmem_free(resok_val, count * sizeof (secinfo4));
1232 1237 resp->SECINFO4resok_len = 0;
1233 1238 resp->SECINFO4resok_val = NULL;
1234 1239 }
1235 1240
1236 1241 /* ARGSUSED */
1237 1242 static void
1238 1243 rfs4_op_access(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
1239 1244 struct compound_state *cs)
1240 1245 {
1241 1246 ACCESS4args *args = &argop->nfs_argop4_u.opaccess;
1242 1247 ACCESS4res *resp = &resop->nfs_resop4_u.opaccess;
1243 1248 int error;
1244 1249 vnode_t *vp;
1245 1250 struct vattr va;
1246 1251 int checkwriteperm;
1247 1252 cred_t *cr = cs->cr;
1248 1253 bslabel_t *clabel, *slabel;
1249 1254 ts_label_t *tslabel;
1250 1255 boolean_t admin_low_client;
1251 1256
1252 1257 DTRACE_NFSV4_2(op__access__start, struct compound_state *, cs,
1253 1258 ACCESS4args *, args);
1254 1259
1255 1260 #if 0 /* XXX allow access even if !cs->access. Eventually only pseudo fs */
1256 1261 if (cs->access == CS_ACCESS_DENIED) {
1257 1262 *cs->statusp = resp->status = NFS4ERR_ACCESS;
1258 1263 goto out;
1259 1264 }
1260 1265 #endif
1261 1266 if (cs->vp == NULL) {
1262 1267 *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
1263 1268 goto out;
1264 1269 }
1265 1270
1266 1271 ASSERT(cr != NULL);
1267 1272
1268 1273 vp = cs->vp;
1269 1274
1270 1275 /*
1271 1276 * If the file system is exported read only, it is not appropriate
1272 1277 * to check write permissions for regular files and directories.
1273 1278 * Special files are interpreted by the client, so the underlying
1274 1279 * permissions are sent back to the client for interpretation.
1275 1280 */
1276 1281 if (rdonly4(req, cs) &&
1277 1282 (vp->v_type == VREG || vp->v_type == VDIR))
1278 1283 checkwriteperm = 0;
1279 1284 else
1280 1285 checkwriteperm = 1;
1281 1286
1282 1287 /*
1283 1288 * XXX
1284 1289 * We need the mode so that we can correctly determine access
1285 1290 * permissions relative to a mandatory lock file. Access to
1286 1291 * mandatory lock files is denied on the server, so it might
1287 1292 * as well be reflected to the server during the open.
1288 1293 */
1289 1294 va.va_mask = AT_MODE;
1290 1295 error = VOP_GETATTR(vp, &va, 0, cr, NULL);
1291 1296 if (error) {
1292 1297 *cs->statusp = resp->status = puterrno4(error);
1293 1298 goto out;
1294 1299 }
1295 1300 resp->access = 0;
1296 1301 resp->supported = 0;
1297 1302
1298 1303 if (is_system_labeled()) {
1299 1304 ASSERT(req->rq_label != NULL);
1300 1305 clabel = req->rq_label;
1301 1306 DTRACE_PROBE2(tx__rfs4__log__info__opaccess__clabel, char *,
1302 1307 "got client label from request(1)",
1303 1308 struct svc_req *, req);
1304 1309 if (!blequal(&l_admin_low->tsl_label, clabel)) {
1305 1310 if ((tslabel = nfs_getflabel(vp, cs->exi)) == NULL) {
1306 1311 *cs->statusp = resp->status = puterrno4(EACCES);
1307 1312 goto out;
1308 1313 }
1309 1314 slabel = label2bslabel(tslabel);
1310 1315 DTRACE_PROBE3(tx__rfs4__log__info__opaccess__slabel,
1311 1316 char *, "got server label(1) for vp(2)",
1312 1317 bslabel_t *, slabel, vnode_t *, vp);
1313 1318
1314 1319 admin_low_client = B_FALSE;
1315 1320 } else
1316 1321 admin_low_client = B_TRUE;
1317 1322 }
1318 1323
1319 1324 if (args->access & ACCESS4_READ) {
1320 1325 error = VOP_ACCESS(vp, VREAD, 0, cr, NULL);
1321 1326 if (!error && !MANDLOCK(vp, va.va_mode) &&
1322 1327 (!is_system_labeled() || admin_low_client ||
1323 1328 bldominates(clabel, slabel)))
1324 1329 resp->access |= ACCESS4_READ;
1325 1330 resp->supported |= ACCESS4_READ;
1326 1331 }
1327 1332 if ((args->access & ACCESS4_LOOKUP) && vp->v_type == VDIR) {
1328 1333 error = VOP_ACCESS(vp, VEXEC, 0, cr, NULL);
1329 1334 if (!error && (!is_system_labeled() || admin_low_client ||
1330 1335 bldominates(clabel, slabel)))
1331 1336 resp->access |= ACCESS4_LOOKUP;
1332 1337 resp->supported |= ACCESS4_LOOKUP;
1333 1338 }
1334 1339 if (checkwriteperm &&
1335 1340 (args->access & (ACCESS4_MODIFY|ACCESS4_EXTEND))) {
1336 1341 error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL);
1337 1342 if (!error && !MANDLOCK(vp, va.va_mode) &&
1338 1343 (!is_system_labeled() || admin_low_client ||
1339 1344 blequal(clabel, slabel)))
1340 1345 resp->access |=
1341 1346 (args->access & (ACCESS4_MODIFY | ACCESS4_EXTEND));
1342 1347 resp->supported |=
1343 1348 resp->access & (ACCESS4_MODIFY | ACCESS4_EXTEND);
1344 1349 }
1345 1350
1346 1351 if (checkwriteperm &&
1347 1352 (args->access & ACCESS4_DELETE) && vp->v_type == VDIR) {
1348 1353 error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL);
1349 1354 if (!error && (!is_system_labeled() || admin_low_client ||
1350 1355 blequal(clabel, slabel)))
1351 1356 resp->access |= ACCESS4_DELETE;
1352 1357 resp->supported |= ACCESS4_DELETE;
1353 1358 }
1354 1359 if (args->access & ACCESS4_EXECUTE && vp->v_type != VDIR) {
1355 1360 error = VOP_ACCESS(vp, VEXEC, 0, cr, NULL);
1356 1361 if (!error && !MANDLOCK(vp, va.va_mode) &&
1357 1362 (!is_system_labeled() || admin_low_client ||
1358 1363 bldominates(clabel, slabel)))
1359 1364 resp->access |= ACCESS4_EXECUTE;
1360 1365 resp->supported |= ACCESS4_EXECUTE;
1361 1366 }
1362 1367
1363 1368 if (is_system_labeled() && !admin_low_client)
1364 1369 label_rele(tslabel);
1365 1370
1366 1371 *cs->statusp = resp->status = NFS4_OK;
1367 1372 out:
1368 1373 DTRACE_NFSV4_2(op__access__done, struct compound_state *, cs,
1369 1374 ACCESS4res *, resp);
1370 1375 }
1371 1376
1372 1377 /* ARGSUSED */
1373 1378 static void
1374 1379 rfs4_op_commit(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
1375 1380 struct compound_state *cs)
1376 1381 {
1377 1382 COMMIT4args *args = &argop->nfs_argop4_u.opcommit;
1378 1383 COMMIT4res *resp = &resop->nfs_resop4_u.opcommit;
1379 1384 int error;
1380 1385 vnode_t *vp = cs->vp;
1381 1386 cred_t *cr = cs->cr;
1382 1387 vattr_t va;
1383 1388
1384 1389 DTRACE_NFSV4_2(op__commit__start, struct compound_state *, cs,
1385 1390 COMMIT4args *, args);
1386 1391
1387 1392 if (vp == NULL) {
1388 1393 *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
1389 1394 goto out;
1390 1395 }
1391 1396 if (cs->access == CS_ACCESS_DENIED) {
1392 1397 *cs->statusp = resp->status = NFS4ERR_ACCESS;
1393 1398 goto out;
1394 1399 }
1395 1400
1396 1401 if (args->offset + args->count < args->offset) {
1397 1402 *cs->statusp = resp->status = NFS4ERR_INVAL;
1398 1403 goto out;
1399 1404 }
1400 1405
1401 1406 va.va_mask = AT_UID;
1402 1407 error = VOP_GETATTR(vp, &va, 0, cr, NULL);
1403 1408
1404 1409 /*
1405 1410 * If we can't get the attributes, then we can't do the
1406 1411 * right access checking. So, we'll fail the request.
1407 1412 */
1408 1413 if (error) {
1409 1414 *cs->statusp = resp->status = puterrno4(error);
1410 1415 goto out;
1411 1416 }
1412 1417 if (rdonly4(req, cs)) {
1413 1418 *cs->statusp = resp->status = NFS4ERR_ROFS;
1414 1419 goto out;
1415 1420 }
1416 1421
1417 1422 if (vp->v_type != VREG) {
1418 1423 if (vp->v_type == VDIR)
1419 1424 resp->status = NFS4ERR_ISDIR;
1420 1425 else
1421 1426 resp->status = NFS4ERR_INVAL;
1422 1427 *cs->statusp = resp->status;
1423 1428 goto out;
1424 1429 }
1425 1430
1426 1431 if (crgetuid(cr) != va.va_uid &&
1427 1432 (error = VOP_ACCESS(vp, VWRITE, 0, cs->cr, NULL))) {
1428 1433 *cs->statusp = resp->status = puterrno4(error);
1429 1434 goto out;
1430 1435 }
1431 1436
1432 1437 error = VOP_FSYNC(vp, FSYNC, cr, NULL);
1433 1438
1434 1439 if (error) {
1435 1440 *cs->statusp = resp->status = puterrno4(error);
1436 1441 goto out;
1437 1442 }
1438 1443
1439 1444 *cs->statusp = resp->status = NFS4_OK;
1440 1445 resp->writeverf = Write4verf;
1441 1446 out:
1442 1447 DTRACE_NFSV4_2(op__commit__done, struct compound_state *, cs,
1443 1448 COMMIT4res *, resp);
1444 1449 }
1445 1450
1446 1451 /*
1447 1452 * rfs4_op_mknod is called from rfs4_op_create after all initial verification
1448 1453 * was completed. It does the nfsv4 create for special files.
1449 1454 */
1450 1455 /* ARGSUSED */
1451 1456 static vnode_t *
1452 1457 do_rfs4_op_mknod(CREATE4args *args, CREATE4res *resp, struct svc_req *req,
1453 1458 struct compound_state *cs, vattr_t *vap, char *nm)
1454 1459 {
1455 1460 int error;
1456 1461 cred_t *cr = cs->cr;
1457 1462 vnode_t *dvp = cs->vp;
1458 1463 vnode_t *vp = NULL;
1459 1464 int mode;
1460 1465 enum vcexcl excl;
1461 1466
1462 1467 switch (args->type) {
1463 1468 case NF4CHR:
1464 1469 case NF4BLK:
1465 1470 if (secpolicy_sys_devices(cr) != 0) {
1466 1471 *cs->statusp = resp->status = NFS4ERR_PERM;
1467 1472 return (NULL);
1468 1473 }
1469 1474 if (args->type == NF4CHR)
1470 1475 vap->va_type = VCHR;
1471 1476 else
1472 1477 vap->va_type = VBLK;
1473 1478 vap->va_rdev = makedevice(args->ftype4_u.devdata.specdata1,
1474 1479 args->ftype4_u.devdata.specdata2);
1475 1480 vap->va_mask |= AT_RDEV;
1476 1481 break;
1477 1482 case NF4SOCK:
1478 1483 vap->va_type = VSOCK;
1479 1484 break;
1480 1485 case NF4FIFO:
1481 1486 vap->va_type = VFIFO;
1482 1487 break;
1483 1488 default:
1484 1489 *cs->statusp = resp->status = NFS4ERR_BADTYPE;
1485 1490 return (NULL);
1486 1491 }
1487 1492
1488 1493 /*
1489 1494 * Must specify the mode.
1490 1495 */
1491 1496 if (!(vap->va_mask & AT_MODE)) {
1492 1497 *cs->statusp = resp->status = NFS4ERR_INVAL;
1493 1498 return (NULL);
1494 1499 }
1495 1500
1496 1501 excl = EXCL;
1497 1502
1498 1503 mode = 0;
1499 1504
1500 1505 error = VOP_CREATE(dvp, nm, vap, excl, mode, &vp, cr, 0, NULL, NULL);
1501 1506 if (error) {
1502 1507 *cs->statusp = resp->status = puterrno4(error);
1503 1508 return (NULL);
1504 1509 }
1505 1510 return (vp);
1506 1511 }
1507 1512
1508 1513 /*
1509 1514 * nfsv4 create is used to create non-regular files. For regular files,
1510 1515 * use nfsv4 open.
1511 1516 */
1512 1517 /* ARGSUSED */
1513 1518 static void
1514 1519 rfs4_op_create(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
1515 1520 struct compound_state *cs)
1516 1521 {
1517 1522 CREATE4args *args = &argop->nfs_argop4_u.opcreate;
1518 1523 CREATE4res *resp = &resop->nfs_resop4_u.opcreate;
1519 1524 int error;
1520 1525 struct vattr bva, iva, iva2, ava, *vap;
1521 1526 cred_t *cr = cs->cr;
1522 1527 vnode_t *dvp = cs->vp;
1523 1528 vnode_t *vp = NULL;
1524 1529 vnode_t *realvp;
1525 1530 char *nm, *lnm;
1526 1531 uint_t len, llen;
1527 1532 int syncval = 0;
1528 1533 struct nfs4_svgetit_arg sarg;
1529 1534 struct nfs4_ntov_table ntov;
1530 1535 struct statvfs64 sb;
1531 1536 nfsstat4 status;
1532 1537 struct sockaddr *ca;
1533 1538 char *name = NULL;
1534 1539 char *lname = NULL;
1535 1540
1536 1541 DTRACE_NFSV4_2(op__create__start, struct compound_state *, cs,
1537 1542 CREATE4args *, args);
1538 1543
1539 1544 resp->attrset = 0;
1540 1545
1541 1546 if (dvp == NULL) {
1542 1547 *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
1543 1548 goto out;
1544 1549 }
1545 1550
1546 1551 /*
1547 1552 * If there is an unshared filesystem mounted on this vnode,
1548 1553 * do not allow to create an object in this directory.
1549 1554 */
1550 1555 if (vn_ismntpt(dvp)) {
1551 1556 *cs->statusp = resp->status = NFS4ERR_ACCESS;
1552 1557 goto out;
1553 1558 }
1554 1559
1555 1560 /* Verify that type is correct */
1556 1561 switch (args->type) {
1557 1562 case NF4LNK:
1558 1563 case NF4BLK:
1559 1564 case NF4CHR:
1560 1565 case NF4SOCK:
1561 1566 case NF4FIFO:
1562 1567 case NF4DIR:
1563 1568 break;
1564 1569 default:
1565 1570 *cs->statusp = resp->status = NFS4ERR_BADTYPE;
1566 1571 goto out;
1567 1572 };
1568 1573
1569 1574 if (cs->access == CS_ACCESS_DENIED) {
1570 1575 *cs->statusp = resp->status = NFS4ERR_ACCESS;
1571 1576 goto out;
1572 1577 }
1573 1578 if (dvp->v_type != VDIR) {
1574 1579 *cs->statusp = resp->status = NFS4ERR_NOTDIR;
1575 1580 goto out;
1576 1581 }
1577 1582 status = utf8_dir_verify(&args->objname);
1578 1583 if (status != NFS4_OK) {
1579 1584 *cs->statusp = resp->status = status;
1580 1585 goto out;
1581 1586 }
1582 1587
1583 1588 if (rdonly4(req, cs)) {
1584 1589 *cs->statusp = resp->status = NFS4ERR_ROFS;
1585 1590 goto out;
1586 1591 }
1587 1592
1588 1593 /*
1589 1594 * Name of newly created object
1590 1595 */
1591 1596 nm = utf8_to_fn(&args->objname, &len, NULL);
1592 1597 if (nm == NULL) {
1593 1598 *cs->statusp = resp->status = NFS4ERR_INVAL;
1594 1599 goto out;
1595 1600 }
1596 1601
1597 1602 if (len > MAXNAMELEN) {
1598 1603 *cs->statusp = resp->status = NFS4ERR_NAMETOOLONG;
1599 1604 kmem_free(nm, len);
1600 1605 goto out;
1601 1606 }
1602 1607
1603 1608 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
1604 1609 name = nfscmd_convname(ca, cs->exi, nm, NFSCMD_CONV_INBOUND,
1605 1610 MAXPATHLEN + 1);
1606 1611
1607 1612 if (name == NULL) {
1608 1613 *cs->statusp = resp->status = NFS4ERR_INVAL;
1609 1614 kmem_free(nm, len);
1610 1615 goto out;
1611 1616 }
1612 1617
1613 1618 resp->attrset = 0;
1614 1619
1615 1620 sarg.sbp = &sb;
1616 1621 sarg.is_referral = B_FALSE;
1617 1622 nfs4_ntov_table_init(&ntov);
1618 1623
1619 1624 status = do_rfs4_set_attrs(&resp->attrset,
1620 1625 &args->createattrs, cs, &sarg, &ntov, NFS4ATTR_SETIT);
1621 1626
1622 1627 if (sarg.vap->va_mask == 0 && status == NFS4_OK)
1623 1628 status = NFS4ERR_INVAL;
1624 1629
1625 1630 if (status != NFS4_OK) {
1626 1631 *cs->statusp = resp->status = status;
1627 1632 if (name != nm)
1628 1633 kmem_free(name, MAXPATHLEN + 1);
1629 1634 kmem_free(nm, len);
1630 1635 nfs4_ntov_table_free(&ntov, &sarg);
1631 1636 resp->attrset = 0;
1632 1637 goto out;
1633 1638 }
1634 1639
1635 1640 /* Get "before" change value */
1636 1641 bva.va_mask = AT_CTIME|AT_SEQ|AT_MODE;
1637 1642 error = VOP_GETATTR(dvp, &bva, 0, cr, NULL);
1638 1643 if (error) {
1639 1644 *cs->statusp = resp->status = puterrno4(error);
1640 1645 if (name != nm)
1641 1646 kmem_free(name, MAXPATHLEN + 1);
1642 1647 kmem_free(nm, len);
1643 1648 nfs4_ntov_table_free(&ntov, &sarg);
1644 1649 resp->attrset = 0;
1645 1650 goto out;
1646 1651 }
1647 1652 NFS4_SET_FATTR4_CHANGE(resp->cinfo.before, bva.va_ctime)
1648 1653
1649 1654 vap = sarg.vap;
1650 1655
1651 1656 /*
1652 1657 * Set the default initial values for attributes when the parent
1653 1658 * directory does not have the VSUID/VSGID bit set and they have
1654 1659 * not been specified in createattrs.
1655 1660 */
1656 1661 if (!(bva.va_mode & VSUID) && (vap->va_mask & AT_UID) == 0) {
1657 1662 vap->va_uid = crgetuid(cr);
1658 1663 vap->va_mask |= AT_UID;
1659 1664 }
1660 1665 if (!(bva.va_mode & VSGID) && (vap->va_mask & AT_GID) == 0) {
1661 1666 vap->va_gid = crgetgid(cr);
1662 1667 vap->va_mask |= AT_GID;
1663 1668 }
1664 1669
1665 1670 vap->va_mask |= AT_TYPE;
1666 1671 switch (args->type) {
1667 1672 case NF4DIR:
1668 1673 vap->va_type = VDIR;
1669 1674 if ((vap->va_mask & AT_MODE) == 0) {
1670 1675 vap->va_mode = 0700; /* default: owner rwx only */
1671 1676 vap->va_mask |= AT_MODE;
1672 1677 }
1673 1678 error = VOP_MKDIR(dvp, name, vap, &vp, cr, NULL, 0, NULL);
1674 1679 if (error)
1675 1680 break;
1676 1681
1677 1682 /*
1678 1683 * Get the initial "after" sequence number, if it fails,
1679 1684 * set to zero
1680 1685 */
1681 1686 iva.va_mask = AT_SEQ;
1682 1687 if (VOP_GETATTR(dvp, &iva, 0, cs->cr, NULL))
1683 1688 iva.va_seq = 0;
1684 1689 break;
1685 1690 case NF4LNK:
1686 1691 vap->va_type = VLNK;
1687 1692 if ((vap->va_mask & AT_MODE) == 0) {
1688 1693 vap->va_mode = 0700; /* default: owner rwx only */
1689 1694 vap->va_mask |= AT_MODE;
1690 1695 }
1691 1696
1692 1697 /*
1693 1698 * symlink names must be treated as data
1694 1699 */
1695 1700 lnm = utf8_to_str((utf8string *)&args->ftype4_u.linkdata,
1696 1701 &llen, NULL);
1697 1702
1698 1703 if (lnm == NULL) {
1699 1704 *cs->statusp = resp->status = NFS4ERR_INVAL;
1700 1705 if (name != nm)
1701 1706 kmem_free(name, MAXPATHLEN + 1);
1702 1707 kmem_free(nm, len);
1703 1708 nfs4_ntov_table_free(&ntov, &sarg);
1704 1709 resp->attrset = 0;
1705 1710 goto out;
1706 1711 }
1707 1712
1708 1713 if (llen > MAXPATHLEN) {
1709 1714 *cs->statusp = resp->status = NFS4ERR_NAMETOOLONG;
1710 1715 if (name != nm)
1711 1716 kmem_free(name, MAXPATHLEN + 1);
1712 1717 kmem_free(nm, len);
1713 1718 kmem_free(lnm, llen);
1714 1719 nfs4_ntov_table_free(&ntov, &sarg);
1715 1720 resp->attrset = 0;
1716 1721 goto out;
1717 1722 }
1718 1723
1719 1724 lname = nfscmd_convname(ca, cs->exi, lnm,
1720 1725 NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
1721 1726
1722 1727 if (lname == NULL) {
1723 1728 *cs->statusp = resp->status = NFS4ERR_SERVERFAULT;
1724 1729 if (name != nm)
1725 1730 kmem_free(name, MAXPATHLEN + 1);
1726 1731 kmem_free(nm, len);
1727 1732 kmem_free(lnm, llen);
1728 1733 nfs4_ntov_table_free(&ntov, &sarg);
1729 1734 resp->attrset = 0;
1730 1735 goto out;
1731 1736 }
1732 1737
1733 1738 error = VOP_SYMLINK(dvp, name, vap, lname, cr, NULL, 0);
1734 1739 if (lname != lnm)
1735 1740 kmem_free(lname, MAXPATHLEN + 1);
1736 1741 kmem_free(lnm, llen);
1737 1742 if (error)
1738 1743 break;
1739 1744
1740 1745 /*
1741 1746 * Get the initial "after" sequence number, if it fails,
1742 1747 * set to zero
1743 1748 */
1744 1749 iva.va_mask = AT_SEQ;
1745 1750 if (VOP_GETATTR(dvp, &iva, 0, cs->cr, NULL))
1746 1751 iva.va_seq = 0;
1747 1752
1748 1753 error = VOP_LOOKUP(dvp, name, &vp, NULL, 0, NULL, cr,
1749 1754 NULL, NULL, NULL);
1750 1755 if (error)
1751 1756 break;
1752 1757
1753 1758 /*
1754 1759 * va_seq is not safe over VOP calls, check it again
1755 1760 * if it has changed zero out iva to force atomic = FALSE.
1756 1761 */
1757 1762 iva2.va_mask = AT_SEQ;
1758 1763 if (VOP_GETATTR(dvp, &iva2, 0, cs->cr, NULL) ||
1759 1764 iva2.va_seq != iva.va_seq)
1760 1765 iva.va_seq = 0;
1761 1766 break;
1762 1767 default:
1763 1768 /*
1764 1769 * probably a special file.
1765 1770 */
1766 1771 if ((vap->va_mask & AT_MODE) == 0) {
1767 1772 vap->va_mode = 0600; /* default: owner rw only */
1768 1773 vap->va_mask |= AT_MODE;
1769 1774 }
1770 1775 syncval = FNODSYNC;
1771 1776 /*
1772 1777 * We know this will only generate one VOP call
1773 1778 */
1774 1779 vp = do_rfs4_op_mknod(args, resp, req, cs, vap, name);
1775 1780
1776 1781 if (vp == NULL) {
1777 1782 if (name != nm)
1778 1783 kmem_free(name, MAXPATHLEN + 1);
1779 1784 kmem_free(nm, len);
1780 1785 nfs4_ntov_table_free(&ntov, &sarg);
1781 1786 resp->attrset = 0;
1782 1787 goto out;
1783 1788 }
1784 1789
1785 1790 /*
1786 1791 * Get the initial "after" sequence number, if it fails,
1787 1792 * set to zero
1788 1793 */
1789 1794 iva.va_mask = AT_SEQ;
1790 1795 if (VOP_GETATTR(dvp, &iva, 0, cs->cr, NULL))
1791 1796 iva.va_seq = 0;
1792 1797
1793 1798 break;
1794 1799 }
1795 1800 if (name != nm)
1796 1801 kmem_free(name, MAXPATHLEN + 1);
1797 1802 kmem_free(nm, len);
1798 1803
1799 1804 if (error) {
1800 1805 *cs->statusp = resp->status = puterrno4(error);
1801 1806 }
1802 1807
1803 1808 /*
1804 1809 * Force modified data and metadata out to stable storage.
1805 1810 */
1806 1811 (void) VOP_FSYNC(dvp, 0, cr, NULL);
1807 1812
1808 1813 if (resp->status != NFS4_OK) {
1809 1814 if (vp != NULL)
1810 1815 VN_RELE(vp);
1811 1816 nfs4_ntov_table_free(&ntov, &sarg);
1812 1817 resp->attrset = 0;
1813 1818 goto out;
1814 1819 }
1815 1820
1816 1821 /*
1817 1822 * Finish setup of cinfo response, "before" value already set.
1818 1823 * Get "after" change value, if it fails, simply return the
1819 1824 * before value.
1820 1825 */
1821 1826 ava.va_mask = AT_CTIME|AT_SEQ;
1822 1827 if (VOP_GETATTR(dvp, &ava, 0, cr, NULL)) {
1823 1828 ava.va_ctime = bva.va_ctime;
1824 1829 ava.va_seq = 0;
1825 1830 }
1826 1831 NFS4_SET_FATTR4_CHANGE(resp->cinfo.after, ava.va_ctime);
1827 1832
1828 1833 /*
1829 1834 * True verification that object was created with correct
1830 1835 * attrs is impossible. The attrs could have been changed
1831 1836 * immediately after object creation. If attributes did
1832 1837 * not verify, the only recourse for the server is to
1833 1838 * destroy the object. Maybe if some attrs (like gid)
1834 1839 * are set incorrectly, the object should be destroyed;
1835 1840 * however, seems bad as a default policy. Do we really
1836 1841 * want to destroy an object over one of the times not
1837 1842 * verifying correctly? For these reasons, the server
1838 1843 * currently sets bits in attrset for createattrs
1839 1844 * that were set; however, no verification is done.
1840 1845 *
1841 1846 * vmask_to_nmask accounts for vattr bits set on create
1842 1847 * [do_rfs4_set_attrs() only sets resp bits for
1843 1848 * non-vattr/vfs bits.]
1844 1849 * Mask off any bits set by default so as not to return
1845 1850 * more attrset bits than were requested in createattrs
1846 1851 */
1847 1852 nfs4_vmask_to_nmask(sarg.vap->va_mask, &resp->attrset);
1848 1853 resp->attrset &= args->createattrs.attrmask;
1849 1854 nfs4_ntov_table_free(&ntov, &sarg);
1850 1855
1851 1856 error = makefh4(&cs->fh, vp, cs->exi);
1852 1857 if (error) {
1853 1858 *cs->statusp = resp->status = puterrno4(error);
1854 1859 }
1855 1860
1856 1861 /*
1857 1862 * The cinfo.atomic = TRUE only if we got no errors, we have
1858 1863 * non-zero va_seq's, and it has incremented by exactly one
1859 1864 * during the creation and it didn't change during the VOP_LOOKUP
1860 1865 * or VOP_FSYNC.
1861 1866 */
1862 1867 if (!error && bva.va_seq && iva.va_seq && ava.va_seq &&
1863 1868 iva.va_seq == (bva.va_seq + 1) && iva.va_seq == ava.va_seq)
1864 1869 resp->cinfo.atomic = TRUE;
1865 1870 else
1866 1871 resp->cinfo.atomic = FALSE;
1867 1872
1868 1873 /*
1869 1874 * Force modified metadata out to stable storage.
1870 1875 *
1871 1876 * if a underlying vp exists, pass it to VOP_FSYNC
1872 1877 */
1873 1878 if (VOP_REALVP(vp, &realvp, NULL) == 0)
1874 1879 (void) VOP_FSYNC(realvp, syncval, cr, NULL);
1875 1880 else
1876 1881 (void) VOP_FSYNC(vp, syncval, cr, NULL);
1877 1882
1878 1883 if (resp->status != NFS4_OK) {
1879 1884 VN_RELE(vp);
1880 1885 goto out;
1881 1886 }
1882 1887 if (cs->vp)
1883 1888 VN_RELE(cs->vp);
1884 1889
1885 1890 cs->vp = vp;
1886 1891 *cs->statusp = resp->status = NFS4_OK;
1887 1892 out:
1888 1893 DTRACE_NFSV4_2(op__create__done, struct compound_state *, cs,
1889 1894 CREATE4res *, resp);
1890 1895 }
1891 1896
1892 1897 /*ARGSUSED*/
1893 1898 static void
1894 1899 rfs4_op_delegpurge(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
1895 1900 struct compound_state *cs)
1896 1901 {
1897 1902 DTRACE_NFSV4_2(op__delegpurge__start, struct compound_state *, cs,
1898 1903 DELEGPURGE4args *, &argop->nfs_argop4_u.opdelegpurge);
1899 1904
1900 1905 rfs4_op_inval(argop, resop, req, cs);
1901 1906
1902 1907 DTRACE_NFSV4_2(op__delegpurge__done, struct compound_state *, cs,
1903 1908 DELEGPURGE4res *, &resop->nfs_resop4_u.opdelegpurge);
1904 1909 }
1905 1910
1906 1911 /*ARGSUSED*/
1907 1912 static void
1908 1913 rfs4_op_delegreturn(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
1909 1914 struct compound_state *cs)
1910 1915 {
1911 1916 DELEGRETURN4args *args = &argop->nfs_argop4_u.opdelegreturn;
1912 1917 DELEGRETURN4res *resp = &resop->nfs_resop4_u.opdelegreturn;
1913 1918 rfs4_deleg_state_t *dsp;
1914 1919 nfsstat4 status;
1915 1920
1916 1921 DTRACE_NFSV4_2(op__delegreturn__start, struct compound_state *, cs,
1917 1922 DELEGRETURN4args *, args);
1918 1923
1919 1924 status = rfs4_get_deleg_state(&args->deleg_stateid, &dsp);
1920 1925 resp->status = *cs->statusp = status;
1921 1926 if (status != NFS4_OK)
1922 1927 goto out;
1923 1928
1924 1929 /* Ensure specified filehandle matches */
1925 1930 if (cs->vp != dsp->rds_finfo->rf_vp) {
1926 1931 resp->status = *cs->statusp = NFS4ERR_BAD_STATEID;
1927 1932 } else
1928 1933 rfs4_return_deleg(dsp, FALSE);
1929 1934
1930 1935 rfs4_update_lease(dsp->rds_client);
1931 1936
1932 1937 rfs4_deleg_state_rele(dsp);
1933 1938 out:
1934 1939 DTRACE_NFSV4_2(op__delegreturn__done, struct compound_state *, cs,
1935 1940 DELEGRETURN4res *, resp);
1936 1941 }
1937 1942
1938 1943 /*
1939 1944 * Check to see if a given "flavor" is an explicitly shared flavor.
1940 1945 * The assumption of this routine is the "flavor" is already a valid
1941 1946 * flavor in the secinfo list of "exi".
1942 1947 *
1943 1948 * e.g.
1944 1949 * # share -o sec=flavor1 /export
1945 1950 * # share -o sec=flavor2 /export/home
1946 1951 *
1947 1952 * flavor2 is not an explicitly shared flavor for /export,
1948 1953 * however it is in the secinfo list for /export thru the
1949 1954 * server namespace setup.
1950 1955 */
1951 1956 int
1952 1957 is_exported_sec(int flavor, struct exportinfo *exi)
1953 1958 {
1954 1959 int i;
1955 1960 struct secinfo *sp;
1956 1961
1957 1962 sp = exi->exi_export.ex_secinfo;
1958 1963 for (i = 0; i < exi->exi_export.ex_seccnt; i++) {
1959 1964 if (flavor == sp[i].s_secinfo.sc_nfsnum ||
1960 1965 sp[i].s_secinfo.sc_nfsnum == AUTH_NONE) {
1961 1966 return (SEC_REF_EXPORTED(&sp[i]));
1962 1967 }
1963 1968 }
1964 1969
1965 1970 /* Should not reach this point based on the assumption */
1966 1971 return (0);
1967 1972 }
1968 1973
1969 1974 /*
1970 1975 * Check if the security flavor used in the request matches what is
1971 1976 * required at the export point or at the root pseudo node (exi_root).
1972 1977 *
1973 1978 * returns 1 if there's a match or if exported with AUTH_NONE; 0 otherwise.
1974 1979 *
1975 1980 */
1976 1981 static int
1977 1982 secinfo_match_or_authnone(struct compound_state *cs)
1978 1983 {
1979 1984 int i;
1980 1985 struct secinfo *sp;
1981 1986
1982 1987 /*
1983 1988 * Check cs->nfsflavor (from the request) against
1984 1989 * the current export data in cs->exi.
1985 1990 */
1986 1991 sp = cs->exi->exi_export.ex_secinfo;
1987 1992 for (i = 0; i < cs->exi->exi_export.ex_seccnt; i++) {
1988 1993 if (cs->nfsflavor == sp[i].s_secinfo.sc_nfsnum ||
1989 1994 sp[i].s_secinfo.sc_nfsnum == AUTH_NONE)
1990 1995 return (1);
1991 1996 }
1992 1997
1993 1998 return (0);
1994 1999 }
1995 2000
1996 2001 /*
1997 2002 * Check the access authority for the client and return the correct error.
1998 2003 */
1999 2004 nfsstat4
2000 2005 call_checkauth4(struct compound_state *cs, struct svc_req *req)
2001 2006 {
2002 2007 int authres;
2003 2008
2004 2009 /*
2005 2010 * First, check if the security flavor used in the request
2006 2011 * are among the flavors set in the server namespace.
2007 2012 */
2008 2013 if (!secinfo_match_or_authnone(cs)) {
2009 2014 *cs->statusp = NFS4ERR_WRONGSEC;
2010 2015 return (*cs->statusp);
2011 2016 }
2012 2017
2013 2018 authres = checkauth4(cs, req);
2014 2019
2015 2020 if (authres > 0) {
2016 2021 *cs->statusp = NFS4_OK;
2017 2022 if (! (cs->access & CS_ACCESS_LIMITED))
2018 2023 cs->access = CS_ACCESS_OK;
2019 2024 } else if (authres == 0) {
2020 2025 *cs->statusp = NFS4ERR_ACCESS;
2021 2026 } else if (authres == -2) {
2022 2027 *cs->statusp = NFS4ERR_WRONGSEC;
2023 2028 } else {
2024 2029 *cs->statusp = NFS4ERR_DELAY;
2025 2030 }
2026 2031 return (*cs->statusp);
2027 2032 }
2028 2033
2029 2034 /*
2030 2035 * bitmap4_to_attrmask is called by getattr and readdir.
2031 2036 * It sets up the vattr mask and determines whether vfsstat call is needed
2032 2037 * based on the input bitmap.
2033 2038 * Returns nfsv4 status.
2034 2039 */
2035 2040 static nfsstat4
2036 2041 bitmap4_to_attrmask(bitmap4 breq, struct nfs4_svgetit_arg *sargp)
2037 2042 {
2038 2043 int i;
2039 2044 uint_t va_mask;
2040 2045 struct statvfs64 *sbp = sargp->sbp;
2041 2046
2042 2047 sargp->sbp = NULL;
2043 2048 sargp->flag = 0;
2044 2049 sargp->rdattr_error = NFS4_OK;
2045 2050 sargp->mntdfid_set = FALSE;
2046 2051 if (sargp->cs->vp)
2047 2052 sargp->xattr = get_fh4_flag(&sargp->cs->fh,
2048 2053 FH4_ATTRDIR | FH4_NAMEDATTR);
2049 2054 else
2050 2055 sargp->xattr = 0;
2051 2056
2052 2057 /*
2053 2058 * Set rdattr_error_req to true if return error per
2054 2059 * failed entry rather than fail the readdir.
2055 2060 */
2056 2061 if (breq & FATTR4_RDATTR_ERROR_MASK)
2057 2062 sargp->rdattr_error_req = 1;
2058 2063 else
2059 2064 sargp->rdattr_error_req = 0;
2060 2065
2061 2066 /*
2062 2067 * generate the va_mask
2063 2068 * Handle the easy cases first
2064 2069 */
2065 2070 switch (breq) {
2066 2071 case NFS4_NTOV_ATTR_MASK:
2067 2072 sargp->vap->va_mask = NFS4_NTOV_ATTR_AT_MASK;
2068 2073 return (NFS4_OK);
2069 2074
2070 2075 case NFS4_FS_ATTR_MASK:
2071 2076 sargp->vap->va_mask = NFS4_FS_ATTR_AT_MASK;
2072 2077 sargp->sbp = sbp;
2073 2078 return (NFS4_OK);
2074 2079
2075 2080 case NFS4_NTOV_ATTR_CACHE_MASK:
2076 2081 sargp->vap->va_mask = NFS4_NTOV_ATTR_CACHE_AT_MASK;
2077 2082 return (NFS4_OK);
2078 2083
2079 2084 case FATTR4_LEASE_TIME_MASK:
2080 2085 sargp->vap->va_mask = 0;
2081 2086 return (NFS4_OK);
2082 2087
2083 2088 default:
2084 2089 va_mask = 0;
2085 2090 for (i = 0; i < nfs4_ntov_map_size; i++) {
2086 2091 if ((breq & nfs4_ntov_map[i].fbit) &&
2087 2092 nfs4_ntov_map[i].vbit)
2088 2093 va_mask |= nfs4_ntov_map[i].vbit;
2089 2094 }
2090 2095
2091 2096 /*
2092 2097 * Check is vfsstat is needed
2093 2098 */
2094 2099 if (breq & NFS4_FS_ATTR_MASK)
2095 2100 sargp->sbp = sbp;
2096 2101
2097 2102 sargp->vap->va_mask = va_mask;
2098 2103 return (NFS4_OK);
2099 2104 }
2100 2105 /* NOTREACHED */
2101 2106 }
2102 2107
2103 2108 /*
2104 2109 * bitmap4_get_sysattrs is called by getattr and readdir.
2105 2110 * It calls both VOP_GETATTR and VFS_STATVFS calls to get the attrs.
2106 2111 * Returns nfsv4 status.
2107 2112 */
2108 2113 static nfsstat4
2109 2114 bitmap4_get_sysattrs(struct nfs4_svgetit_arg *sargp)
2110 2115 {
2111 2116 int error;
2112 2117 struct compound_state *cs = sargp->cs;
2113 2118 vnode_t *vp = cs->vp;
2114 2119
2115 2120 if (sargp->sbp != NULL) {
2116 2121 if (error = VFS_STATVFS(vp->v_vfsp, sargp->sbp)) {
2117 2122 sargp->sbp = NULL; /* to identify error */
2118 2123 return (puterrno4(error));
2119 2124 }
2120 2125 }
2121 2126
2122 2127 return (rfs4_vop_getattr(vp, sargp->vap, 0, cs->cr));
2123 2128 }
2124 2129
2125 2130 static void
2126 2131 nfs4_ntov_table_init(struct nfs4_ntov_table *ntovp)
2127 2132 {
2128 2133 ntovp->na = kmem_zalloc(sizeof (union nfs4_attr_u) * nfs4_ntov_map_size,
2129 2134 KM_SLEEP);
2130 2135 ntovp->attrcnt = 0;
2131 2136 ntovp->vfsstat = FALSE;
2132 2137 }
2133 2138
2134 2139 static void
2135 2140 nfs4_ntov_table_free(struct nfs4_ntov_table *ntovp,
2136 2141 struct nfs4_svgetit_arg *sargp)
2137 2142 {
2138 2143 int i;
2139 2144 union nfs4_attr_u *na;
2140 2145 uint8_t *amap;
2141 2146
2142 2147 /*
2143 2148 * XXX Should do the same checks for whether the bit is set
2144 2149 */
2145 2150 for (i = 0, na = ntovp->na, amap = ntovp->amap;
2146 2151 i < ntovp->attrcnt; i++, na++, amap++) {
2147 2152 (void) (*nfs4_ntov_map[*amap].sv_getit)(
2148 2153 NFS4ATTR_FREEIT, sargp, na);
2149 2154 }
2150 2155 if ((sargp->op == NFS4ATTR_SETIT) || (sargp->op == NFS4ATTR_VERIT)) {
2151 2156 /*
2152 2157 * xdr_free for getattr will be done later
2153 2158 */
2154 2159 for (i = 0, na = ntovp->na, amap = ntovp->amap;
2155 2160 i < ntovp->attrcnt; i++, na++, amap++) {
2156 2161 xdr_free(nfs4_ntov_map[*amap].xfunc, (caddr_t)na);
2157 2162 }
2158 2163 }
2159 2164 kmem_free(ntovp->na, sizeof (union nfs4_attr_u) * nfs4_ntov_map_size);
2160 2165 }
2161 2166
2162 2167 /*
2163 2168 * do_rfs4_op_getattr gets the system attrs and converts into fattr4.
2164 2169 */
2165 2170 static nfsstat4
2166 2171 do_rfs4_op_getattr(bitmap4 breq, fattr4 *fattrp,
2167 2172 struct nfs4_svgetit_arg *sargp)
2168 2173 {
2169 2174 int error = 0;
2170 2175 int i, k;
2171 2176 struct nfs4_ntov_table ntov;
2172 2177 XDR xdr;
2173 2178 ulong_t xdr_size;
2174 2179 char *xdr_attrs;
2175 2180 nfsstat4 status = NFS4_OK;
2176 2181 nfsstat4 prev_rdattr_error = sargp->rdattr_error;
2177 2182 union nfs4_attr_u *na;
2178 2183 uint8_t *amap;
2179 2184
2180 2185 sargp->op = NFS4ATTR_GETIT;
2181 2186 sargp->flag = 0;
2182 2187
2183 2188 fattrp->attrmask = 0;
2184 2189 /* if no bits requested, then return empty fattr4 */
2185 2190 if (breq == 0) {
2186 2191 fattrp->attrlist4_len = 0;
2187 2192 fattrp->attrlist4 = NULL;
2188 2193 return (NFS4_OK);
2189 2194 }
2190 2195
2191 2196 /*
2192 2197 * return NFS4ERR_INVAL when client requests write-only attrs
2193 2198 */
2194 2199 if (breq & (FATTR4_TIME_ACCESS_SET_MASK | FATTR4_TIME_MODIFY_SET_MASK))
2195 2200 return (NFS4ERR_INVAL);
2196 2201
2197 2202 nfs4_ntov_table_init(&ntov);
2198 2203 na = ntov.na;
2199 2204 amap = ntov.amap;
2200 2205
2201 2206 /*
2202 2207 * Now loop to get or verify the attrs
2203 2208 */
2204 2209 for (i = 0; i < nfs4_ntov_map_size; i++) {
2205 2210 if (breq & nfs4_ntov_map[i].fbit) {
2206 2211 if ((*nfs4_ntov_map[i].sv_getit)(
2207 2212 NFS4ATTR_SUPPORTED, sargp, NULL) == 0) {
2208 2213
2209 2214 error = (*nfs4_ntov_map[i].sv_getit)(
2210 2215 NFS4ATTR_GETIT, sargp, na);
2211 2216
2212 2217 /*
2213 2218 * Possible error values:
2214 2219 * >0 if sv_getit failed to
2215 2220 * get the attr; 0 if succeeded;
2216 2221 * <0 if rdattr_error and the
2217 2222 * attribute cannot be returned.
2218 2223 */
2219 2224 if (error && !(sargp->rdattr_error_req))
2220 2225 goto done;
2221 2226 /*
2222 2227 * If error then just for entry
2223 2228 */
2224 2229 if (error == 0) {
2225 2230 fattrp->attrmask |=
2226 2231 nfs4_ntov_map[i].fbit;
2227 2232 *amap++ =
2228 2233 (uint8_t)nfs4_ntov_map[i].nval;
2229 2234 na++;
2230 2235 (ntov.attrcnt)++;
2231 2236 } else if ((error > 0) &&
2232 2237 (sargp->rdattr_error == NFS4_OK)) {
2233 2238 sargp->rdattr_error = puterrno4(error);
2234 2239 }
2235 2240 error = 0;
2236 2241 }
2237 2242 }
2238 2243 }
2239 2244
2240 2245 /*
2241 2246 * If rdattr_error was set after the return value for it was assigned,
2242 2247 * update it.
2243 2248 */
2244 2249 if (prev_rdattr_error != sargp->rdattr_error) {
2245 2250 na = ntov.na;
2246 2251 amap = ntov.amap;
2247 2252 for (i = 0; i < ntov.attrcnt; i++, na++, amap++) {
2248 2253 k = *amap;
2249 2254 if (k < FATTR4_RDATTR_ERROR) {
2250 2255 continue;
2251 2256 }
2252 2257 if ((k == FATTR4_RDATTR_ERROR) &&
2253 2258 ((*nfs4_ntov_map[k].sv_getit)(
2254 2259 NFS4ATTR_SUPPORTED, sargp, NULL) == 0)) {
2255 2260
2256 2261 (void) (*nfs4_ntov_map[k].sv_getit)(
2257 2262 NFS4ATTR_GETIT, sargp, na);
2258 2263 }
2259 2264 break;
2260 2265 }
2261 2266 }
2262 2267
2263 2268 xdr_size = 0;
2264 2269 na = ntov.na;
2265 2270 amap = ntov.amap;
2266 2271 for (i = 0; i < ntov.attrcnt; i++, na++, amap++) {
2267 2272 xdr_size += xdr_sizeof(nfs4_ntov_map[*amap].xfunc, na);
2268 2273 }
2269 2274
2270 2275 fattrp->attrlist4_len = xdr_size;
2271 2276 if (xdr_size) {
2272 2277 /* freed by rfs4_op_getattr_free() */
2273 2278 fattrp->attrlist4 = xdr_attrs = kmem_zalloc(xdr_size, KM_SLEEP);
2274 2279
2275 2280 xdrmem_create(&xdr, xdr_attrs, xdr_size, XDR_ENCODE);
2276 2281
2277 2282 na = ntov.na;
2278 2283 amap = ntov.amap;
2279 2284 for (i = 0; i < ntov.attrcnt; i++, na++, amap++) {
2280 2285 if (!(*nfs4_ntov_map[*amap].xfunc)(&xdr, na)) {
2281 2286 DTRACE_PROBE1(nfss__e__getattr4_encfail,
2282 2287 int, *amap);
2283 2288 status = NFS4ERR_SERVERFAULT;
2284 2289 break;
2285 2290 }
2286 2291 }
2287 2292 /* xdrmem_destroy(&xdrs); */ /* NO-OP */
2288 2293 } else {
2289 2294 fattrp->attrlist4 = NULL;
2290 2295 }
2291 2296 done:
2292 2297
2293 2298 nfs4_ntov_table_free(&ntov, sargp);
2294 2299
2295 2300 if (error != 0)
2296 2301 status = puterrno4(error);
2297 2302
2298 2303 return (status);
2299 2304 }
2300 2305
2301 2306 /* ARGSUSED */
2302 2307 static void
2303 2308 rfs4_op_getattr(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
2304 2309 struct compound_state *cs)
2305 2310 {
2306 2311 GETATTR4args *args = &argop->nfs_argop4_u.opgetattr;
2307 2312 GETATTR4res *resp = &resop->nfs_resop4_u.opgetattr;
2308 2313 struct nfs4_svgetit_arg sarg;
2309 2314 struct statvfs64 sb;
2310 2315 nfsstat4 status;
2311 2316
2312 2317 DTRACE_NFSV4_2(op__getattr__start, struct compound_state *, cs,
2313 2318 GETATTR4args *, args);
2314 2319
2315 2320 if (cs->vp == NULL) {
2316 2321 *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
2317 2322 goto out;
2318 2323 }
2319 2324
2320 2325 if (cs->access == CS_ACCESS_DENIED) {
2321 2326 *cs->statusp = resp->status = NFS4ERR_ACCESS;
2322 2327 goto out;
2323 2328 }
2324 2329
2325 2330 sarg.sbp = &sb;
2326 2331 sarg.cs = cs;
2327 2332 sarg.is_referral = B_FALSE;
2328 2333
2329 2334 status = bitmap4_to_attrmask(args->attr_request, &sarg);
2330 2335 if (status == NFS4_OK) {
2331 2336
2332 2337 status = bitmap4_get_sysattrs(&sarg);
2333 2338 if (status == NFS4_OK) {
2334 2339
2335 2340 /* Is this a referral? */
2336 2341 if (vn_is_nfs_reparse(cs->vp, cs->cr)) {
2337 2342 /* Older V4 Solaris client sees a link */
2338 2343 if (client_is_downrev(req))
2339 2344 sarg.vap->va_type = VLNK;
2340 2345 else
2341 2346 sarg.is_referral = B_TRUE;
2342 2347 }
2343 2348
2344 2349 status = do_rfs4_op_getattr(args->attr_request,
2345 2350 &resp->obj_attributes, &sarg);
2346 2351 }
2347 2352 }
2348 2353 *cs->statusp = resp->status = status;
2349 2354 out:
2350 2355 DTRACE_NFSV4_2(op__getattr__done, struct compound_state *, cs,
2351 2356 GETATTR4res *, resp);
2352 2357 }
2353 2358
2354 2359 static void
2355 2360 rfs4_op_getattr_free(nfs_resop4 *resop)
2356 2361 {
2357 2362 GETATTR4res *resp = &resop->nfs_resop4_u.opgetattr;
2358 2363
2359 2364 nfs4_fattr4_free(&resp->obj_attributes);
2360 2365 }
2361 2366
2362 2367 /* ARGSUSED */
2363 2368 static void
2364 2369 rfs4_op_getfh(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
2365 2370 struct compound_state *cs)
2366 2371 {
2367 2372 GETFH4res *resp = &resop->nfs_resop4_u.opgetfh;
2368 2373
2369 2374 DTRACE_NFSV4_1(op__getfh__start, struct compound_state *, cs);
2370 2375
2371 2376 if (cs->vp == NULL) {
2372 2377 *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
2373 2378 goto out;
2374 2379 }
2375 2380 if (cs->access == CS_ACCESS_DENIED) {
2376 2381 *cs->statusp = resp->status = NFS4ERR_ACCESS;
2377 2382 goto out;
2378 2383 }
2379 2384
2380 2385 /* check for reparse point at the share point */
2381 2386 if (cs->exi->exi_moved || vn_is_nfs_reparse(cs->exi->exi_vp, cs->cr)) {
2382 2387 /* it's all bad */
2383 2388 cs->exi->exi_moved = 1;
2384 2389 *cs->statusp = resp->status = NFS4ERR_MOVED;
2385 2390 DTRACE_PROBE2(nfs4serv__func__referral__shared__moved,
2386 2391 vnode_t *, cs->vp, char *, "rfs4_op_getfh");
2387 2392 return;
2388 2393 }
2389 2394
2390 2395 /* check for reparse point at vp */
2391 2396 if (vn_is_nfs_reparse(cs->vp, cs->cr) && !client_is_downrev(req)) {
2392 2397 /* it's not all bad */
2393 2398 *cs->statusp = resp->status = NFS4ERR_MOVED;
2394 2399 DTRACE_PROBE2(nfs4serv__func__referral__moved,
2395 2400 vnode_t *, cs->vp, char *, "rfs4_op_getfh");
2396 2401 return;
2397 2402 }
2398 2403
2399 2404 resp->object.nfs_fh4_val =
2400 2405 kmem_alloc(cs->fh.nfs_fh4_len, KM_SLEEP);
2401 2406 nfs_fh4_copy(&cs->fh, &resp->object);
2402 2407 *cs->statusp = resp->status = NFS4_OK;
2403 2408 out:
2404 2409 DTRACE_NFSV4_2(op__getfh__done, struct compound_state *, cs,
2405 2410 GETFH4res *, resp);
2406 2411 }
2407 2412
2408 2413 static void
2409 2414 rfs4_op_getfh_free(nfs_resop4 *resop)
2410 2415 {
2411 2416 GETFH4res *resp = &resop->nfs_resop4_u.opgetfh;
2412 2417
2413 2418 if (resp->status == NFS4_OK &&
2414 2419 resp->object.nfs_fh4_val != NULL) {
2415 2420 kmem_free(resp->object.nfs_fh4_val, resp->object.nfs_fh4_len);
2416 2421 resp->object.nfs_fh4_val = NULL;
2417 2422 resp->object.nfs_fh4_len = 0;
2418 2423 }
2419 2424 }
2420 2425
2421 2426 /*
2422 2427 * illegal: args: void
2423 2428 * res : status (NFS4ERR_OP_ILLEGAL)
2424 2429 */
2425 2430 /* ARGSUSED */
2426 2431 static void
2427 2432 rfs4_op_illegal(nfs_argop4 *argop, nfs_resop4 *resop,
2428 2433 struct svc_req *req, struct compound_state *cs)
2429 2434 {
2430 2435 ILLEGAL4res *resp = &resop->nfs_resop4_u.opillegal;
2431 2436
2432 2437 resop->resop = OP_ILLEGAL;
2433 2438 *cs->statusp = resp->status = NFS4ERR_OP_ILLEGAL;
2434 2439 }
2435 2440
2436 2441 /*
2437 2442 * link: args: SAVED_FH: file, CURRENT_FH: target directory
2438 2443 * res: status. If success - CURRENT_FH unchanged, return change_info
2439 2444 */
2440 2445 /* ARGSUSED */
2441 2446 static void
2442 2447 rfs4_op_link(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
2443 2448 struct compound_state *cs)
2444 2449 {
2445 2450 LINK4args *args = &argop->nfs_argop4_u.oplink;
2446 2451 LINK4res *resp = &resop->nfs_resop4_u.oplink;
2447 2452 int error;
2448 2453 vnode_t *vp;
2449 2454 vnode_t *dvp;
2450 2455 struct vattr bdva, idva, adva;
2451 2456 char *nm;
2452 2457 uint_t len;
2453 2458 struct sockaddr *ca;
2454 2459 char *name = NULL;
2455 2460 nfsstat4 status;
2456 2461
2457 2462 DTRACE_NFSV4_2(op__link__start, struct compound_state *, cs,
2458 2463 LINK4args *, args);
2459 2464
2460 2465 /* SAVED_FH: source object */
2461 2466 vp = cs->saved_vp;
2462 2467 if (vp == NULL) {
2463 2468 *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
2464 2469 goto out;
2465 2470 }
2466 2471
2467 2472 /* CURRENT_FH: target directory */
2468 2473 dvp = cs->vp;
2469 2474 if (dvp == NULL) {
2470 2475 *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
2471 2476 goto out;
2472 2477 }
2473 2478
2474 2479 /*
2475 2480 * If there is a non-shared filesystem mounted on this vnode,
2476 2481 * do not allow to link any file in this directory.
2477 2482 */
2478 2483 if (vn_ismntpt(dvp)) {
2479 2484 *cs->statusp = resp->status = NFS4ERR_ACCESS;
2480 2485 goto out;
2481 2486 }
2482 2487
2483 2488 if (cs->access == CS_ACCESS_DENIED) {
2484 2489 *cs->statusp = resp->status = NFS4ERR_ACCESS;
2485 2490 goto out;
2486 2491 }
2487 2492
2488 2493 /* Check source object's type validity */
2489 2494 if (vp->v_type == VDIR) {
2490 2495 *cs->statusp = resp->status = NFS4ERR_ISDIR;
2491 2496 goto out;
2492 2497 }
2493 2498
2494 2499 /* Check target directory's type */
2495 2500 if (dvp->v_type != VDIR) {
2496 2501 *cs->statusp = resp->status = NFS4ERR_NOTDIR;
2497 2502 goto out;
2498 2503 }
2499 2504
2500 2505 if (cs->saved_exi != cs->exi) {
2501 2506 *cs->statusp = resp->status = NFS4ERR_XDEV;
2502 2507 goto out;
2503 2508 }
2504 2509
2505 2510 status = utf8_dir_verify(&args->newname);
2506 2511 if (status != NFS4_OK) {
2507 2512 *cs->statusp = resp->status = status;
2508 2513 goto out;
2509 2514 }
2510 2515
2511 2516 nm = utf8_to_fn(&args->newname, &len, NULL);
2512 2517 if (nm == NULL) {
2513 2518 *cs->statusp = resp->status = NFS4ERR_INVAL;
2514 2519 goto out;
2515 2520 }
2516 2521
2517 2522 if (len > MAXNAMELEN) {
2518 2523 *cs->statusp = resp->status = NFS4ERR_NAMETOOLONG;
2519 2524 kmem_free(nm, len);
2520 2525 goto out;
2521 2526 }
2522 2527
2523 2528 if (rdonly4(req, cs)) {
2524 2529 *cs->statusp = resp->status = NFS4ERR_ROFS;
2525 2530 kmem_free(nm, len);
2526 2531 goto out;
2527 2532 }
2528 2533
2529 2534 /* Get "before" change value */
2530 2535 bdva.va_mask = AT_CTIME|AT_SEQ;
2531 2536 error = VOP_GETATTR(dvp, &bdva, 0, cs->cr, NULL);
2532 2537 if (error) {
2533 2538 *cs->statusp = resp->status = puterrno4(error);
2534 2539 kmem_free(nm, len);
2535 2540 goto out;
2536 2541 }
2537 2542
2538 2543 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
2539 2544 name = nfscmd_convname(ca, cs->exi, nm, NFSCMD_CONV_INBOUND,
2540 2545 MAXPATHLEN + 1);
2541 2546
2542 2547 if (name == NULL) {
2543 2548 *cs->statusp = resp->status = NFS4ERR_INVAL;
2544 2549 kmem_free(nm, len);
2545 2550 goto out;
2546 2551 }
2547 2552
2548 2553 NFS4_SET_FATTR4_CHANGE(resp->cinfo.before, bdva.va_ctime)
2549 2554
2550 2555 error = VOP_LINK(dvp, vp, name, cs->cr, NULL, 0);
2551 2556
2552 2557 if (nm != name)
2553 2558 kmem_free(name, MAXPATHLEN + 1);
2554 2559 kmem_free(nm, len);
2555 2560
2556 2561 /*
2557 2562 * Get the initial "after" sequence number, if it fails, set to zero
2558 2563 */
2559 2564 idva.va_mask = AT_SEQ;
2560 2565 if (VOP_GETATTR(dvp, &idva, 0, cs->cr, NULL))
2561 2566 idva.va_seq = 0;
2562 2567
2563 2568 /*
2564 2569 * Force modified data and metadata out to stable storage.
2565 2570 */
2566 2571 (void) VOP_FSYNC(vp, FNODSYNC, cs->cr, NULL);
2567 2572 (void) VOP_FSYNC(dvp, 0, cs->cr, NULL);
2568 2573
2569 2574 if (error) {
2570 2575 *cs->statusp = resp->status = puterrno4(error);
2571 2576 goto out;
2572 2577 }
2573 2578
2574 2579 /*
2575 2580 * Get "after" change value, if it fails, simply return the
2576 2581 * before value.
2577 2582 */
2578 2583 adva.va_mask = AT_CTIME|AT_SEQ;
2579 2584 if (VOP_GETATTR(dvp, &adva, 0, cs->cr, NULL)) {
2580 2585 adva.va_ctime = bdva.va_ctime;
2581 2586 adva.va_seq = 0;
2582 2587 }
2583 2588
2584 2589 NFS4_SET_FATTR4_CHANGE(resp->cinfo.after, adva.va_ctime)
2585 2590
2586 2591 /*
2587 2592 * The cinfo.atomic = TRUE only if we have
2588 2593 * non-zero va_seq's, and it has incremented by exactly one
2589 2594 * during the VOP_LINK and it didn't change during the VOP_FSYNC.
2590 2595 */
2591 2596 if (bdva.va_seq && idva.va_seq && adva.va_seq &&
2592 2597 idva.va_seq == (bdva.va_seq + 1) && idva.va_seq == adva.va_seq)
2593 2598 resp->cinfo.atomic = TRUE;
2594 2599 else
2595 2600 resp->cinfo.atomic = FALSE;
2596 2601
2597 2602 *cs->statusp = resp->status = NFS4_OK;
2598 2603 out:
2599 2604 DTRACE_NFSV4_2(op__link__done, struct compound_state *, cs,
2600 2605 LINK4res *, resp);
2601 2606 }
2602 2607
2603 2608 /*
↓ open down ↓ |
1480 lines elided |
↑ open up ↑ |
2604 2609 * Used by rfs4_op_lookup and rfs4_op_lookupp to do the actual work.
2605 2610 */
2606 2611
2607 2612 /* ARGSUSED */
2608 2613 static nfsstat4
2609 2614 do_rfs4_op_lookup(char *nm, struct svc_req *req, struct compound_state *cs)
2610 2615 {
2611 2616 int error;
2612 2617 int different_export = 0;
2613 2618 vnode_t *vp, *pre_tvp = NULL, *oldvp = NULL;
2614 - struct exportinfo *exi = NULL, *pre_exi = NULL;
2619 + struct exportinfo *exi = NULL, *pre_exi = NULL, *oexi = NULL;
2615 2620 nfsstat4 stat;
2616 2621 fid_t fid;
2617 2622 int attrdir, dotdot, walk;
2618 2623 bool_t is_newvp = FALSE;
2619 2624
2620 2625 if (cs->vp->v_flag & V_XATTRDIR) {
2621 2626 attrdir = 1;
2622 2627 ASSERT(get_fh4_flag(&cs->fh, FH4_ATTRDIR));
2623 2628 } else {
2624 2629 attrdir = 0;
2625 2630 ASSERT(! get_fh4_flag(&cs->fh, FH4_ATTRDIR));
2626 2631 }
2627 2632
2628 2633 dotdot = (nm[0] == '.' && nm[1] == '.' && nm[2] == '\0');
2629 2634
2630 2635 /*
2631 2636 * If dotdotting, then need to check whether it's
2632 2637 * above the root of a filesystem, or above an
2633 2638 * export point.
2634 2639 */
2635 2640 if (dotdot) {
2636 2641
2637 2642 /*
2638 2643 * If dotdotting at the root of a filesystem, then
2639 2644 * need to traverse back to the mounted-on filesystem
2640 2645 * and do the dotdot lookup there.
2641 2646 */
2642 2647 if (cs->vp->v_flag & VROOT) {
2643 2648
2644 2649 /*
2645 2650 * If at the system root, then can
2646 2651 * go up no further.
2647 2652 */
2648 2653 if (VN_CMP(cs->vp, rootdir))
2649 2654 return (puterrno4(ENOENT));
2650 2655
2651 2656 /*
2652 2657 * Traverse back to the mounted-on filesystem
2653 2658 */
2654 2659 cs->vp = untraverse(cs->vp);
2655 2660
2656 2661 /*
2657 2662 * Set the different_export flag so we remember
2658 2663 * to pick up a new exportinfo entry for
2659 2664 * this new filesystem.
2660 2665 */
2661 2666 different_export = 1;
2662 2667 } else {
2663 2668
2664 2669 /*
2665 2670 * If dotdotting above an export point then set
2666 2671 * the different_export to get new export info.
2667 2672 */
2668 2673 different_export = nfs_exported(cs->exi, cs->vp);
2669 2674 }
2670 2675 }
2671 2676
2672 2677 error = VOP_LOOKUP(cs->vp, nm, &vp, NULL, 0, NULL, cs->cr,
2673 2678 NULL, NULL, NULL);
2674 2679 if (error)
2675 2680 return (puterrno4(error));
2676 2681
2677 2682 /*
2678 2683 * If the vnode is in a pseudo filesystem, check whether it is visible.
2679 2684 *
2680 2685 * XXX if the vnode is a symlink and it is not visible in
2681 2686 * a pseudo filesystem, return ENOENT (not following symlink).
2682 2687 * V4 client can not mount such symlink. This is a regression
2683 2688 * from V2/V3.
2684 2689 *
2685 2690 * In the same exported filesystem, if the security flavor used
2686 2691 * is not an explicitly shared flavor, limit the view to the visible
2687 2692 * list entries only. This is not a WRONGSEC case because it's already
2688 2693 * checked via PUTROOTFH/PUTPUBFH or PUTFH.
2689 2694 */
2690 2695 if (!different_export &&
2691 2696 (PSEUDO(cs->exi) || ! is_exported_sec(cs->nfsflavor, cs->exi) ||
2692 2697 cs->access & CS_ACCESS_LIMITED)) {
2693 2698 if (! nfs_visible(cs->exi, vp, &different_export)) {
2694 2699 VN_RELE(vp);
2695 2700 return (puterrno4(ENOENT));
2696 2701 }
2697 2702 }
↓ open down ↓ |
73 lines elided |
↑ open up ↑ |
2698 2703
2699 2704 /*
2700 2705 * If it's a mountpoint, then traverse it.
2701 2706 */
2702 2707 if (vn_ismntpt(vp)) {
2703 2708 pre_exi = cs->exi; /* save pre-traversed exportinfo */
2704 2709 pre_tvp = vp; /* save pre-traversed vnode */
2705 2710
2706 2711 /*
2707 2712 * hold pre_tvp to counteract rele by traverse. We will
2708 - * need pre_tvp below if checkexport4 fails
2713 + * need pre_tvp below if checkexport fails
2709 2714 */
2710 2715 VN_HOLD(pre_tvp);
2711 2716 if ((error = traverse(&vp)) != 0) {
2712 2717 VN_RELE(vp);
2713 2718 VN_RELE(pre_tvp);
2714 2719 return (puterrno4(error));
2715 2720 }
2716 2721 different_export = 1;
2717 2722 } else if (vp->v_vfsp != cs->vp->v_vfsp) {
2718 2723 /*
2719 2724 * The vfsp comparison is to handle the case where
2720 2725 * a LOFS mount is shared. lo_lookup traverses mount points,
2721 2726 * and NFS is unaware of local fs transistions because
2722 2727 * v_vfsmountedhere isn't set. For this special LOFS case,
2723 2728 * the dir and the obj returned by lookup will have different
2724 2729 * vfs ptrs.
2725 2730 */
2726 2731 different_export = 1;
2727 2732 }
2728 2733
2729 2734 if (different_export) {
2730 2735
2731 2736 bzero(&fid, sizeof (fid));
2732 2737 fid.fid_len = MAXFIDSZ;
2733 2738 error = vop_fid_pseudo(vp, &fid);
↓ open down ↓ |
15 lines elided |
↑ open up ↑ |
2734 2739 if (error) {
2735 2740 VN_RELE(vp);
2736 2741 if (pre_tvp)
2737 2742 VN_RELE(pre_tvp);
2738 2743 return (puterrno4(error));
2739 2744 }
2740 2745
2741 2746 if (dotdot)
2742 2747 exi = nfs_vptoexi(NULL, vp, cs->cr, &walk, NULL, TRUE);
2743 2748 else
2744 - exi = checkexport4(&vp->v_vfsp->vfs_fsid, &fid, vp);
2749 + exi = checkexport(&vp->v_vfsp->vfs_fsid, &fid, vp);
2745 2750
2746 2751 if (exi == NULL) {
2747 2752 if (pre_tvp) {
2748 2753 /*
2749 2754 * If this vnode is a mounted-on vnode,
2750 2755 * but the mounted-on file system is not
2751 2756 * exported, send back the filehandle for
2752 2757 * the mounted-on vnode, not the root of
2753 2758 * the mounted-on file system.
2754 2759 */
2755 2760 VN_RELE(vp);
2756 2761 vp = pre_tvp;
2757 2762 exi = pre_exi;
2763 + if (exi)
2764 + exi_hold(exi);
2758 2765 } else {
2759 2766 VN_RELE(vp);
2760 2767 return (puterrno4(EACCES));
2761 2768 }
2762 2769 } else if (pre_tvp) {
2763 2770 /* we're done with pre_tvp now. release extra hold */
2764 2771 VN_RELE(pre_tvp);
2765 2772 }
2766 2773
2774 + if (cs->exi)
2775 + exi_rele(cs->exi);
2767 2776 cs->exi = exi;
2768 2777
2769 2778 /*
2770 2779 * Now we do a checkauth4. The reason is that
2771 2780 * this client/user may not have access to the new
2772 2781 * exported file system, and if he does,
2773 2782 * the client/user may be mapped to a different uid.
2774 2783 *
2775 2784 * We start with a new cr, because the checkauth4 done
2776 2785 * in the PUT*FH operation over wrote the cred's uid,
2777 2786 * gid, etc, and we want the real thing before calling
2778 2787 * checkauth4()
2779 2788 */
2780 2789 crfree(cs->cr);
2781 2790 cs->cr = crdup(cs->basecr);
2782 2791
2783 2792 oldvp = cs->vp;
2784 2793 cs->vp = vp;
2785 2794 is_newvp = TRUE;
2786 2795
2787 2796 stat = call_checkauth4(cs, req);
2788 2797 if (stat != NFS4_OK) {
2789 2798 VN_RELE(cs->vp);
2790 2799 cs->vp = oldvp;
2791 2800 return (stat);
2792 2801 }
2793 2802 }
2794 2803
2795 2804 /*
2796 2805 * After various NFS checks, do a label check on the path
2797 2806 * component. The label on this path should either be the
2798 2807 * global zone's label or a zone's label. We are only
2799 2808 * interested in the zone's label because exported files
2800 2809 * in global zone is accessible (though read-only) to
2801 2810 * clients. The exportability/visibility check is already
2802 2811 * done before reaching this code.
2803 2812 */
2804 2813 if (is_system_labeled()) {
2805 2814 bslabel_t *clabel;
2806 2815
2807 2816 ASSERT(req->rq_label != NULL);
2808 2817 clabel = req->rq_label;
2809 2818 DTRACE_PROBE2(tx__rfs4__log__info__oplookup__clabel, char *,
2810 2819 "got client label from request(1)", struct svc_req *, req);
2811 2820
2812 2821 if (!blequal(&l_admin_low->tsl_label, clabel)) {
2813 2822 if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
2814 2823 cs->exi)) {
2815 2824 error = EACCES;
2816 2825 goto err_out;
2817 2826 }
2818 2827 } else {
2819 2828 /*
2820 2829 * We grant access to admin_low label clients
2821 2830 * only if the client is trusted, i.e. also
2822 2831 * running Solaris Trusted Extension.
2823 2832 */
2824 2833 struct sockaddr *ca;
2825 2834 int addr_type;
2826 2835 void *ipaddr;
2827 2836 tsol_tpc_t *tp;
2828 2837
2829 2838 ca = (struct sockaddr *)svc_getrpccaller(
2830 2839 req->rq_xprt)->buf;
2831 2840 if (ca->sa_family == AF_INET) {
2832 2841 addr_type = IPV4_VERSION;
2833 2842 ipaddr = &((struct sockaddr_in *)ca)->sin_addr;
2834 2843 } else if (ca->sa_family == AF_INET6) {
2835 2844 addr_type = IPV6_VERSION;
2836 2845 ipaddr = &((struct sockaddr_in6 *)
2837 2846 ca)->sin6_addr;
2838 2847 }
2839 2848 tp = find_tpc(ipaddr, addr_type, B_FALSE);
2840 2849 if (tp == NULL || tp->tpc_tp.tp_doi !=
2841 2850 l_admin_low->tsl_doi || tp->tpc_tp.host_type !=
2842 2851 SUN_CIPSO) {
2843 2852 if (tp != NULL)
2844 2853 TPC_RELE(tp);
2845 2854 error = EACCES;
2846 2855 goto err_out;
2847 2856 }
2848 2857 TPC_RELE(tp);
2849 2858 }
2850 2859 }
2851 2860
2852 2861 error = makefh4(&cs->fh, vp, cs->exi);
2853 2862
2854 2863 err_out:
2855 2864 if (error) {
2856 2865 if (is_newvp) {
2857 2866 VN_RELE(cs->vp);
2858 2867 cs->vp = oldvp;
2859 2868 } else
2860 2869 VN_RELE(vp);
2861 2870 return (puterrno4(error));
2862 2871 }
2863 2872
2864 2873 if (!is_newvp) {
2865 2874 if (cs->vp)
2866 2875 VN_RELE(cs->vp);
2867 2876 cs->vp = vp;
2868 2877 } else if (oldvp)
2869 2878 VN_RELE(oldvp);
2870 2879
2871 2880 /*
2872 2881 * if did lookup on attrdir and didn't lookup .., set named
2873 2882 * attr fh flag
2874 2883 */
2875 2884 if (attrdir && ! dotdot)
2876 2885 set_fh4_flag(&cs->fh, FH4_NAMEDATTR);
2877 2886
2878 2887 /* Assume false for now, open proc will set this */
2879 2888 cs->mandlock = FALSE;
2880 2889
2881 2890 return (NFS4_OK);
2882 2891 }
2883 2892
2884 2893 /* ARGSUSED */
2885 2894 static void
2886 2895 rfs4_op_lookup(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
2887 2896 struct compound_state *cs)
2888 2897 {
2889 2898 LOOKUP4args *args = &argop->nfs_argop4_u.oplookup;
2890 2899 LOOKUP4res *resp = &resop->nfs_resop4_u.oplookup;
2891 2900 char *nm;
2892 2901 uint_t len;
2893 2902 struct sockaddr *ca;
2894 2903 char *name = NULL;
2895 2904 nfsstat4 status;
2896 2905
2897 2906 DTRACE_NFSV4_2(op__lookup__start, struct compound_state *, cs,
2898 2907 LOOKUP4args *, args);
2899 2908
2900 2909 if (cs->vp == NULL) {
2901 2910 *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
2902 2911 goto out;
2903 2912 }
2904 2913
2905 2914 if (cs->vp->v_type == VLNK) {
2906 2915 *cs->statusp = resp->status = NFS4ERR_SYMLINK;
2907 2916 goto out;
2908 2917 }
2909 2918
2910 2919 if (cs->vp->v_type != VDIR) {
2911 2920 *cs->statusp = resp->status = NFS4ERR_NOTDIR;
2912 2921 goto out;
2913 2922 }
2914 2923
2915 2924 status = utf8_dir_verify(&args->objname);
2916 2925 if (status != NFS4_OK) {
2917 2926 *cs->statusp = resp->status = status;
2918 2927 goto out;
2919 2928 }
2920 2929
2921 2930 nm = utf8_to_str(&args->objname, &len, NULL);
2922 2931 if (nm == NULL) {
2923 2932 *cs->statusp = resp->status = NFS4ERR_INVAL;
2924 2933 goto out;
2925 2934 }
2926 2935
2927 2936 if (len > MAXNAMELEN) {
2928 2937 *cs->statusp = resp->status = NFS4ERR_NAMETOOLONG;
2929 2938 kmem_free(nm, len);
2930 2939 goto out;
2931 2940 }
2932 2941
2933 2942 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
2934 2943 name = nfscmd_convname(ca, cs->exi, nm, NFSCMD_CONV_INBOUND,
2935 2944 MAXPATHLEN + 1);
2936 2945
2937 2946 if (name == NULL) {
2938 2947 *cs->statusp = resp->status = NFS4ERR_INVAL;
2939 2948 kmem_free(nm, len);
2940 2949 goto out;
2941 2950 }
2942 2951
2943 2952 *cs->statusp = resp->status = do_rfs4_op_lookup(name, req, cs);
2944 2953
2945 2954 if (name != nm)
2946 2955 kmem_free(name, MAXPATHLEN + 1);
2947 2956 kmem_free(nm, len);
2948 2957
2949 2958 out:
2950 2959 DTRACE_NFSV4_2(op__lookup__done, struct compound_state *, cs,
2951 2960 LOOKUP4res *, resp);
2952 2961 }
2953 2962
2954 2963 /* ARGSUSED */
2955 2964 static void
2956 2965 rfs4_op_lookupp(nfs_argop4 *args, nfs_resop4 *resop, struct svc_req *req,
2957 2966 struct compound_state *cs)
2958 2967 {
2959 2968 LOOKUPP4res *resp = &resop->nfs_resop4_u.oplookupp;
2960 2969
2961 2970 DTRACE_NFSV4_1(op__lookupp__start, struct compound_state *, cs);
2962 2971
2963 2972 if (cs->vp == NULL) {
2964 2973 *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
2965 2974 goto out;
2966 2975 }
2967 2976
2968 2977 if (cs->vp->v_type != VDIR) {
2969 2978 *cs->statusp = resp->status = NFS4ERR_NOTDIR;
2970 2979 goto out;
2971 2980 }
2972 2981
2973 2982 *cs->statusp = resp->status = do_rfs4_op_lookup("..", req, cs);
2974 2983
2975 2984 /*
2976 2985 * From NFSV4 Specification, LOOKUPP should not check for
2977 2986 * NFS4ERR_WRONGSEC. Retrun NFS4_OK instead.
2978 2987 */
2979 2988 if (resp->status == NFS4ERR_WRONGSEC) {
2980 2989 *cs->statusp = resp->status = NFS4_OK;
2981 2990 }
2982 2991
2983 2992 out:
2984 2993 DTRACE_NFSV4_2(op__lookupp__done, struct compound_state *, cs,
2985 2994 LOOKUPP4res *, resp);
2986 2995 }
2987 2996
2988 2997
2989 2998 /*ARGSUSED2*/
2990 2999 static void
2991 3000 rfs4_op_openattr(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
2992 3001 struct compound_state *cs)
2993 3002 {
2994 3003 OPENATTR4args *args = &argop->nfs_argop4_u.opopenattr;
2995 3004 OPENATTR4res *resp = &resop->nfs_resop4_u.opopenattr;
2996 3005 vnode_t *avp = NULL;
2997 3006 int lookup_flags = LOOKUP_XATTR, error;
2998 3007 int exp_ro = 0;
2999 3008
3000 3009 DTRACE_NFSV4_2(op__openattr__start, struct compound_state *, cs,
3001 3010 OPENATTR4args *, args);
3002 3011
3003 3012 if (cs->vp == NULL) {
3004 3013 *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
3005 3014 goto out;
3006 3015 }
3007 3016
3008 3017 if ((cs->vp->v_vfsp->vfs_flag & VFS_XATTR) == 0 &&
3009 3018 !vfs_has_feature(cs->vp->v_vfsp, VFSFT_SYSATTR_VIEWS)) {
3010 3019 *cs->statusp = resp->status = puterrno4(ENOTSUP);
3011 3020 goto out;
3012 3021 }
3013 3022
3014 3023 /*
3015 3024 * If file system supports passing ACE mask to VOP_ACCESS then
3016 3025 * check for ACE_READ_NAMED_ATTRS, otherwise do legacy checks
3017 3026 */
3018 3027
3019 3028 if (vfs_has_feature(cs->vp->v_vfsp, VFSFT_ACEMASKONACCESS))
3020 3029 error = VOP_ACCESS(cs->vp, ACE_READ_NAMED_ATTRS,
3021 3030 V_ACE_MASK, cs->cr, NULL);
3022 3031 else
3023 3032 error = ((VOP_ACCESS(cs->vp, VREAD, 0, cs->cr, NULL) != 0) &&
3024 3033 (VOP_ACCESS(cs->vp, VWRITE, 0, cs->cr, NULL) != 0) &&
3025 3034 (VOP_ACCESS(cs->vp, VEXEC, 0, cs->cr, NULL) != 0));
3026 3035
3027 3036 if (error) {
3028 3037 *cs->statusp = resp->status = puterrno4(EACCES);
3029 3038 goto out;
3030 3039 }
3031 3040
3032 3041 /*
3033 3042 * The CREATE_XATTR_DIR VOP flag cannot be specified if
3034 3043 * the file system is exported read-only -- regardless of
3035 3044 * createdir flag. Otherwise the attrdir would be created
3036 3045 * (assuming server fs isn't mounted readonly locally). If
3037 3046 * VOP_LOOKUP returns ENOENT in this case, the error will
3038 3047 * be translated into EROFS. ENOSYS is mapped to ENOTSUP
3039 3048 * because specfs has no VOP_LOOKUP op, so the macro would
3040 3049 * return ENOSYS. EINVAL is returned by all (current)
3041 3050 * Solaris file system implementations when any of their
3042 3051 * restrictions are violated (xattr(dir) can't have xattrdir).
3043 3052 * Returning NOTSUPP is more appropriate in this case
3044 3053 * because the object will never be able to have an attrdir.
3045 3054 */
3046 3055 if (args->createdir && ! (exp_ro = rdonly4(req, cs)))
3047 3056 lookup_flags |= CREATE_XATTR_DIR;
3048 3057
3049 3058 error = VOP_LOOKUP(cs->vp, "", &avp, NULL, lookup_flags, NULL, cs->cr,
3050 3059 NULL, NULL, NULL);
3051 3060
3052 3061 if (error) {
3053 3062 if (error == ENOENT && args->createdir && exp_ro)
3054 3063 *cs->statusp = resp->status = puterrno4(EROFS);
3055 3064 else if (error == EINVAL || error == ENOSYS)
3056 3065 *cs->statusp = resp->status = puterrno4(ENOTSUP);
3057 3066 else
3058 3067 *cs->statusp = resp->status = puterrno4(error);
3059 3068 goto out;
3060 3069 }
3061 3070
3062 3071 ASSERT(avp->v_flag & V_XATTRDIR);
3063 3072
3064 3073 error = makefh4(&cs->fh, avp, cs->exi);
3065 3074
3066 3075 if (error) {
3067 3076 VN_RELE(avp);
3068 3077 *cs->statusp = resp->status = puterrno4(error);
3069 3078 goto out;
3070 3079 }
3071 3080
3072 3081 VN_RELE(cs->vp);
3073 3082 cs->vp = avp;
3074 3083
3075 3084 /*
3076 3085 * There is no requirement for an attrdir fh flag
3077 3086 * because the attrdir has a vnode flag to distinguish
3078 3087 * it from regular (non-xattr) directories. The
3079 3088 * FH4_ATTRDIR flag is set for future sanity checks.
3080 3089 */
3081 3090 set_fh4_flag(&cs->fh, FH4_ATTRDIR);
3082 3091 *cs->statusp = resp->status = NFS4_OK;
3083 3092
3084 3093 out:
3085 3094 DTRACE_NFSV4_2(op__openattr__done, struct compound_state *, cs,
3086 3095 OPENATTR4res *, resp);
3087 3096 }
3088 3097
3089 3098 static int
3090 3099 do_io(int direction, vnode_t *vp, struct uio *uio, int ioflag, cred_t *cred,
3091 3100 caller_context_t *ct)
3092 3101 {
3093 3102 int error;
3094 3103 int i;
3095 3104 clock_t delaytime;
3096 3105
3097 3106 delaytime = MSEC_TO_TICK_ROUNDUP(rfs4_lock_delay);
3098 3107
3099 3108 /*
3100 3109 * Don't block on mandatory locks. If this routine returns
3101 3110 * EAGAIN, the caller should return NFS4ERR_LOCKED.
3102 3111 */
3103 3112 uio->uio_fmode = FNONBLOCK;
3104 3113
3105 3114 for (i = 0; i < rfs4_maxlock_tries; i++) {
3106 3115
3107 3116
3108 3117 if (direction == FREAD) {
3109 3118 (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, ct);
3110 3119 error = VOP_READ(vp, uio, ioflag, cred, ct);
3111 3120 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, ct);
3112 3121 } else {
3113 3122 (void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, ct);
3114 3123 error = VOP_WRITE(vp, uio, ioflag, cred, ct);
3115 3124 VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, ct);
3116 3125 }
3117 3126
3118 3127 if (error != EAGAIN)
3119 3128 break;
3120 3129
3121 3130 if (i < rfs4_maxlock_tries - 1) {
3122 3131 delay(delaytime);
3123 3132 delaytime *= 2;
3124 3133 }
3125 3134 }
3126 3135
3127 3136 return (error);
3128 3137 }
3129 3138
3130 3139 /* ARGSUSED */
3131 3140 static void
3132 3141 rfs4_op_read(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
3133 3142 struct compound_state *cs)
3134 3143 {
3135 3144 READ4args *args = &argop->nfs_argop4_u.opread;
3136 3145 READ4res *resp = &resop->nfs_resop4_u.opread;
3137 3146 int error;
3138 3147 int verror;
3139 3148 vnode_t *vp;
3140 3149 struct vattr va;
3141 3150 struct iovec iov, *iovp = NULL;
3142 3151 int iovcnt;
3143 3152 struct uio uio;
3144 3153 u_offset_t offset;
3145 3154 bool_t *deleg = &cs->deleg;
3146 3155 nfsstat4 stat;
3147 3156 int in_crit = 0;
3148 3157 mblk_t *mp = NULL;
3149 3158 int alloc_err = 0;
3150 3159 int rdma_used = 0;
3151 3160 int loaned_buffers;
3152 3161 caller_context_t ct;
3153 3162 struct uio *uiop;
3154 3163
3155 3164 DTRACE_NFSV4_2(op__read__start, struct compound_state *, cs,
3156 3165 READ4args, args);
3157 3166
3158 3167 vp = cs->vp;
3159 3168 if (vp == NULL) {
3160 3169 *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
3161 3170 goto out;
3162 3171 }
3163 3172 if (cs->access == CS_ACCESS_DENIED) {
3164 3173 *cs->statusp = resp->status = NFS4ERR_ACCESS;
3165 3174 goto out;
3166 3175 }
3167 3176
3168 3177 if ((stat = rfs4_check_stateid(FREAD, vp, &args->stateid, FALSE,
3169 3178 deleg, TRUE, &ct)) != NFS4_OK) {
3170 3179 *cs->statusp = resp->status = stat;
3171 3180 goto out;
3172 3181 }
3173 3182
3174 3183 /*
3175 3184 * Enter the critical region before calling VOP_RWLOCK
3176 3185 * to avoid a deadlock with write requests.
3177 3186 */
3178 3187 if (nbl_need_check(vp)) {
3179 3188 nbl_start_crit(vp, RW_READER);
3180 3189 in_crit = 1;
3181 3190 if (nbl_conflict(vp, NBL_READ, args->offset, args->count, 0,
3182 3191 &ct)) {
3183 3192 *cs->statusp = resp->status = NFS4ERR_LOCKED;
3184 3193 goto out;
3185 3194 }
3186 3195 }
3187 3196
3188 3197 if (args->wlist) {
3189 3198 if (args->count > clist_len(args->wlist)) {
3190 3199 *cs->statusp = resp->status = NFS4ERR_INVAL;
3191 3200 goto out;
3192 3201 }
3193 3202 rdma_used = 1;
3194 3203 }
3195 3204
3196 3205 /* use loaned buffers for TCP */
3197 3206 loaned_buffers = (nfs_loaned_buffers && !rdma_used) ? 1 : 0;
3198 3207
3199 3208 va.va_mask = AT_MODE|AT_SIZE|AT_UID;
3200 3209 verror = VOP_GETATTR(vp, &va, 0, cs->cr, &ct);
3201 3210
3202 3211 /*
3203 3212 * If we can't get the attributes, then we can't do the
3204 3213 * right access checking. So, we'll fail the request.
3205 3214 */
3206 3215 if (verror) {
3207 3216 *cs->statusp = resp->status = puterrno4(verror);
3208 3217 goto out;
3209 3218 }
3210 3219
3211 3220 if (vp->v_type != VREG) {
3212 3221 *cs->statusp = resp->status =
3213 3222 ((vp->v_type == VDIR) ? NFS4ERR_ISDIR : NFS4ERR_INVAL);
3214 3223 goto out;
3215 3224 }
3216 3225
3217 3226 if (crgetuid(cs->cr) != va.va_uid &&
3218 3227 (error = VOP_ACCESS(vp, VREAD, 0, cs->cr, &ct)) &&
3219 3228 (error = VOP_ACCESS(vp, VEXEC, 0, cs->cr, &ct))) {
3220 3229 *cs->statusp = resp->status = puterrno4(error);
3221 3230 goto out;
3222 3231 }
3223 3232
3224 3233 if (MANDLOCK(vp, va.va_mode)) { /* XXX - V4 supports mand locking */
3225 3234 *cs->statusp = resp->status = NFS4ERR_ACCESS;
3226 3235 goto out;
3227 3236 }
3228 3237
3229 3238 offset = args->offset;
3230 3239 if (offset >= va.va_size) {
3231 3240 *cs->statusp = resp->status = NFS4_OK;
3232 3241 resp->eof = TRUE;
3233 3242 resp->data_len = 0;
3234 3243 resp->data_val = NULL;
3235 3244 resp->mblk = NULL;
3236 3245 /* RDMA */
3237 3246 resp->wlist = args->wlist;
3238 3247 resp->wlist_len = resp->data_len;
3239 3248 *cs->statusp = resp->status = NFS4_OK;
3240 3249 if (resp->wlist)
3241 3250 clist_zero_len(resp->wlist);
3242 3251 goto out;
3243 3252 }
3244 3253
3245 3254 if (args->count == 0) {
3246 3255 *cs->statusp = resp->status = NFS4_OK;
3247 3256 resp->eof = FALSE;
3248 3257 resp->data_len = 0;
3249 3258 resp->data_val = NULL;
3250 3259 resp->mblk = NULL;
3251 3260 /* RDMA */
3252 3261 resp->wlist = args->wlist;
3253 3262 resp->wlist_len = resp->data_len;
3254 3263 if (resp->wlist)
3255 3264 clist_zero_len(resp->wlist);
3256 3265 goto out;
3257 3266 }
3258 3267
3259 3268 /*
3260 3269 * Do not allocate memory more than maximum allowed
3261 3270 * transfer size
3262 3271 */
3263 3272 if (args->count > rfs4_tsize(req))
3264 3273 args->count = rfs4_tsize(req);
3265 3274
3266 3275 if (loaned_buffers) {
3267 3276 uiop = (uio_t *)rfs_setup_xuio(vp);
3268 3277 ASSERT(uiop != NULL);
3269 3278 uiop->uio_segflg = UIO_SYSSPACE;
3270 3279 uiop->uio_loffset = args->offset;
3271 3280 uiop->uio_resid = args->count;
3272 3281
3273 3282 /* Jump to do the read if successful */
3274 3283 if (!VOP_REQZCBUF(vp, UIO_READ, (xuio_t *)uiop, cs->cr, &ct)) {
3275 3284 /*
3276 3285 * Need to hold the vnode until after VOP_RETZCBUF()
3277 3286 * is called.
3278 3287 */
3279 3288 VN_HOLD(vp);
3280 3289 goto doio_read;
3281 3290 }
3282 3291
3283 3292 DTRACE_PROBE2(nfss__i__reqzcbuf_failed, int,
3284 3293 uiop->uio_loffset, int, uiop->uio_resid);
3285 3294
3286 3295 uiop->uio_extflg = 0;
3287 3296
3288 3297 /* failure to setup for zero copy */
3289 3298 rfs_free_xuio((void *)uiop);
3290 3299 loaned_buffers = 0;
3291 3300 }
3292 3301
3293 3302 /*
3294 3303 * If returning data via RDMA Write, then grab the chunk list. If we
3295 3304 * aren't returning READ data w/RDMA_WRITE, then grab a mblk.
3296 3305 */
3297 3306 if (rdma_used) {
3298 3307 mp = NULL;
3299 3308 (void) rdma_get_wchunk(req, &iov, args->wlist);
3300 3309 uio.uio_iov = &iov;
3301 3310 uio.uio_iovcnt = 1;
3302 3311 } else {
3303 3312 /*
3304 3313 * mp will contain the data to be sent out in the read reply.
3305 3314 * It will be freed after the reply has been sent.
3306 3315 */
3307 3316 mp = rfs_read_alloc(args->count, &iovp, &iovcnt);
3308 3317 ASSERT(mp != NULL);
3309 3318 ASSERT(alloc_err == 0);
3310 3319 uio.uio_iov = iovp;
3311 3320 uio.uio_iovcnt = iovcnt;
3312 3321 }
3313 3322
3314 3323 uio.uio_segflg = UIO_SYSSPACE;
3315 3324 uio.uio_extflg = UIO_COPY_CACHED;
3316 3325 uio.uio_loffset = args->offset;
3317 3326 uio.uio_resid = args->count;
3318 3327 uiop = &uio;
3319 3328
3320 3329 doio_read:
3321 3330 error = do_io(FREAD, vp, uiop, 0, cs->cr, &ct);
3322 3331
3323 3332 va.va_mask = AT_SIZE;
3324 3333 verror = VOP_GETATTR(vp, &va, 0, cs->cr, &ct);
3325 3334
3326 3335 if (error) {
3327 3336 if (mp)
3328 3337 freemsg(mp);
3329 3338 *cs->statusp = resp->status = puterrno4(error);
3330 3339 goto out;
3331 3340 }
3332 3341
3333 3342 /* make mblk using zc buffers */
3334 3343 if (loaned_buffers) {
3335 3344 mp = uio_to_mblk(uiop);
3336 3345 ASSERT(mp != NULL);
3337 3346 }
3338 3347
3339 3348 *cs->statusp = resp->status = NFS4_OK;
3340 3349
3341 3350 ASSERT(uiop->uio_resid >= 0);
3342 3351 resp->data_len = args->count - uiop->uio_resid;
3343 3352 if (mp) {
3344 3353 resp->data_val = (char *)mp->b_datap->db_base;
3345 3354 rfs_rndup_mblks(mp, resp->data_len, loaned_buffers);
3346 3355 } else {
3347 3356 resp->data_val = (caddr_t)iov.iov_base;
3348 3357 }
3349 3358
3350 3359 resp->mblk = mp;
3351 3360
3352 3361 if (!verror && offset + resp->data_len == va.va_size)
3353 3362 resp->eof = TRUE;
3354 3363 else
3355 3364 resp->eof = FALSE;
3356 3365
3357 3366 if (rdma_used) {
3358 3367 if (!rdma_setup_read_data4(args, resp)) {
3359 3368 *cs->statusp = resp->status = NFS4ERR_INVAL;
3360 3369 }
3361 3370 } else {
3362 3371 resp->wlist = NULL;
3363 3372 }
3364 3373
3365 3374 out:
3366 3375 if (in_crit)
3367 3376 nbl_end_crit(vp);
3368 3377
3369 3378 if (iovp != NULL)
3370 3379 kmem_free(iovp, iovcnt * sizeof (struct iovec));
3371 3380
3372 3381 DTRACE_NFSV4_2(op__read__done, struct compound_state *, cs,
3373 3382 READ4res *, resp);
3374 3383 }
3375 3384
3376 3385 static void
3377 3386 rfs4_op_read_free(nfs_resop4 *resop)
3378 3387 {
3379 3388 READ4res *resp = &resop->nfs_resop4_u.opread;
3380 3389
3381 3390 if (resp->status == NFS4_OK && resp->mblk != NULL) {
3382 3391 freemsg(resp->mblk);
3383 3392 resp->mblk = NULL;
3384 3393 resp->data_val = NULL;
3385 3394 resp->data_len = 0;
3386 3395 }
3387 3396 }
3388 3397
3389 3398 static void
3390 3399 rfs4_op_readdir_free(nfs_resop4 * resop)
3391 3400 {
3392 3401 READDIR4res *resp = &resop->nfs_resop4_u.opreaddir;
3393 3402
3394 3403 if (resp->status == NFS4_OK && resp->mblk != NULL) {
3395 3404 freeb(resp->mblk);
3396 3405 resp->mblk = NULL;
3397 3406 resp->data_len = 0;
3398 3407 }
3399 3408 }
3400 3409
3401 3410
3402 3411 /* ARGSUSED */
3403 3412 static void
3404 3413 rfs4_op_putpubfh(nfs_argop4 *args, nfs_resop4 *resop, struct svc_req *req,
3405 3414 struct compound_state *cs)
3406 3415 {
3407 3416 PUTPUBFH4res *resp = &resop->nfs_resop4_u.opputpubfh;
3408 3417 int error;
3409 3418 vnode_t *vp;
3410 3419 struct exportinfo *exi, *sav_exi;
3411 3420 nfs_fh4_fmt_t *fh_fmtp;
3412 3421
3413 3422 DTRACE_NFSV4_1(op__putpubfh__start, struct compound_state *, cs);
3414 3423
3415 3424 if (cs->vp) {
3416 3425 VN_RELE(cs->vp);
3417 3426 cs->vp = NULL;
3418 3427 }
3419 3428
3420 3429 if (cs->cr)
3421 3430 crfree(cs->cr);
3422 3431
3423 3432 cs->cr = crdup(cs->basecr);
3424 3433
3425 3434 vp = exi_public->exi_vp;
3426 3435 if (vp == NULL) {
3427 3436 *cs->statusp = resp->status = NFS4ERR_SERVERFAULT;
3428 3437 goto out;
3429 3438 }
3430 3439
3431 3440 error = makefh4(&cs->fh, vp, exi_public);
3432 3441 if (error != 0) {
3433 3442 *cs->statusp = resp->status = puterrno4(error);
3434 3443 goto out;
3435 3444 }
3436 3445 sav_exi = cs->exi;
↓ open down ↓ |
660 lines elided |
↑ open up ↑ |
3437 3446 if (exi_public == exi_root) {
3438 3447 /*
3439 3448 * No filesystem is actually shared public, so we default
3440 3449 * to exi_root. In this case, we must check whether root
3441 3450 * is exported.
3442 3451 */
3443 3452 fh_fmtp = (nfs_fh4_fmt_t *)cs->fh.nfs_fh4_val;
3444 3453
3445 3454 /*
3446 3455 * if root filesystem is exported, the exportinfo struct that we
3447 - * should use is what checkexport4 returns, because root_exi is
3456 + * should use is what checkexport returns, because root_exi is
3448 3457 * actually a mostly empty struct.
3449 3458 */
3450 - exi = checkexport4(&fh_fmtp->fh4_fsid,
3459 + exi = checkexport(&fh_fmtp->fh4_fsid,
3451 3460 (fid_t *)&fh_fmtp->fh4_xlen, NULL);
3452 - cs->exi = ((exi != NULL) ? exi : exi_public);
3461 + if (exi) {
3462 + cs->exi = exi;
3463 + } else {
3464 + exi_hold(exi_public);
3465 + cs->exi = exi_public;
3466 + }
3453 3467 } else {
3454 3468 /*
3455 3469 * it's a properly shared filesystem
3456 3470 */
3471 + exi_hold(exi_public);
3457 3472 cs->exi = exi_public;
3458 3473 }
3459 3474
3460 3475 if (is_system_labeled()) {
3461 3476 bslabel_t *clabel;
3462 3477
3463 3478 ASSERT(req->rq_label != NULL);
3464 3479 clabel = req->rq_label;
3465 3480 DTRACE_PROBE2(tx__rfs4__log__info__opputpubfh__clabel, char *,
3466 3481 "got client label from request(1)",
3467 3482 struct svc_req *, req);
3468 3483 if (!blequal(&l_admin_low->tsl_label, clabel)) {
3469 3484 if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
3470 3485 cs->exi)) {
3471 3486 *cs->statusp = resp->status =
3472 3487 NFS4ERR_SERVERFAULT;
3488 + if (sav_exi)
3489 + exi_rele(sav_exi);
3473 3490 goto out;
3474 3491 }
3475 3492 }
3476 3493 }
3477 3494
3478 3495 VN_HOLD(vp);
3479 3496 cs->vp = vp;
3480 3497
3481 3498 if ((resp->status = call_checkauth4(cs, req)) != NFS4_OK) {
3482 3499 VN_RELE(cs->vp);
3483 3500 cs->vp = NULL;
3501 + exi_rele(cs->exi);
3484 3502 cs->exi = sav_exi;
3485 3503 goto out;
3486 3504 }
3505 + if (sav_exi)
3506 + exi_rele(sav_exi);
3487 3507
3488 3508 *cs->statusp = resp->status = NFS4_OK;
3489 3509 out:
3490 3510 DTRACE_NFSV4_2(op__putpubfh__done, struct compound_state *, cs,
3491 3511 PUTPUBFH4res *, resp);
3492 3512 }
3493 3513
3494 3514 /*
3495 3515 * XXX - issue with put*fh operations. Suppose /export/home is exported.
3496 3516 * Suppose an NFS client goes to mount /export/home/joe. If /export, home,
3497 3517 * or joe have restrictive search permissions, then we shouldn't let
3498 3518 * the client get a file handle. This is easy to enforce. However, we
3499 3519 * don't know what security flavor should be used until we resolve the
3500 3520 * path name. Another complication is uid mapping. If root is
3501 3521 * the user, then it will be mapped to the anonymous user by default,
3502 3522 * but we won't know that till we've resolved the path name. And we won't
3503 3523 * know what the anonymous user is.
3504 3524 * Luckily, SECINFO is specified to take a full filename.
3505 3525 * So what we will have to in rfs4_op_lookup is check that flavor of
3506 3526 * the target object matches that of the request, and if root was the
3507 3527 * caller, check for the root= and anon= options, and if necessary,
3508 3528 * repeat the lookup using the right cred_t. But that's not done yet.
3509 3529 */
3510 3530 /* ARGSUSED */
3511 3531 static void
3512 3532 rfs4_op_putfh(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
3513 3533 struct compound_state *cs)
3514 3534 {
3515 3535 PUTFH4args *args = &argop->nfs_argop4_u.opputfh;
3516 3536 PUTFH4res *resp = &resop->nfs_resop4_u.opputfh;
3517 3537 nfs_fh4_fmt_t *fh_fmtp;
3518 3538
3519 3539 DTRACE_NFSV4_2(op__putfh__start, struct compound_state *, cs,
3520 3540 PUTFH4args *, args);
3521 3541
3522 3542 if (cs->vp) {
3523 3543 VN_RELE(cs->vp);
3524 3544 cs->vp = NULL;
3525 3545 }
3526 3546
3527 3547 if (cs->cr) {
3528 3548 crfree(cs->cr);
↓ open down ↓ |
32 lines elided |
↑ open up ↑ |
3529 3549 cs->cr = NULL;
3530 3550 }
3531 3551
3532 3552
3533 3553 if (args->object.nfs_fh4_len < NFS_FH4_LEN) {
3534 3554 *cs->statusp = resp->status = NFS4ERR_BADHANDLE;
3535 3555 goto out;
3536 3556 }
3537 3557
3538 3558 fh_fmtp = (nfs_fh4_fmt_t *)args->object.nfs_fh4_val;
3539 - cs->exi = checkexport4(&fh_fmtp->fh4_fsid, (fid_t *)&fh_fmtp->fh4_xlen,
3559 + if (cs->exi)
3560 + exi_rele(cs->exi);
3561 + cs->exi = checkexport(&fh_fmtp->fh4_fsid, (fid_t *)&fh_fmtp->fh4_xlen,
3540 3562 NULL);
3541 3563
3542 3564 if (cs->exi == NULL) {
3543 3565 *cs->statusp = resp->status = NFS4ERR_STALE;
3544 3566 goto out;
3545 3567 }
3546 3568
3547 3569 cs->cr = crdup(cs->basecr);
3548 3570
3549 3571 ASSERT(cs->cr != NULL);
3550 3572
3551 3573 if (! (cs->vp = nfs4_fhtovp(&args->object, cs->exi, &resp->status))) {
3552 3574 *cs->statusp = resp->status;
3553 3575 goto out;
3554 3576 }
3555 3577
3556 3578 if ((resp->status = call_checkauth4(cs, req)) != NFS4_OK) {
3557 3579 VN_RELE(cs->vp);
3558 3580 cs->vp = NULL;
3559 3581 goto out;
3560 3582 }
3561 3583
3562 3584 nfs_fh4_copy(&args->object, &cs->fh);
3563 3585 *cs->statusp = resp->status = NFS4_OK;
3564 3586 cs->deleg = FALSE;
3565 3587
3566 3588 out:
3567 3589 DTRACE_NFSV4_2(op__putfh__done, struct compound_state *, cs,
3568 3590 PUTFH4res *, resp);
3569 3591 }
3570 3592
3571 3593 /* ARGSUSED */
3572 3594 static void
3573 3595 rfs4_op_putrootfh(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
3574 3596 struct compound_state *cs)
3575 3597 {
3576 3598 PUTROOTFH4res *resp = &resop->nfs_resop4_u.opputrootfh;
3577 3599 int error;
3578 3600 fid_t fid;
3579 3601 struct exportinfo *exi, *sav_exi;
3580 3602
3581 3603 DTRACE_NFSV4_1(op__putrootfh__start, struct compound_state *, cs);
3582 3604
3583 3605 if (cs->vp) {
3584 3606 VN_RELE(cs->vp);
3585 3607 cs->vp = NULL;
3586 3608 }
3587 3609
3588 3610 if (cs->cr)
3589 3611 crfree(cs->cr);
3590 3612
3591 3613 cs->cr = crdup(cs->basecr);
3592 3614
3593 3615 /*
3594 3616 * Using rootdir, the system root vnode,
3595 3617 * get its fid.
3596 3618 */
3597 3619 bzero(&fid, sizeof (fid));
3598 3620 fid.fid_len = MAXFIDSZ;
3599 3621 error = vop_fid_pseudo(rootdir, &fid);
3600 3622 if (error != 0) {
3601 3623 *cs->statusp = resp->status = puterrno4(error);
3602 3624 goto out;
↓ open down ↓ |
53 lines elided |
↑ open up ↑ |
3603 3625 }
3604 3626
3605 3627 /*
3606 3628 * Then use the root fsid & fid it to find out if it's exported
3607 3629 *
3608 3630 * If the server root isn't exported directly, then
3609 3631 * it should at least be a pseudo export based on
3610 3632 * one or more exports further down in the server's
3611 3633 * file tree.
3612 3634 */
3613 - exi = checkexport4(&rootdir->v_vfsp->vfs_fsid, &fid, NULL);
3635 + exi = checkexport(&rootdir->v_vfsp->vfs_fsid, &fid, NULL);
3614 3636 if (exi == NULL || exi->exi_export.ex_flags & EX_PUBLIC) {
3615 3637 NFS4_DEBUG(rfs4_debug,
3616 3638 (CE_WARN, "rfs4_op_putrootfh: export check failure"));
3617 3639 *cs->statusp = resp->status = NFS4ERR_SERVERFAULT;
3640 + if (exi)
3641 + exi_rele(exi);
3618 3642 goto out;
3619 3643 }
3620 3644
3621 3645 /*
3622 3646 * Now make a filehandle based on the root
3623 3647 * export and root vnode.
3624 3648 */
3625 3649 error = makefh4(&cs->fh, rootdir, exi);
3626 3650 if (error != 0) {
3627 3651 *cs->statusp = resp->status = puterrno4(error);
3652 + exi_rele(exi);
3628 3653 goto out;
3629 3654 }
3630 3655
3631 3656 sav_exi = cs->exi;
3632 3657 cs->exi = exi;
3633 3658
3634 3659 VN_HOLD(rootdir);
3635 3660 cs->vp = rootdir;
3636 3661
3637 3662 if ((resp->status = call_checkauth4(cs, req)) != NFS4_OK) {
3638 3663 VN_RELE(rootdir);
3639 3664 cs->vp = NULL;
3665 + exi_rele(exi);
3640 3666 cs->exi = sav_exi;
3641 3667 goto out;
3642 3668 }
3669 + if (sav_exi)
3670 + exi_rele(sav_exi);
3643 3671
3644 3672 *cs->statusp = resp->status = NFS4_OK;
3645 3673 cs->deleg = FALSE;
3646 3674 out:
3647 3675 DTRACE_NFSV4_2(op__putrootfh__done, struct compound_state *, cs,
3648 3676 PUTROOTFH4res *, resp);
3649 3677 }
3650 3678
3651 3679 /*
3652 3680 * set_rdattr_params sets up the variables used to manage what information
3653 3681 * to get for each directory entry.
3654 3682 */
3655 3683 static nfsstat4
3656 3684 set_rdattr_params(struct nfs4_svgetit_arg *sargp,
3657 3685 bitmap4 attrs, bool_t *need_to_lookup)
3658 3686 {
3659 3687 uint_t va_mask;
3660 3688 nfsstat4 status;
3661 3689 bitmap4 objbits;
3662 3690
3663 3691 status = bitmap4_to_attrmask(attrs, sargp);
3664 3692 if (status != NFS4_OK) {
3665 3693 /*
3666 3694 * could not even figure attr mask
3667 3695 */
3668 3696 return (status);
3669 3697 }
3670 3698 va_mask = sargp->vap->va_mask;
3671 3699
3672 3700 /*
3673 3701 * dirent's d_ino is always correct value for mounted_on_fileid.
3674 3702 * mntdfid_set is set once here, but mounted_on_fileid is
3675 3703 * set in main dirent processing loop for each dirent.
3676 3704 * The mntdfid_set is a simple optimization that lets the
3677 3705 * server attr code avoid work when caller is readdir.
3678 3706 */
3679 3707 sargp->mntdfid_set = TRUE;
3680 3708
3681 3709 /*
3682 3710 * Lookup entry only if client asked for any of the following:
3683 3711 * a) vattr attrs
3684 3712 * b) vfs attrs
3685 3713 * c) attrs w/per-object scope requested (change, filehandle, etc)
3686 3714 * other than mounted_on_fileid (which we can take from dirent)
3687 3715 */
3688 3716 objbits = attrs ? attrs & NFS4_VP_ATTR_MASK : 0;
3689 3717
3690 3718 if (va_mask || sargp->sbp || (objbits & ~FATTR4_MOUNTED_ON_FILEID_MASK))
3691 3719 *need_to_lookup = TRUE;
3692 3720 else
3693 3721 *need_to_lookup = FALSE;
3694 3722
3695 3723 if (sargp->sbp == NULL)
3696 3724 return (NFS4_OK);
3697 3725
3698 3726 /*
3699 3727 * If filesystem attrs are requested, get them now from the
3700 3728 * directory vp, as most entries will have same filesystem. The only
3701 3729 * exception are mounted over entries but we handle
3702 3730 * those as we go (XXX mounted over detection not yet implemented).
3703 3731 */
3704 3732 sargp->vap->va_mask = 0; /* to avoid VOP_GETATTR */
3705 3733 status = bitmap4_get_sysattrs(sargp);
3706 3734 sargp->vap->va_mask = va_mask;
3707 3735
3708 3736 if ((status != NFS4_OK) && sargp->rdattr_error_req) {
3709 3737 /*
3710 3738 * Failed to get filesystem attributes.
3711 3739 * Return a rdattr_error for each entry, but don't fail.
3712 3740 * However, don't get any obj-dependent attrs.
3713 3741 */
3714 3742 sargp->rdattr_error = status; /* for rdattr_error */
3715 3743 *need_to_lookup = FALSE;
3716 3744 /*
3717 3745 * At least get fileid for regular readdir output
3718 3746 */
3719 3747 sargp->vap->va_mask &= AT_NODEID;
3720 3748 status = NFS4_OK;
3721 3749 }
3722 3750
3723 3751 return (status);
3724 3752 }
3725 3753
3726 3754 /*
3727 3755 * readlink: args: CURRENT_FH.
3728 3756 * res: status. If success - CURRENT_FH unchanged, return linktext.
3729 3757 */
3730 3758
3731 3759 /* ARGSUSED */
3732 3760 static void
3733 3761 rfs4_op_readlink(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
3734 3762 struct compound_state *cs)
3735 3763 {
3736 3764 READLINK4res *resp = &resop->nfs_resop4_u.opreadlink;
3737 3765 int error;
3738 3766 vnode_t *vp;
3739 3767 struct iovec iov;
3740 3768 struct vattr va;
3741 3769 struct uio uio;
3742 3770 char *data;
3743 3771 struct sockaddr *ca;
3744 3772 char *name = NULL;
3745 3773 int is_referral;
3746 3774
3747 3775 DTRACE_NFSV4_1(op__readlink__start, struct compound_state *, cs);
3748 3776
3749 3777 /* CURRENT_FH: directory */
3750 3778 vp = cs->vp;
3751 3779 if (vp == NULL) {
3752 3780 *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
3753 3781 goto out;
3754 3782 }
3755 3783
3756 3784 if (cs->access == CS_ACCESS_DENIED) {
3757 3785 *cs->statusp = resp->status = NFS4ERR_ACCESS;
3758 3786 goto out;
3759 3787 }
3760 3788
3761 3789 /* Is it a referral? */
3762 3790 if (vn_is_nfs_reparse(vp, cs->cr) && client_is_downrev(req)) {
3763 3791
3764 3792 is_referral = 1;
3765 3793
3766 3794 } else {
3767 3795
3768 3796 is_referral = 0;
3769 3797
3770 3798 if (vp->v_type == VDIR) {
3771 3799 *cs->statusp = resp->status = NFS4ERR_ISDIR;
3772 3800 goto out;
3773 3801 }
3774 3802
3775 3803 if (vp->v_type != VLNK) {
3776 3804 *cs->statusp = resp->status = NFS4ERR_INVAL;
3777 3805 goto out;
3778 3806 }
3779 3807
3780 3808 }
3781 3809
3782 3810 va.va_mask = AT_MODE;
3783 3811 error = VOP_GETATTR(vp, &va, 0, cs->cr, NULL);
3784 3812 if (error) {
3785 3813 *cs->statusp = resp->status = puterrno4(error);
3786 3814 goto out;
3787 3815 }
3788 3816
3789 3817 if (MANDLOCK(vp, va.va_mode)) {
3790 3818 *cs->statusp = resp->status = NFS4ERR_ACCESS;
3791 3819 goto out;
3792 3820 }
3793 3821
3794 3822 data = kmem_alloc(MAXPATHLEN + 1, KM_SLEEP);
3795 3823
3796 3824 if (is_referral) {
3797 3825 char *s;
3798 3826 size_t strsz;
3799 3827
3800 3828 /* Get an artificial symlink based on a referral */
3801 3829 s = build_symlink(vp, cs->cr, &strsz);
3802 3830 global_svstat_ptr[4][NFS_REFERLINKS].value.ui64++;
3803 3831 DTRACE_PROBE2(nfs4serv__func__referral__reflink,
3804 3832 vnode_t *, vp, char *, s);
3805 3833 if (s == NULL)
3806 3834 error = EINVAL;
3807 3835 else {
3808 3836 error = 0;
3809 3837 (void) strlcpy(data, s, MAXPATHLEN + 1);
3810 3838 kmem_free(s, strsz);
3811 3839 }
3812 3840
3813 3841 } else {
3814 3842
3815 3843 iov.iov_base = data;
3816 3844 iov.iov_len = MAXPATHLEN;
3817 3845 uio.uio_iov = &iov;
3818 3846 uio.uio_iovcnt = 1;
3819 3847 uio.uio_segflg = UIO_SYSSPACE;
3820 3848 uio.uio_extflg = UIO_COPY_CACHED;
3821 3849 uio.uio_loffset = 0;
3822 3850 uio.uio_resid = MAXPATHLEN;
3823 3851
3824 3852 error = VOP_READLINK(vp, &uio, cs->cr, NULL);
3825 3853
3826 3854 if (!error)
3827 3855 *(data + MAXPATHLEN - uio.uio_resid) = '\0';
3828 3856 }
3829 3857
3830 3858 if (error) {
3831 3859 kmem_free((caddr_t)data, (uint_t)MAXPATHLEN + 1);
3832 3860 *cs->statusp = resp->status = puterrno4(error);
3833 3861 goto out;
3834 3862 }
3835 3863
3836 3864 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
3837 3865 name = nfscmd_convname(ca, cs->exi, data, NFSCMD_CONV_OUTBOUND,
3838 3866 MAXPATHLEN + 1);
3839 3867
3840 3868 if (name == NULL) {
3841 3869 /*
3842 3870 * Even though the conversion failed, we return
3843 3871 * something. We just don't translate it.
3844 3872 */
3845 3873 name = data;
3846 3874 }
3847 3875
3848 3876 /*
3849 3877 * treat link name as data
3850 3878 */
3851 3879 (void) str_to_utf8(name, (utf8string *)&resp->link);
3852 3880
3853 3881 if (name != data)
3854 3882 kmem_free(name, MAXPATHLEN + 1);
3855 3883 kmem_free((caddr_t)data, (uint_t)MAXPATHLEN + 1);
3856 3884 *cs->statusp = resp->status = NFS4_OK;
3857 3885
3858 3886 out:
3859 3887 DTRACE_NFSV4_2(op__readlink__done, struct compound_state *, cs,
3860 3888 READLINK4res *, resp);
3861 3889 }
3862 3890
3863 3891 static void
3864 3892 rfs4_op_readlink_free(nfs_resop4 *resop)
3865 3893 {
3866 3894 READLINK4res *resp = &resop->nfs_resop4_u.opreadlink;
3867 3895 utf8string *symlink = (utf8string *)&resp->link;
3868 3896
3869 3897 if (symlink->utf8string_val) {
3870 3898 UTF8STRING_FREE(*symlink)
3871 3899 }
3872 3900 }
3873 3901
3874 3902 /*
3875 3903 * release_lockowner:
3876 3904 * Release any state associated with the supplied
3877 3905 * lockowner. Note if any lo_state is holding locks we will not
3878 3906 * rele that lo_state and thus the lockowner will not be destroyed.
3879 3907 * A client using lock after the lock owner stateid has been released
3880 3908 * will suffer the consequence of NFS4ERR_BAD_STATEID and would have
3881 3909 * to reissue the lock with new_lock_owner set to TRUE.
3882 3910 * args: lock_owner
3883 3911 * res: status
3884 3912 */
3885 3913 /* ARGSUSED */
3886 3914 static void
3887 3915 rfs4_op_release_lockowner(nfs_argop4 *argop, nfs_resop4 *resop,
3888 3916 struct svc_req *req, struct compound_state *cs)
3889 3917 {
3890 3918 RELEASE_LOCKOWNER4args *ap = &argop->nfs_argop4_u.oprelease_lockowner;
3891 3919 RELEASE_LOCKOWNER4res *resp = &resop->nfs_resop4_u.oprelease_lockowner;
3892 3920 rfs4_lockowner_t *lo;
3893 3921 rfs4_openowner_t *oo;
3894 3922 rfs4_state_t *sp;
3895 3923 rfs4_lo_state_t *lsp;
3896 3924 rfs4_client_t *cp;
3897 3925 bool_t create = FALSE;
3898 3926 locklist_t *llist;
3899 3927 sysid_t sysid;
3900 3928
3901 3929 DTRACE_NFSV4_2(op__release__lockowner__start, struct compound_state *,
3902 3930 cs, RELEASE_LOCKOWNER4args *, ap);
3903 3931
3904 3932 /* Make sure there is a clientid around for this request */
3905 3933 cp = rfs4_findclient_by_id(ap->lock_owner.clientid, FALSE);
3906 3934
3907 3935 if (cp == NULL) {
3908 3936 *cs->statusp = resp->status =
3909 3937 rfs4_check_clientid(&ap->lock_owner.clientid, 0);
3910 3938 goto out;
3911 3939 }
3912 3940 rfs4_client_rele(cp);
3913 3941
3914 3942 lo = rfs4_findlockowner(&ap->lock_owner, &create);
3915 3943 if (lo == NULL) {
3916 3944 *cs->statusp = resp->status = NFS4_OK;
3917 3945 goto out;
3918 3946 }
3919 3947 ASSERT(lo->rl_client != NULL);
3920 3948
3921 3949 /*
3922 3950 * Check for EXPIRED client. If so will reap state with in a lease
3923 3951 * period or on next set_clientid_confirm step
3924 3952 */
3925 3953 if (rfs4_lease_expired(lo->rl_client)) {
3926 3954 rfs4_lockowner_rele(lo);
3927 3955 *cs->statusp = resp->status = NFS4ERR_EXPIRED;
3928 3956 goto out;
3929 3957 }
3930 3958
3931 3959 /*
3932 3960 * If no sysid has been assigned, then no locks exist; just return.
3933 3961 */
3934 3962 rfs4_dbe_lock(lo->rl_client->rc_dbe);
3935 3963 if (lo->rl_client->rc_sysidt == LM_NOSYSID) {
3936 3964 rfs4_lockowner_rele(lo);
3937 3965 rfs4_dbe_unlock(lo->rl_client->rc_dbe);
3938 3966 goto out;
3939 3967 }
3940 3968
3941 3969 sysid = lo->rl_client->rc_sysidt;
3942 3970 rfs4_dbe_unlock(lo->rl_client->rc_dbe);
3943 3971
3944 3972 /*
3945 3973 * Mark the lockowner invalid.
3946 3974 */
3947 3975 rfs4_dbe_hide(lo->rl_dbe);
3948 3976
3949 3977 /*
3950 3978 * sysid-pid pair should now not be used since the lockowner is
3951 3979 * invalid. If the client were to instantiate the lockowner again
3952 3980 * it would be assigned a new pid. Thus we can get the list of
3953 3981 * current locks.
3954 3982 */
3955 3983
3956 3984 llist = flk_get_active_locks(sysid, lo->rl_pid);
3957 3985 /* If we are still holding locks fail */
3958 3986 if (llist != NULL) {
3959 3987
3960 3988 *cs->statusp = resp->status = NFS4ERR_LOCKS_HELD;
3961 3989
3962 3990 flk_free_locklist(llist);
3963 3991 /*
3964 3992 * We need to unhide the lockowner so the client can
3965 3993 * try it again. The bad thing here is if the client
3966 3994 * has a logic error that took it here in the first place
3967 3995 * he probably has lost accounting of the locks that it
3968 3996 * is holding. So we may have dangling state until the
3969 3997 * open owner state is reaped via close. One scenario
3970 3998 * that could possibly occur is that the client has
3971 3999 * sent the unlock request(s) in separate threads
3972 4000 * and has not waited for the replies before sending the
3973 4001 * RELEASE_LOCKOWNER request. Presumably, it would expect
3974 4002 * and deal appropriately with NFS4ERR_LOCKS_HELD, by
3975 4003 * reissuing the request.
3976 4004 */
3977 4005 rfs4_dbe_unhide(lo->rl_dbe);
3978 4006 rfs4_lockowner_rele(lo);
3979 4007 goto out;
3980 4008 }
3981 4009
3982 4010 /*
3983 4011 * For the corresponding client we need to check each open
3984 4012 * owner for any opens that have lockowner state associated
3985 4013 * with this lockowner.
3986 4014 */
3987 4015
3988 4016 rfs4_dbe_lock(lo->rl_client->rc_dbe);
3989 4017 for (oo = list_head(&lo->rl_client->rc_openownerlist); oo != NULL;
3990 4018 oo = list_next(&lo->rl_client->rc_openownerlist, oo)) {
3991 4019
3992 4020 rfs4_dbe_lock(oo->ro_dbe);
3993 4021 for (sp = list_head(&oo->ro_statelist); sp != NULL;
3994 4022 sp = list_next(&oo->ro_statelist, sp)) {
3995 4023
3996 4024 rfs4_dbe_lock(sp->rs_dbe);
3997 4025 for (lsp = list_head(&sp->rs_lostatelist);
3998 4026 lsp != NULL;
3999 4027 lsp = list_next(&sp->rs_lostatelist, lsp)) {
4000 4028 if (lsp->rls_locker == lo) {
4001 4029 rfs4_dbe_lock(lsp->rls_dbe);
4002 4030 rfs4_dbe_invalidate(lsp->rls_dbe);
4003 4031 rfs4_dbe_unlock(lsp->rls_dbe);
4004 4032 }
4005 4033 }
4006 4034 rfs4_dbe_unlock(sp->rs_dbe);
4007 4035 }
4008 4036 rfs4_dbe_unlock(oo->ro_dbe);
4009 4037 }
4010 4038 rfs4_dbe_unlock(lo->rl_client->rc_dbe);
4011 4039
4012 4040 rfs4_lockowner_rele(lo);
4013 4041
4014 4042 *cs->statusp = resp->status = NFS4_OK;
4015 4043
4016 4044 out:
4017 4045 DTRACE_NFSV4_2(op__release__lockowner__done, struct compound_state *,
4018 4046 cs, RELEASE_LOCKOWNER4res *, resp);
4019 4047 }
4020 4048
4021 4049 /*
4022 4050 * short utility function to lookup a file and recall the delegation
4023 4051 */
4024 4052 static rfs4_file_t *
4025 4053 rfs4_lookup_and_findfile(vnode_t *dvp, char *nm, vnode_t **vpp,
4026 4054 int *lkup_error, cred_t *cr)
4027 4055 {
4028 4056 vnode_t *vp;
4029 4057 rfs4_file_t *fp = NULL;
4030 4058 bool_t fcreate = FALSE;
4031 4059 int error;
4032 4060
4033 4061 if (vpp)
4034 4062 *vpp = NULL;
4035 4063
4036 4064 if ((error = VOP_LOOKUP(dvp, nm, &vp, NULL, 0, NULL, cr, NULL, NULL,
4037 4065 NULL)) == 0) {
4038 4066 if (vp->v_type == VREG)
4039 4067 fp = rfs4_findfile(vp, NULL, &fcreate);
4040 4068 if (vpp)
4041 4069 *vpp = vp;
4042 4070 else
4043 4071 VN_RELE(vp);
4044 4072 }
4045 4073
4046 4074 if (lkup_error)
4047 4075 *lkup_error = error;
4048 4076
4049 4077 return (fp);
4050 4078 }
4051 4079
4052 4080 /*
4053 4081 * remove: args: CURRENT_FH: directory; name.
4054 4082 * res: status. If success - CURRENT_FH unchanged, return change_info
4055 4083 * for directory.
4056 4084 */
4057 4085 /* ARGSUSED */
4058 4086 static void
4059 4087 rfs4_op_remove(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
4060 4088 struct compound_state *cs)
4061 4089 {
4062 4090 REMOVE4args *args = &argop->nfs_argop4_u.opremove;
4063 4091 REMOVE4res *resp = &resop->nfs_resop4_u.opremove;
4064 4092 int error;
4065 4093 vnode_t *dvp, *vp;
4066 4094 struct vattr bdva, idva, adva;
4067 4095 char *nm;
4068 4096 uint_t len;
4069 4097 rfs4_file_t *fp;
4070 4098 int in_crit = 0;
4071 4099 bslabel_t *clabel;
4072 4100 struct sockaddr *ca;
4073 4101 char *name = NULL;
4074 4102 nfsstat4 status;
4075 4103
4076 4104 DTRACE_NFSV4_2(op__remove__start, struct compound_state *, cs,
4077 4105 REMOVE4args *, args);
4078 4106
4079 4107 /* CURRENT_FH: directory */
4080 4108 dvp = cs->vp;
4081 4109 if (dvp == NULL) {
4082 4110 *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
4083 4111 goto out;
4084 4112 }
4085 4113
4086 4114 if (cs->access == CS_ACCESS_DENIED) {
4087 4115 *cs->statusp = resp->status = NFS4ERR_ACCESS;
4088 4116 goto out;
4089 4117 }
4090 4118
4091 4119 /*
4092 4120 * If there is an unshared filesystem mounted on this vnode,
4093 4121 * Do not allow to remove anything in this directory.
4094 4122 */
4095 4123 if (vn_ismntpt(dvp)) {
4096 4124 *cs->statusp = resp->status = NFS4ERR_ACCESS;
4097 4125 goto out;
4098 4126 }
4099 4127
4100 4128 if (dvp->v_type != VDIR) {
4101 4129 *cs->statusp = resp->status = NFS4ERR_NOTDIR;
4102 4130 goto out;
4103 4131 }
4104 4132
4105 4133 status = utf8_dir_verify(&args->target);
4106 4134 if (status != NFS4_OK) {
4107 4135 *cs->statusp = resp->status = status;
4108 4136 goto out;
4109 4137 }
4110 4138
4111 4139 /*
4112 4140 * Lookup the file so that we can check if it's a directory
4113 4141 */
4114 4142 nm = utf8_to_fn(&args->target, &len, NULL);
4115 4143 if (nm == NULL) {
4116 4144 *cs->statusp = resp->status = NFS4ERR_INVAL;
4117 4145 goto out;
4118 4146 }
4119 4147
4120 4148 if (len > MAXNAMELEN) {
4121 4149 *cs->statusp = resp->status = NFS4ERR_NAMETOOLONG;
4122 4150 kmem_free(nm, len);
4123 4151 goto out;
4124 4152 }
4125 4153
4126 4154 if (rdonly4(req, cs)) {
4127 4155 *cs->statusp = resp->status = NFS4ERR_ROFS;
4128 4156 kmem_free(nm, len);
4129 4157 goto out;
4130 4158 }
4131 4159
4132 4160 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
4133 4161 name = nfscmd_convname(ca, cs->exi, nm, NFSCMD_CONV_INBOUND,
4134 4162 MAXPATHLEN + 1);
4135 4163
4136 4164 if (name == NULL) {
4137 4165 *cs->statusp = resp->status = NFS4ERR_INVAL;
4138 4166 kmem_free(nm, len);
4139 4167 goto out;
4140 4168 }
4141 4169
4142 4170 /*
4143 4171 * Lookup the file to determine type and while we are see if
4144 4172 * there is a file struct around and check for delegation.
4145 4173 * We don't need to acquire va_seq before this lookup, if
4146 4174 * it causes an update, cinfo.before will not match, which will
4147 4175 * trigger a cache flush even if atomic is TRUE.
4148 4176 */
4149 4177 if (fp = rfs4_lookup_and_findfile(dvp, name, &vp, &error, cs->cr)) {
4150 4178 if (rfs4_check_delegated_byfp(FWRITE, fp, TRUE, TRUE, TRUE,
4151 4179 NULL)) {
4152 4180 VN_RELE(vp);
4153 4181 rfs4_file_rele(fp);
4154 4182 *cs->statusp = resp->status = NFS4ERR_DELAY;
4155 4183 if (nm != name)
4156 4184 kmem_free(name, MAXPATHLEN + 1);
4157 4185 kmem_free(nm, len);
4158 4186 goto out;
4159 4187 }
4160 4188 }
4161 4189
4162 4190 /* Didn't find anything to remove */
4163 4191 if (vp == NULL) {
4164 4192 *cs->statusp = resp->status = error;
4165 4193 if (nm != name)
4166 4194 kmem_free(name, MAXPATHLEN + 1);
4167 4195 kmem_free(nm, len);
4168 4196 goto out;
4169 4197 }
4170 4198
4171 4199 if (nbl_need_check(vp)) {
4172 4200 nbl_start_crit(vp, RW_READER);
4173 4201 in_crit = 1;
4174 4202 if (nbl_conflict(vp, NBL_REMOVE, 0, 0, 0, NULL)) {
4175 4203 *cs->statusp = resp->status = NFS4ERR_FILE_OPEN;
4176 4204 if (nm != name)
4177 4205 kmem_free(name, MAXPATHLEN + 1);
4178 4206 kmem_free(nm, len);
4179 4207 nbl_end_crit(vp);
4180 4208 VN_RELE(vp);
4181 4209 if (fp) {
4182 4210 rfs4_clear_dont_grant(fp);
4183 4211 rfs4_file_rele(fp);
4184 4212 }
4185 4213 goto out;
4186 4214 }
4187 4215 }
4188 4216
4189 4217 /* check label before allowing removal */
4190 4218 if (is_system_labeled()) {
4191 4219 ASSERT(req->rq_label != NULL);
4192 4220 clabel = req->rq_label;
4193 4221 DTRACE_PROBE2(tx__rfs4__log__info__opremove__clabel, char *,
4194 4222 "got client label from request(1)",
4195 4223 struct svc_req *, req);
4196 4224 if (!blequal(&l_admin_low->tsl_label, clabel)) {
4197 4225 if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK,
4198 4226 cs->exi)) {
4199 4227 *cs->statusp = resp->status = NFS4ERR_ACCESS;
4200 4228 if (name != nm)
4201 4229 kmem_free(name, MAXPATHLEN + 1);
4202 4230 kmem_free(nm, len);
4203 4231 if (in_crit)
4204 4232 nbl_end_crit(vp);
4205 4233 VN_RELE(vp);
4206 4234 if (fp) {
4207 4235 rfs4_clear_dont_grant(fp);
4208 4236 rfs4_file_rele(fp);
4209 4237 }
4210 4238 goto out;
4211 4239 }
4212 4240 }
4213 4241 }
4214 4242
4215 4243 /* Get dir "before" change value */
4216 4244 bdva.va_mask = AT_CTIME|AT_SEQ;
4217 4245 error = VOP_GETATTR(dvp, &bdva, 0, cs->cr, NULL);
4218 4246 if (error) {
4219 4247 *cs->statusp = resp->status = puterrno4(error);
4220 4248 if (nm != name)
4221 4249 kmem_free(name, MAXPATHLEN + 1);
4222 4250 kmem_free(nm, len);
4223 4251 if (in_crit)
4224 4252 nbl_end_crit(vp);
4225 4253 VN_RELE(vp);
4226 4254 if (fp) {
4227 4255 rfs4_clear_dont_grant(fp);
4228 4256 rfs4_file_rele(fp);
4229 4257 }
4230 4258 goto out;
4231 4259 }
4232 4260 NFS4_SET_FATTR4_CHANGE(resp->cinfo.before, bdva.va_ctime)
4233 4261
4234 4262 /* Actually do the REMOVE operation */
4235 4263 if (vp->v_type == VDIR) {
4236 4264 /*
4237 4265 * Can't remove a directory that has a mounted-on filesystem.
4238 4266 */
4239 4267 if (vn_ismntpt(vp)) {
4240 4268 error = EACCES;
4241 4269 } else {
4242 4270 /*
4243 4271 * System V defines rmdir to return EEXIST,
4244 4272 * not ENOTEMPTY, if the directory is not
4245 4273 * empty. A System V NFS server needs to map
4246 4274 * NFS4ERR_EXIST to NFS4ERR_NOTEMPTY to
4247 4275 * transmit over the wire.
4248 4276 */
4249 4277 if ((error = VOP_RMDIR(dvp, name, rootdir, cs->cr,
4250 4278 NULL, 0)) == EEXIST)
4251 4279 error = ENOTEMPTY;
4252 4280 }
4253 4281 } else {
4254 4282 if ((error = VOP_REMOVE(dvp, name, cs->cr, NULL, 0)) == 0 &&
4255 4283 fp != NULL) {
4256 4284 struct vattr va;
4257 4285 vnode_t *tvp;
4258 4286
4259 4287 rfs4_dbe_lock(fp->rf_dbe);
4260 4288 tvp = fp->rf_vp;
4261 4289 if (tvp)
4262 4290 VN_HOLD(tvp);
4263 4291 rfs4_dbe_unlock(fp->rf_dbe);
4264 4292
4265 4293 if (tvp) {
4266 4294 /*
4267 4295 * This is va_seq safe because we are not
4268 4296 * manipulating dvp.
4269 4297 */
4270 4298 va.va_mask = AT_NLINK;
4271 4299 if (!VOP_GETATTR(tvp, &va, 0, cs->cr, NULL) &&
4272 4300 va.va_nlink == 0) {
4273 4301 /* Remove state on file remove */
4274 4302 if (in_crit) {
4275 4303 nbl_end_crit(vp);
4276 4304 in_crit = 0;
4277 4305 }
4278 4306 rfs4_close_all_state(fp);
4279 4307 }
4280 4308 VN_RELE(tvp);
4281 4309 }
4282 4310 }
4283 4311 }
4284 4312
4285 4313 if (in_crit)
4286 4314 nbl_end_crit(vp);
4287 4315 VN_RELE(vp);
4288 4316
4289 4317 if (fp) {
4290 4318 rfs4_clear_dont_grant(fp);
4291 4319 rfs4_file_rele(fp);
4292 4320 }
4293 4321 if (nm != name)
4294 4322 kmem_free(name, MAXPATHLEN + 1);
4295 4323 kmem_free(nm, len);
4296 4324
4297 4325 if (error) {
4298 4326 *cs->statusp = resp->status = puterrno4(error);
4299 4327 goto out;
4300 4328 }
4301 4329
4302 4330 /*
4303 4331 * Get the initial "after" sequence number, if it fails, set to zero
4304 4332 */
4305 4333 idva.va_mask = AT_SEQ;
4306 4334 if (VOP_GETATTR(dvp, &idva, 0, cs->cr, NULL))
4307 4335 idva.va_seq = 0;
4308 4336
4309 4337 /*
4310 4338 * Force modified data and metadata out to stable storage.
4311 4339 */
4312 4340 (void) VOP_FSYNC(dvp, 0, cs->cr, NULL);
4313 4341
4314 4342 /*
4315 4343 * Get "after" change value, if it fails, simply return the
4316 4344 * before value.
4317 4345 */
4318 4346 adva.va_mask = AT_CTIME|AT_SEQ;
4319 4347 if (VOP_GETATTR(dvp, &adva, 0, cs->cr, NULL)) {
4320 4348 adva.va_ctime = bdva.va_ctime;
4321 4349 adva.va_seq = 0;
4322 4350 }
4323 4351
4324 4352 NFS4_SET_FATTR4_CHANGE(resp->cinfo.after, adva.va_ctime)
4325 4353
4326 4354 /*
4327 4355 * The cinfo.atomic = TRUE only if we have
4328 4356 * non-zero va_seq's, and it has incremented by exactly one
4329 4357 * during the VOP_REMOVE/RMDIR and it didn't change during
4330 4358 * the VOP_FSYNC.
4331 4359 */
4332 4360 if (bdva.va_seq && idva.va_seq && adva.va_seq &&
4333 4361 idva.va_seq == (bdva.va_seq + 1) && idva.va_seq == adva.va_seq)
4334 4362 resp->cinfo.atomic = TRUE;
4335 4363 else
4336 4364 resp->cinfo.atomic = FALSE;
4337 4365
4338 4366 *cs->statusp = resp->status = NFS4_OK;
4339 4367
4340 4368 out:
4341 4369 DTRACE_NFSV4_2(op__remove__done, struct compound_state *, cs,
4342 4370 REMOVE4res *, resp);
4343 4371 }
4344 4372
4345 4373 /*
4346 4374 * rename: args: SAVED_FH: from directory, CURRENT_FH: target directory,
4347 4375 * oldname and newname.
4348 4376 * res: status. If success - CURRENT_FH unchanged, return change_info
4349 4377 * for both from and target directories.
4350 4378 */
4351 4379 /* ARGSUSED */
4352 4380 static void
4353 4381 rfs4_op_rename(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
4354 4382 struct compound_state *cs)
4355 4383 {
4356 4384 RENAME4args *args = &argop->nfs_argop4_u.oprename;
4357 4385 RENAME4res *resp = &resop->nfs_resop4_u.oprename;
4358 4386 int error;
4359 4387 vnode_t *odvp;
4360 4388 vnode_t *ndvp;
4361 4389 vnode_t *srcvp, *targvp;
4362 4390 struct vattr obdva, oidva, oadva;
4363 4391 struct vattr nbdva, nidva, nadva;
4364 4392 char *onm, *nnm;
4365 4393 uint_t olen, nlen;
4366 4394 rfs4_file_t *fp, *sfp;
4367 4395 int in_crit_src, in_crit_targ;
4368 4396 int fp_rele_grant_hold, sfp_rele_grant_hold;
4369 4397 bslabel_t *clabel;
4370 4398 struct sockaddr *ca;
4371 4399 char *converted_onm = NULL;
4372 4400 char *converted_nnm = NULL;
4373 4401 nfsstat4 status;
4374 4402
4375 4403 DTRACE_NFSV4_2(op__rename__start, struct compound_state *, cs,
4376 4404 RENAME4args *, args);
4377 4405
4378 4406 fp = sfp = NULL;
4379 4407 srcvp = targvp = NULL;
4380 4408 in_crit_src = in_crit_targ = 0;
4381 4409 fp_rele_grant_hold = sfp_rele_grant_hold = 0;
4382 4410
4383 4411 /* CURRENT_FH: target directory */
4384 4412 ndvp = cs->vp;
4385 4413 if (ndvp == NULL) {
4386 4414 *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
4387 4415 goto out;
4388 4416 }
4389 4417
4390 4418 /* SAVED_FH: from directory */
4391 4419 odvp = cs->saved_vp;
4392 4420 if (odvp == NULL) {
4393 4421 *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
4394 4422 goto out;
4395 4423 }
4396 4424
4397 4425 if (cs->access == CS_ACCESS_DENIED) {
4398 4426 *cs->statusp = resp->status = NFS4ERR_ACCESS;
4399 4427 goto out;
4400 4428 }
4401 4429
4402 4430 /*
4403 4431 * If there is an unshared filesystem mounted on this vnode,
4404 4432 * do not allow to rename objects in this directory.
4405 4433 */
4406 4434 if (vn_ismntpt(odvp)) {
4407 4435 *cs->statusp = resp->status = NFS4ERR_ACCESS;
4408 4436 goto out;
4409 4437 }
4410 4438
4411 4439 /*
4412 4440 * If there is an unshared filesystem mounted on this vnode,
4413 4441 * do not allow to rename to this directory.
4414 4442 */
4415 4443 if (vn_ismntpt(ndvp)) {
4416 4444 *cs->statusp = resp->status = NFS4ERR_ACCESS;
4417 4445 goto out;
4418 4446 }
4419 4447
4420 4448 if (odvp->v_type != VDIR || ndvp->v_type != VDIR) {
4421 4449 *cs->statusp = resp->status = NFS4ERR_NOTDIR;
4422 4450 goto out;
4423 4451 }
4424 4452
4425 4453 if (cs->saved_exi != cs->exi) {
4426 4454 *cs->statusp = resp->status = NFS4ERR_XDEV;
4427 4455 goto out;
4428 4456 }
4429 4457
4430 4458 status = utf8_dir_verify(&args->oldname);
4431 4459 if (status != NFS4_OK) {
4432 4460 *cs->statusp = resp->status = status;
4433 4461 goto out;
4434 4462 }
4435 4463
4436 4464 status = utf8_dir_verify(&args->newname);
4437 4465 if (status != NFS4_OK) {
4438 4466 *cs->statusp = resp->status = status;
4439 4467 goto out;
4440 4468 }
4441 4469
4442 4470 onm = utf8_to_fn(&args->oldname, &olen, NULL);
4443 4471 if (onm == NULL) {
4444 4472 *cs->statusp = resp->status = NFS4ERR_INVAL;
4445 4473 goto out;
4446 4474 }
4447 4475 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
4448 4476 nlen = MAXPATHLEN + 1;
4449 4477 converted_onm = nfscmd_convname(ca, cs->exi, onm, NFSCMD_CONV_INBOUND,
4450 4478 nlen);
4451 4479
4452 4480 if (converted_onm == NULL) {
4453 4481 *cs->statusp = resp->status = NFS4ERR_INVAL;
4454 4482 kmem_free(onm, olen);
4455 4483 goto out;
4456 4484 }
4457 4485
4458 4486 nnm = utf8_to_fn(&args->newname, &nlen, NULL);
4459 4487 if (nnm == NULL) {
4460 4488 *cs->statusp = resp->status = NFS4ERR_INVAL;
4461 4489 if (onm != converted_onm)
4462 4490 kmem_free(converted_onm, MAXPATHLEN + 1);
4463 4491 kmem_free(onm, olen);
4464 4492 goto out;
4465 4493 }
4466 4494 converted_nnm = nfscmd_convname(ca, cs->exi, nnm, NFSCMD_CONV_INBOUND,
4467 4495 MAXPATHLEN + 1);
4468 4496
4469 4497 if (converted_nnm == NULL) {
4470 4498 *cs->statusp = resp->status = NFS4ERR_INVAL;
4471 4499 kmem_free(nnm, nlen);
4472 4500 nnm = NULL;
4473 4501 if (onm != converted_onm)
4474 4502 kmem_free(converted_onm, MAXPATHLEN + 1);
4475 4503 kmem_free(onm, olen);
4476 4504 goto out;
4477 4505 }
4478 4506
4479 4507
4480 4508 if (olen > MAXNAMELEN || nlen > MAXNAMELEN) {
4481 4509 *cs->statusp = resp->status = NFS4ERR_NAMETOOLONG;
4482 4510 kmem_free(onm, olen);
4483 4511 kmem_free(nnm, nlen);
4484 4512 goto out;
4485 4513 }
4486 4514
4487 4515
4488 4516 if (rdonly4(req, cs)) {
4489 4517 *cs->statusp = resp->status = NFS4ERR_ROFS;
4490 4518 if (onm != converted_onm)
4491 4519 kmem_free(converted_onm, MAXPATHLEN + 1);
4492 4520 kmem_free(onm, olen);
4493 4521 if (nnm != converted_nnm)
4494 4522 kmem_free(converted_nnm, MAXPATHLEN + 1);
4495 4523 kmem_free(nnm, nlen);
4496 4524 goto out;
4497 4525 }
4498 4526
4499 4527 /* check label of the target dir */
4500 4528 if (is_system_labeled()) {
4501 4529 ASSERT(req->rq_label != NULL);
4502 4530 clabel = req->rq_label;
4503 4531 DTRACE_PROBE2(tx__rfs4__log__info__oprename__clabel, char *,
4504 4532 "got client label from request(1)",
4505 4533 struct svc_req *, req);
4506 4534 if (!blequal(&l_admin_low->tsl_label, clabel)) {
4507 4535 if (!do_rfs_label_check(clabel, ndvp,
4508 4536 EQUALITY_CHECK, cs->exi)) {
4509 4537 *cs->statusp = resp->status = NFS4ERR_ACCESS;
4510 4538 goto err_out;
4511 4539 }
4512 4540 }
4513 4541 }
4514 4542
4515 4543 /*
4516 4544 * Is the source a file and have a delegation?
4517 4545 * We don't need to acquire va_seq before these lookups, if
4518 4546 * it causes an update, cinfo.before will not match, which will
4519 4547 * trigger a cache flush even if atomic is TRUE.
4520 4548 */
4521 4549 if (sfp = rfs4_lookup_and_findfile(odvp, converted_onm, &srcvp,
4522 4550 &error, cs->cr)) {
4523 4551 if (rfs4_check_delegated_byfp(FWRITE, sfp, TRUE, TRUE, TRUE,
4524 4552 NULL)) {
4525 4553 *cs->statusp = resp->status = NFS4ERR_DELAY;
4526 4554 goto err_out;
4527 4555 }
4528 4556 }
4529 4557
4530 4558 if (srcvp == NULL) {
4531 4559 *cs->statusp = resp->status = puterrno4(error);
4532 4560 if (onm != converted_onm)
4533 4561 kmem_free(converted_onm, MAXPATHLEN + 1);
4534 4562 kmem_free(onm, olen);
4535 4563 if (nnm != converted_nnm)
4536 4564 kmem_free(converted_nnm, MAXPATHLEN + 1);
4537 4565 kmem_free(nnm, nlen);
4538 4566 goto out;
4539 4567 }
4540 4568
4541 4569 sfp_rele_grant_hold = 1;
4542 4570
4543 4571 /* Does the destination exist and a file and have a delegation? */
4544 4572 if (fp = rfs4_lookup_and_findfile(ndvp, converted_nnm, &targvp,
4545 4573 NULL, cs->cr)) {
4546 4574 if (rfs4_check_delegated_byfp(FWRITE, fp, TRUE, TRUE, TRUE,
4547 4575 NULL)) {
4548 4576 *cs->statusp = resp->status = NFS4ERR_DELAY;
4549 4577 goto err_out;
4550 4578 }
4551 4579 }
4552 4580 fp_rele_grant_hold = 1;
4553 4581
4554 4582
4555 4583 /* Check for NBMAND lock on both source and target */
4556 4584 if (nbl_need_check(srcvp)) {
4557 4585 nbl_start_crit(srcvp, RW_READER);
4558 4586 in_crit_src = 1;
4559 4587 if (nbl_conflict(srcvp, NBL_RENAME, 0, 0, 0, NULL)) {
4560 4588 *cs->statusp = resp->status = NFS4ERR_FILE_OPEN;
4561 4589 goto err_out;
4562 4590 }
4563 4591 }
4564 4592
4565 4593 if (targvp && nbl_need_check(targvp)) {
4566 4594 nbl_start_crit(targvp, RW_READER);
4567 4595 in_crit_targ = 1;
4568 4596 if (nbl_conflict(targvp, NBL_REMOVE, 0, 0, 0, NULL)) {
4569 4597 *cs->statusp = resp->status = NFS4ERR_FILE_OPEN;
4570 4598 goto err_out;
4571 4599 }
4572 4600 }
4573 4601
4574 4602 /* Get source "before" change value */
4575 4603 obdva.va_mask = AT_CTIME|AT_SEQ;
4576 4604 error = VOP_GETATTR(odvp, &obdva, 0, cs->cr, NULL);
4577 4605 if (!error) {
4578 4606 nbdva.va_mask = AT_CTIME|AT_SEQ;
4579 4607 error = VOP_GETATTR(ndvp, &nbdva, 0, cs->cr, NULL);
4580 4608 }
4581 4609 if (error) {
4582 4610 *cs->statusp = resp->status = puterrno4(error);
4583 4611 goto err_out;
4584 4612 }
4585 4613
4586 4614 NFS4_SET_FATTR4_CHANGE(resp->source_cinfo.before, obdva.va_ctime)
4587 4615 NFS4_SET_FATTR4_CHANGE(resp->target_cinfo.before, nbdva.va_ctime)
4588 4616
4589 4617 if ((error = VOP_RENAME(odvp, converted_onm, ndvp, converted_nnm,
4590 4618 cs->cr, NULL, 0)) == 0 && fp != NULL) {
4591 4619 struct vattr va;
4592 4620 vnode_t *tvp;
4593 4621
4594 4622 rfs4_dbe_lock(fp->rf_dbe);
4595 4623 tvp = fp->rf_vp;
4596 4624 if (tvp)
4597 4625 VN_HOLD(tvp);
4598 4626 rfs4_dbe_unlock(fp->rf_dbe);
4599 4627
4600 4628 if (tvp) {
4601 4629 va.va_mask = AT_NLINK;
4602 4630 if (!VOP_GETATTR(tvp, &va, 0, cs->cr, NULL) &&
4603 4631 va.va_nlink == 0) {
4604 4632 /* The file is gone and so should the state */
4605 4633 if (in_crit_targ) {
4606 4634 nbl_end_crit(targvp);
4607 4635 in_crit_targ = 0;
4608 4636 }
4609 4637 rfs4_close_all_state(fp);
4610 4638 }
4611 4639 VN_RELE(tvp);
4612 4640 }
4613 4641 }
4614 4642 if (error == 0)
4615 4643 vn_renamepath(ndvp, srcvp, nnm, nlen - 1);
4616 4644
4617 4645 if (in_crit_src)
4618 4646 nbl_end_crit(srcvp);
4619 4647 if (srcvp)
4620 4648 VN_RELE(srcvp);
4621 4649 if (in_crit_targ)
4622 4650 nbl_end_crit(targvp);
4623 4651 if (targvp)
4624 4652 VN_RELE(targvp);
4625 4653
4626 4654 if (sfp) {
4627 4655 rfs4_clear_dont_grant(sfp);
4628 4656 rfs4_file_rele(sfp);
4629 4657 }
4630 4658 if (fp) {
4631 4659 rfs4_clear_dont_grant(fp);
4632 4660 rfs4_file_rele(fp);
4633 4661 }
4634 4662
4635 4663 if (converted_onm != onm)
4636 4664 kmem_free(converted_onm, MAXPATHLEN + 1);
4637 4665 kmem_free(onm, olen);
4638 4666 if (converted_nnm != nnm)
4639 4667 kmem_free(converted_nnm, MAXPATHLEN + 1);
4640 4668 kmem_free(nnm, nlen);
4641 4669
4642 4670 /*
4643 4671 * Get the initial "after" sequence number, if it fails, set to zero
4644 4672 */
4645 4673 oidva.va_mask = AT_SEQ;
4646 4674 if (VOP_GETATTR(odvp, &oidva, 0, cs->cr, NULL))
4647 4675 oidva.va_seq = 0;
4648 4676
4649 4677 nidva.va_mask = AT_SEQ;
4650 4678 if (VOP_GETATTR(ndvp, &nidva, 0, cs->cr, NULL))
4651 4679 nidva.va_seq = 0;
4652 4680
4653 4681 /*
4654 4682 * Force modified data and metadata out to stable storage.
4655 4683 */
4656 4684 (void) VOP_FSYNC(odvp, 0, cs->cr, NULL);
4657 4685 (void) VOP_FSYNC(ndvp, 0, cs->cr, NULL);
4658 4686
4659 4687 if (error) {
4660 4688 *cs->statusp = resp->status = puterrno4(error);
4661 4689 goto out;
4662 4690 }
4663 4691
4664 4692 /*
4665 4693 * Get "after" change values, if it fails, simply return the
4666 4694 * before value.
4667 4695 */
4668 4696 oadva.va_mask = AT_CTIME|AT_SEQ;
4669 4697 if (VOP_GETATTR(odvp, &oadva, 0, cs->cr, NULL)) {
4670 4698 oadva.va_ctime = obdva.va_ctime;
4671 4699 oadva.va_seq = 0;
4672 4700 }
4673 4701
4674 4702 nadva.va_mask = AT_CTIME|AT_SEQ;
4675 4703 if (VOP_GETATTR(odvp, &nadva, 0, cs->cr, NULL)) {
4676 4704 nadva.va_ctime = nbdva.va_ctime;
4677 4705 nadva.va_seq = 0;
4678 4706 }
4679 4707
4680 4708 NFS4_SET_FATTR4_CHANGE(resp->source_cinfo.after, oadva.va_ctime)
4681 4709 NFS4_SET_FATTR4_CHANGE(resp->target_cinfo.after, nadva.va_ctime)
4682 4710
4683 4711 /*
4684 4712 * The cinfo.atomic = TRUE only if we have
4685 4713 * non-zero va_seq's, and it has incremented by exactly one
4686 4714 * during the VOP_RENAME and it didn't change during the VOP_FSYNC.
4687 4715 */
4688 4716 if (obdva.va_seq && oidva.va_seq && oadva.va_seq &&
4689 4717 oidva.va_seq == (obdva.va_seq + 1) && oidva.va_seq == oadva.va_seq)
4690 4718 resp->source_cinfo.atomic = TRUE;
4691 4719 else
4692 4720 resp->source_cinfo.atomic = FALSE;
4693 4721
4694 4722 if (nbdva.va_seq && nidva.va_seq && nadva.va_seq &&
4695 4723 nidva.va_seq == (nbdva.va_seq + 1) && nidva.va_seq == nadva.va_seq)
4696 4724 resp->target_cinfo.atomic = TRUE;
4697 4725 else
4698 4726 resp->target_cinfo.atomic = FALSE;
4699 4727
4700 4728 #ifdef VOLATILE_FH_TEST
4701 4729 {
4702 4730 extern void add_volrnm_fh(struct exportinfo *, vnode_t *);
4703 4731
4704 4732 /*
4705 4733 * Add the renamed file handle to the volatile rename list
4706 4734 */
4707 4735 if (cs->exi->exi_export.ex_flags & EX_VOLRNM) {
4708 4736 /* file handles may expire on rename */
4709 4737 vnode_t *vp;
4710 4738
4711 4739 nnm = utf8_to_fn(&args->newname, &nlen, NULL);
4712 4740 /*
4713 4741 * Already know that nnm will be a valid string
4714 4742 */
4715 4743 error = VOP_LOOKUP(ndvp, nnm, &vp, NULL, 0, NULL, cs->cr,
4716 4744 NULL, NULL, NULL);
4717 4745 kmem_free(nnm, nlen);
4718 4746 if (!error) {
4719 4747 add_volrnm_fh(cs->exi, vp);
4720 4748 VN_RELE(vp);
4721 4749 }
4722 4750 }
4723 4751 }
4724 4752 #endif /* VOLATILE_FH_TEST */
4725 4753
4726 4754 *cs->statusp = resp->status = NFS4_OK;
4727 4755 out:
4728 4756 DTRACE_NFSV4_2(op__rename__done, struct compound_state *, cs,
4729 4757 RENAME4res *, resp);
4730 4758 return;
4731 4759
4732 4760 err_out:
4733 4761 if (onm != converted_onm)
4734 4762 kmem_free(converted_onm, MAXPATHLEN + 1);
4735 4763 if (onm != NULL)
4736 4764 kmem_free(onm, olen);
4737 4765 if (nnm != converted_nnm)
4738 4766 kmem_free(converted_nnm, MAXPATHLEN + 1);
4739 4767 if (nnm != NULL)
4740 4768 kmem_free(nnm, nlen);
4741 4769
4742 4770 if (in_crit_src) nbl_end_crit(srcvp);
4743 4771 if (in_crit_targ) nbl_end_crit(targvp);
4744 4772 if (targvp) VN_RELE(targvp);
4745 4773 if (srcvp) VN_RELE(srcvp);
4746 4774 if (sfp) {
4747 4775 if (sfp_rele_grant_hold) rfs4_clear_dont_grant(sfp);
4748 4776 rfs4_file_rele(sfp);
4749 4777 }
4750 4778 if (fp) {
4751 4779 if (fp_rele_grant_hold) rfs4_clear_dont_grant(fp);
4752 4780 rfs4_file_rele(fp);
4753 4781 }
4754 4782
4755 4783 DTRACE_NFSV4_2(op__rename__done, struct compound_state *, cs,
4756 4784 RENAME4res *, resp);
4757 4785 }
4758 4786
4759 4787 /* ARGSUSED */
4760 4788 static void
4761 4789 rfs4_op_renew(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
4762 4790 struct compound_state *cs)
4763 4791 {
4764 4792 RENEW4args *args = &argop->nfs_argop4_u.oprenew;
4765 4793 RENEW4res *resp = &resop->nfs_resop4_u.oprenew;
4766 4794 rfs4_client_t *cp;
4767 4795
4768 4796 DTRACE_NFSV4_2(op__renew__start, struct compound_state *, cs,
4769 4797 RENEW4args *, args);
4770 4798
4771 4799 if ((cp = rfs4_findclient_by_id(args->clientid, FALSE)) == NULL) {
4772 4800 *cs->statusp = resp->status =
4773 4801 rfs4_check_clientid(&args->clientid, 0);
4774 4802 goto out;
4775 4803 }
4776 4804
4777 4805 if (rfs4_lease_expired(cp)) {
4778 4806 rfs4_client_rele(cp);
4779 4807 *cs->statusp = resp->status = NFS4ERR_EXPIRED;
4780 4808 goto out;
4781 4809 }
4782 4810
4783 4811 rfs4_update_lease(cp);
4784 4812
4785 4813 mutex_enter(cp->rc_cbinfo.cb_lock);
4786 4814 if (cp->rc_cbinfo.cb_notified_of_cb_path_down == FALSE) {
4787 4815 cp->rc_cbinfo.cb_notified_of_cb_path_down = TRUE;
4788 4816 *cs->statusp = resp->status = NFS4ERR_CB_PATH_DOWN;
4789 4817 } else {
4790 4818 *cs->statusp = resp->status = NFS4_OK;
4791 4819 }
4792 4820 mutex_exit(cp->rc_cbinfo.cb_lock);
4793 4821
4794 4822 rfs4_client_rele(cp);
4795 4823
4796 4824 out:
4797 4825 DTRACE_NFSV4_2(op__renew__done, struct compound_state *, cs,
4798 4826 RENEW4res *, resp);
4799 4827 }
4800 4828
4801 4829 /* ARGSUSED */
4802 4830 static void
4803 4831 rfs4_op_restorefh(nfs_argop4 *args, nfs_resop4 *resop, struct svc_req *req,
4804 4832 struct compound_state *cs)
4805 4833 {
4806 4834 RESTOREFH4res *resp = &resop->nfs_resop4_u.oprestorefh;
4807 4835
4808 4836 DTRACE_NFSV4_1(op__restorefh__start, struct compound_state *, cs);
4809 4837
↓ open down ↓ |
1157 lines elided |
↑ open up ↑ |
4810 4838 /* No need to check cs->access - we are not accessing any object */
4811 4839 if ((cs->saved_vp == NULL) || (cs->saved_fh.nfs_fh4_val == NULL)) {
4812 4840 *cs->statusp = resp->status = NFS4ERR_RESTOREFH;
4813 4841 goto out;
4814 4842 }
4815 4843 if (cs->vp != NULL) {
4816 4844 VN_RELE(cs->vp);
4817 4845 }
4818 4846 cs->vp = cs->saved_vp;
4819 4847 cs->saved_vp = NULL;
4848 + if (cs->exi)
4849 + exi_rele(cs->exi);
4820 4850 cs->exi = cs->saved_exi;
4851 + if (cs->exi)
4852 + exi_hold(cs->exi);
4821 4853 nfs_fh4_copy(&cs->saved_fh, &cs->fh);
4822 4854 *cs->statusp = resp->status = NFS4_OK;
4823 4855 cs->deleg = FALSE;
4824 4856
4825 4857 out:
4826 4858 DTRACE_NFSV4_2(op__restorefh__done, struct compound_state *, cs,
4827 4859 RESTOREFH4res *, resp);
4828 4860 }
4829 4861
4830 4862 /* ARGSUSED */
4831 4863 static void
4832 4864 rfs4_op_savefh(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
4833 4865 struct compound_state *cs)
4834 4866 {
4835 4867 SAVEFH4res *resp = &resop->nfs_resop4_u.opsavefh;
4836 4868
4837 4869 DTRACE_NFSV4_1(op__savefh__start, struct compound_state *, cs);
4838 4870
↓ open down ↓ |
8 lines elided |
↑ open up ↑ |
4839 4871 /* No need to check cs->access - we are not accessing any object */
4840 4872 if (cs->vp == NULL) {
4841 4873 *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
4842 4874 goto out;
4843 4875 }
4844 4876 if (cs->saved_vp != NULL) {
4845 4877 VN_RELE(cs->saved_vp);
4846 4878 }
4847 4879 cs->saved_vp = cs->vp;
4848 4880 VN_HOLD(cs->saved_vp);
4881 + if (cs->saved_exi)
4882 + exi_rele(cs->saved_exi);
4849 4883 cs->saved_exi = cs->exi;
4884 + if (cs->saved_exi)
4885 + exi_hold(cs->saved_exi);
4850 4886 /*
4851 4887 * since SAVEFH is fairly rare, don't alloc space for its fh
4852 4888 * unless necessary.
4853 4889 */
4854 4890 if (cs->saved_fh.nfs_fh4_val == NULL) {
4855 4891 cs->saved_fh.nfs_fh4_val = kmem_alloc(NFS4_FHSIZE, KM_SLEEP);
4856 4892 }
4857 4893 nfs_fh4_copy(&cs->fh, &cs->saved_fh);
4858 4894 *cs->statusp = resp->status = NFS4_OK;
4859 4895
4860 4896 out:
4861 4897 DTRACE_NFSV4_2(op__savefh__done, struct compound_state *, cs,
4862 4898 SAVEFH4res *, resp);
4863 4899 }
4864 4900
4865 4901 /*
4866 4902 * rfs4_verify_attr is called when nfsv4 Setattr failed, but we wish to
4867 4903 * return the bitmap of attrs that were set successfully. It is also
4868 4904 * called by Verify/Nverify to test the vattr/vfsstat attrs. It should
4869 4905 * always be called only after rfs4_do_set_attrs().
4870 4906 *
4871 4907 * Verify that the attributes are same as the expected ones. sargp->vap
4872 4908 * and sargp->sbp contain the input attributes as translated from fattr4.
4873 4909 *
4874 4910 * This function verifies only the attrs that correspond to a vattr or
4875 4911 * vfsstat struct. That is because of the extra step needed to get the
4876 4912 * corresponding system structs. Other attributes have already been set or
4877 4913 * verified by do_rfs4_set_attrs.
4878 4914 *
4879 4915 * Return 0 if all attrs match, -1 if some don't, error if error processing.
4880 4916 */
4881 4917 static int
4882 4918 rfs4_verify_attr(struct nfs4_svgetit_arg *sargp,
4883 4919 bitmap4 *resp, struct nfs4_ntov_table *ntovp)
4884 4920 {
4885 4921 int error, ret_error = 0;
4886 4922 int i, k;
4887 4923 uint_t sva_mask = sargp->vap->va_mask;
4888 4924 uint_t vbit;
4889 4925 union nfs4_attr_u *na;
4890 4926 uint8_t *amap;
4891 4927 bool_t getsb = ntovp->vfsstat;
4892 4928
4893 4929 if (sva_mask != 0) {
4894 4930 /*
4895 4931 * Okay to overwrite sargp->vap because we verify based
4896 4932 * on the incoming values.
4897 4933 */
4898 4934 ret_error = VOP_GETATTR(sargp->cs->vp, sargp->vap, 0,
4899 4935 sargp->cs->cr, NULL);
4900 4936 if (ret_error) {
4901 4937 if (resp == NULL)
4902 4938 return (ret_error);
4903 4939 /*
4904 4940 * Must return bitmap of successful attrs
4905 4941 */
4906 4942 sva_mask = 0; /* to prevent checking vap later */
4907 4943 } else {
4908 4944 /*
4909 4945 * Some file systems clobber va_mask. it is probably
4910 4946 * wrong of them to do so, nonethless we practice
4911 4947 * defensive coding.
4912 4948 * See bug id 4276830.
4913 4949 */
4914 4950 sargp->vap->va_mask = sva_mask;
4915 4951 }
4916 4952 }
4917 4953
4918 4954 if (getsb) {
4919 4955 /*
4920 4956 * Now get the superblock and loop on the bitmap, as there is
4921 4957 * no simple way of translating from superblock to bitmap4.
4922 4958 */
4923 4959 ret_error = VFS_STATVFS(sargp->cs->vp->v_vfsp, sargp->sbp);
4924 4960 if (ret_error) {
4925 4961 if (resp == NULL)
4926 4962 goto errout;
4927 4963 getsb = FALSE;
4928 4964 }
4929 4965 }
4930 4966
4931 4967 /*
4932 4968 * Now loop and verify each attribute which getattr returned
4933 4969 * whether it's the same as the input.
4934 4970 */
4935 4971 if (resp == NULL && !getsb && (sva_mask == 0))
4936 4972 goto errout;
4937 4973
4938 4974 na = ntovp->na;
4939 4975 amap = ntovp->amap;
4940 4976 k = 0;
4941 4977 for (i = 0; i < ntovp->attrcnt; i++, na++, amap++) {
4942 4978 k = *amap;
4943 4979 ASSERT(nfs4_ntov_map[k].nval == k);
4944 4980 vbit = nfs4_ntov_map[k].vbit;
4945 4981
4946 4982 /*
4947 4983 * If vattr attribute but VOP_GETATTR failed, or it's
4948 4984 * superblock attribute but VFS_STATVFS failed, skip
4949 4985 */
4950 4986 if (vbit) {
4951 4987 if ((vbit & sva_mask) == 0)
4952 4988 continue;
4953 4989 } else if (!(getsb && nfs4_ntov_map[k].vfsstat)) {
4954 4990 continue;
4955 4991 }
4956 4992 error = (*nfs4_ntov_map[k].sv_getit)(NFS4ATTR_VERIT, sargp, na);
4957 4993 if (resp != NULL) {
4958 4994 if (error)
4959 4995 ret_error = -1; /* not all match */
4960 4996 else /* update response bitmap */
4961 4997 *resp |= nfs4_ntov_map[k].fbit;
4962 4998 continue;
4963 4999 }
4964 5000 if (error) {
4965 5001 ret_error = -1; /* not all match */
4966 5002 break;
4967 5003 }
4968 5004 }
4969 5005 errout:
4970 5006 return (ret_error);
4971 5007 }
4972 5008
4973 5009 /*
4974 5010 * Decode the attribute to be set/verified. If the attr requires a sys op
4975 5011 * (VOP_GETATTR, VFS_VFSSTAT), and the request is to verify, then don't
4976 5012 * call the sv_getit function for it, because the sys op hasn't yet been done.
4977 5013 * Return 0 for success, error code if failed.
4978 5014 *
4979 5015 * Note: the decoded arg is not freed here but in nfs4_ntov_table_free.
4980 5016 */
4981 5017 static int
4982 5018 decode_fattr4_attr(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sargp,
4983 5019 int k, XDR *xdrp, bitmap4 *resp_bval, union nfs4_attr_u *nap)
4984 5020 {
4985 5021 int error = 0;
4986 5022 bool_t set_later;
4987 5023
4988 5024 sargp->vap->va_mask |= nfs4_ntov_map[k].vbit;
4989 5025
4990 5026 if ((*nfs4_ntov_map[k].xfunc)(xdrp, nap)) {
4991 5027 set_later = nfs4_ntov_map[k].vbit || nfs4_ntov_map[k].vfsstat;
4992 5028 /*
4993 5029 * don't verify yet if a vattr or sb dependent attr,
4994 5030 * because we don't have their sys values yet.
4995 5031 * Will be done later.
4996 5032 */
4997 5033 if (! (set_later && (cmd == NFS4ATTR_VERIT))) {
4998 5034 /*
4999 5035 * ACLs are a special case, since setting the MODE
5000 5036 * conflicts with setting the ACL. We delay setting
5001 5037 * the ACL until all other attributes have been set.
5002 5038 * The ACL gets set in do_rfs4_op_setattr().
5003 5039 */
5004 5040 if (nfs4_ntov_map[k].fbit != FATTR4_ACL_MASK) {
5005 5041 error = (*nfs4_ntov_map[k].sv_getit)(cmd,
5006 5042 sargp, nap);
5007 5043 if (error) {
5008 5044 xdr_free(nfs4_ntov_map[k].xfunc,
5009 5045 (caddr_t)nap);
5010 5046 }
5011 5047 }
5012 5048 }
5013 5049 } else {
5014 5050 #ifdef DEBUG
5015 5051 cmn_err(CE_NOTE, "decode_fattr4_attr: error "
5016 5052 "decoding attribute %d\n", k);
5017 5053 #endif
5018 5054 error = EINVAL;
5019 5055 }
5020 5056 if (!error && resp_bval && !set_later) {
5021 5057 *resp_bval |= nfs4_ntov_map[k].fbit;
5022 5058 }
5023 5059
5024 5060 return (error);
5025 5061 }
5026 5062
5027 5063 /*
5028 5064 * Set vattr based on incoming fattr4 attrs - used by setattr.
5029 5065 * Set response mask. Ignore any values that are not writable vattr attrs.
5030 5066 */
5031 5067 static nfsstat4
5032 5068 do_rfs4_set_attrs(bitmap4 *resp, fattr4 *fattrp, struct compound_state *cs,
5033 5069 struct nfs4_svgetit_arg *sargp, struct nfs4_ntov_table *ntovp,
5034 5070 nfs4_attr_cmd_t cmd)
5035 5071 {
5036 5072 int error = 0;
5037 5073 int i;
5038 5074 char *attrs = fattrp->attrlist4;
5039 5075 uint32_t attrslen = fattrp->attrlist4_len;
5040 5076 XDR xdr;
5041 5077 nfsstat4 status = NFS4_OK;
5042 5078 vnode_t *vp = cs->vp;
5043 5079 union nfs4_attr_u *na;
5044 5080 uint8_t *amap;
5045 5081
5046 5082 #ifndef lint
5047 5083 /*
5048 5084 * Make sure that maximum attribute number can be expressed as an
5049 5085 * 8 bit quantity.
5050 5086 */
5051 5087 ASSERT(NFS4_MAXNUM_ATTRS <= (UINT8_MAX + 1));
5052 5088 #endif
5053 5089
5054 5090 if (vp == NULL) {
5055 5091 if (resp)
5056 5092 *resp = 0;
5057 5093 return (NFS4ERR_NOFILEHANDLE);
5058 5094 }
5059 5095 if (cs->access == CS_ACCESS_DENIED) {
5060 5096 if (resp)
5061 5097 *resp = 0;
5062 5098 return (NFS4ERR_ACCESS);
5063 5099 }
5064 5100
5065 5101 sargp->op = cmd;
5066 5102 sargp->cs = cs;
5067 5103 sargp->flag = 0; /* may be set later */
5068 5104 sargp->vap->va_mask = 0;
5069 5105 sargp->rdattr_error = NFS4_OK;
5070 5106 sargp->rdattr_error_req = FALSE;
5071 5107 /* sargp->sbp is set by the caller */
5072 5108
5073 5109 xdrmem_create(&xdr, attrs, attrslen, XDR_DECODE);
5074 5110
5075 5111 na = ntovp->na;
5076 5112 amap = ntovp->amap;
5077 5113
5078 5114 /*
5079 5115 * The following loop iterates on the nfs4_ntov_map checking
5080 5116 * if the fbit is set in the requested bitmap.
5081 5117 * If set then we process the arguments using the
5082 5118 * rfs4_fattr4 conversion functions to populate the setattr
5083 5119 * vattr and va_mask. Any settable attrs that are not using vattr
5084 5120 * will be set in this loop.
5085 5121 */
5086 5122 for (i = 0; i < nfs4_ntov_map_size; i++) {
5087 5123 if (!(fattrp->attrmask & nfs4_ntov_map[i].fbit)) {
5088 5124 continue;
5089 5125 }
5090 5126 /*
5091 5127 * If setattr, must be a writable attr.
5092 5128 * If verify/nverify, must be a readable attr.
5093 5129 */
5094 5130 if ((error = (*nfs4_ntov_map[i].sv_getit)(
5095 5131 NFS4ATTR_SUPPORTED, sargp, NULL)) != 0) {
5096 5132 /*
5097 5133 * Client tries to set/verify an
5098 5134 * unsupported attribute, tries to set
5099 5135 * a read only attr or verify a write
5100 5136 * only one - error!
5101 5137 */
5102 5138 break;
5103 5139 }
5104 5140 /*
5105 5141 * Decode the attribute to set/verify
5106 5142 */
5107 5143 error = decode_fattr4_attr(cmd, sargp, nfs4_ntov_map[i].nval,
5108 5144 &xdr, resp ? resp : NULL, na);
5109 5145 if (error)
5110 5146 break;
5111 5147 *amap++ = (uint8_t)nfs4_ntov_map[i].nval;
5112 5148 na++;
5113 5149 (ntovp->attrcnt)++;
5114 5150 if (nfs4_ntov_map[i].vfsstat)
5115 5151 ntovp->vfsstat = TRUE;
5116 5152 }
5117 5153
5118 5154 if (error != 0)
5119 5155 status = (error == ENOTSUP ? NFS4ERR_ATTRNOTSUPP :
5120 5156 puterrno4(error));
5121 5157 /* xdrmem_destroy(&xdrs); */ /* NO-OP */
5122 5158 return (status);
5123 5159 }
5124 5160
5125 5161 static nfsstat4
5126 5162 do_rfs4_op_setattr(bitmap4 *resp, fattr4 *fattrp, struct compound_state *cs,
5127 5163 stateid4 *stateid)
5128 5164 {
5129 5165 int error = 0;
5130 5166 struct nfs4_svgetit_arg sarg;
5131 5167 bool_t trunc;
5132 5168
5133 5169 nfsstat4 status = NFS4_OK;
5134 5170 cred_t *cr = cs->cr;
5135 5171 vnode_t *vp = cs->vp;
5136 5172 struct nfs4_ntov_table ntov;
5137 5173 struct statvfs64 sb;
5138 5174 struct vattr bva;
5139 5175 struct flock64 bf;
5140 5176 int in_crit = 0;
5141 5177 uint_t saved_mask = 0;
5142 5178 caller_context_t ct;
5143 5179
5144 5180 *resp = 0;
5145 5181 sarg.sbp = &sb;
5146 5182 sarg.is_referral = B_FALSE;
5147 5183 nfs4_ntov_table_init(&ntov);
5148 5184 status = do_rfs4_set_attrs(resp, fattrp, cs, &sarg, &ntov,
5149 5185 NFS4ATTR_SETIT);
5150 5186 if (status != NFS4_OK) {
5151 5187 /*
5152 5188 * failed set attrs
5153 5189 */
5154 5190 goto done;
5155 5191 }
5156 5192 if ((sarg.vap->va_mask == 0) &&
5157 5193 (! (fattrp->attrmask & FATTR4_ACL_MASK))) {
5158 5194 /*
5159 5195 * no further work to be done
5160 5196 */
5161 5197 goto done;
5162 5198 }
5163 5199
5164 5200 /*
5165 5201 * If we got a request to set the ACL and the MODE, only
5166 5202 * allow changing VSUID, VSGID, and VSVTX. Attempting
5167 5203 * to change any other bits, along with setting an ACL,
5168 5204 * gives NFS4ERR_INVAL.
5169 5205 */
5170 5206 if ((fattrp->attrmask & FATTR4_ACL_MASK) &&
5171 5207 (fattrp->attrmask & FATTR4_MODE_MASK)) {
5172 5208 vattr_t va;
5173 5209
5174 5210 va.va_mask = AT_MODE;
5175 5211 error = VOP_GETATTR(vp, &va, 0, cs->cr, NULL);
5176 5212 if (error) {
5177 5213 status = puterrno4(error);
5178 5214 goto done;
5179 5215 }
5180 5216 if ((sarg.vap->va_mode ^ va.va_mode) &
5181 5217 ~(VSUID | VSGID | VSVTX)) {
5182 5218 status = NFS4ERR_INVAL;
5183 5219 goto done;
5184 5220 }
5185 5221 }
5186 5222
5187 5223 /* Check stateid only if size has been set */
5188 5224 if (sarg.vap->va_mask & AT_SIZE) {
5189 5225 trunc = (sarg.vap->va_size == 0);
5190 5226 status = rfs4_check_stateid(FWRITE, cs->vp, stateid,
5191 5227 trunc, &cs->deleg, sarg.vap->va_mask & AT_SIZE, &ct);
5192 5228 if (status != NFS4_OK)
5193 5229 goto done;
5194 5230 } else {
5195 5231 ct.cc_sysid = 0;
5196 5232 ct.cc_pid = 0;
5197 5233 ct.cc_caller_id = nfs4_srv_caller_id;
5198 5234 ct.cc_flags = CC_DONTBLOCK;
5199 5235 }
5200 5236
5201 5237 /* XXX start of possible race with delegations */
5202 5238
5203 5239 /*
5204 5240 * We need to specially handle size changes because it is
5205 5241 * possible for the client to create a file with read-only
5206 5242 * modes, but with the file opened for writing. If the client
5207 5243 * then tries to set the file size, e.g. ftruncate(3C),
5208 5244 * fcntl(F_FREESP), the normal access checking done in
5209 5245 * VOP_SETATTR would prevent the client from doing it even though
5210 5246 * it should be allowed to do so. To get around this, we do the
5211 5247 * access checking for ourselves and use VOP_SPACE which doesn't
5212 5248 * do the access checking.
5213 5249 * Also the client should not be allowed to change the file
5214 5250 * size if there is a conflicting non-blocking mandatory lock in
5215 5251 * the region of the change.
5216 5252 */
5217 5253 if (vp->v_type == VREG && (sarg.vap->va_mask & AT_SIZE)) {
5218 5254 u_offset_t offset;
5219 5255 ssize_t length;
5220 5256
5221 5257 /*
5222 5258 * ufs_setattr clears AT_SIZE from vap->va_mask, but
5223 5259 * before returning, sarg.vap->va_mask is used to
5224 5260 * generate the setattr reply bitmap. We also clear
5225 5261 * AT_SIZE below before calling VOP_SPACE. For both
5226 5262 * of these cases, the va_mask needs to be saved here
5227 5263 * and restored after calling VOP_SETATTR.
5228 5264 */
5229 5265 saved_mask = sarg.vap->va_mask;
5230 5266
5231 5267 /*
5232 5268 * Check any possible conflict due to NBMAND locks.
5233 5269 * Get into critical region before VOP_GETATTR, so the
5234 5270 * size attribute is valid when checking conflicts.
5235 5271 */
5236 5272 if (nbl_need_check(vp)) {
5237 5273 nbl_start_crit(vp, RW_READER);
5238 5274 in_crit = 1;
5239 5275 }
5240 5276
5241 5277 bva.va_mask = AT_UID|AT_SIZE;
5242 5278 if (error = VOP_GETATTR(vp, &bva, 0, cr, &ct)) {
5243 5279 status = puterrno4(error);
5244 5280 goto done;
5245 5281 }
5246 5282
5247 5283 if (in_crit) {
5248 5284 if (sarg.vap->va_size < bva.va_size) {
5249 5285 offset = sarg.vap->va_size;
5250 5286 length = bva.va_size - sarg.vap->va_size;
5251 5287 } else {
5252 5288 offset = bva.va_size;
5253 5289 length = sarg.vap->va_size - bva.va_size;
5254 5290 }
5255 5291 if (nbl_conflict(vp, NBL_WRITE, offset, length, 0,
5256 5292 &ct)) {
5257 5293 status = NFS4ERR_LOCKED;
5258 5294 goto done;
5259 5295 }
5260 5296 }
5261 5297
5262 5298 if (crgetuid(cr) == bva.va_uid) {
5263 5299 sarg.vap->va_mask &= ~AT_SIZE;
5264 5300 bf.l_type = F_WRLCK;
5265 5301 bf.l_whence = 0;
5266 5302 bf.l_start = (off64_t)sarg.vap->va_size;
5267 5303 bf.l_len = 0;
5268 5304 bf.l_sysid = 0;
5269 5305 bf.l_pid = 0;
5270 5306 error = VOP_SPACE(vp, F_FREESP, &bf, FWRITE,
5271 5307 (offset_t)sarg.vap->va_size, cr, &ct);
5272 5308 }
5273 5309 }
5274 5310
5275 5311 if (!error && sarg.vap->va_mask != 0)
5276 5312 error = VOP_SETATTR(vp, sarg.vap, sarg.flag, cr, &ct);
5277 5313
5278 5314 /* restore va_mask -- ufs_setattr clears AT_SIZE */
5279 5315 if (saved_mask & AT_SIZE)
5280 5316 sarg.vap->va_mask |= AT_SIZE;
5281 5317
5282 5318 /*
5283 5319 * If an ACL was being set, it has been delayed until now,
5284 5320 * in order to set the mode (via the VOP_SETATTR() above) first.
5285 5321 */
5286 5322 if ((! error) && (fattrp->attrmask & FATTR4_ACL_MASK)) {
5287 5323 int i;
5288 5324
5289 5325 for (i = 0; i < NFS4_MAXNUM_ATTRS; i++)
5290 5326 if (ntov.amap[i] == FATTR4_ACL)
5291 5327 break;
5292 5328 if (i < NFS4_MAXNUM_ATTRS) {
5293 5329 error = (*nfs4_ntov_map[FATTR4_ACL].sv_getit)(
5294 5330 NFS4ATTR_SETIT, &sarg, &ntov.na[i]);
5295 5331 if (error == 0) {
5296 5332 *resp |= FATTR4_ACL_MASK;
5297 5333 } else if (error == ENOTSUP) {
5298 5334 (void) rfs4_verify_attr(&sarg, resp, &ntov);
5299 5335 status = NFS4ERR_ATTRNOTSUPP;
5300 5336 goto done;
5301 5337 }
5302 5338 } else {
5303 5339 NFS4_DEBUG(rfs4_debug,
5304 5340 (CE_NOTE, "do_rfs4_op_setattr: "
5305 5341 "unable to find ACL in fattr4"));
5306 5342 error = EINVAL;
5307 5343 }
5308 5344 }
5309 5345
5310 5346 if (error) {
5311 5347 /* check if a monitor detected a delegation conflict */
5312 5348 if (error == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK))
5313 5349 status = NFS4ERR_DELAY;
5314 5350 else
5315 5351 status = puterrno4(error);
5316 5352
5317 5353 /*
5318 5354 * Set the response bitmap when setattr failed.
5319 5355 * If VOP_SETATTR partially succeeded, test by doing a
5320 5356 * VOP_GETATTR on the object and comparing the data
5321 5357 * to the setattr arguments.
5322 5358 */
5323 5359 (void) rfs4_verify_attr(&sarg, resp, &ntov);
5324 5360 } else {
5325 5361 /*
5326 5362 * Force modified metadata out to stable storage.
5327 5363 */
5328 5364 (void) VOP_FSYNC(vp, FNODSYNC, cr, &ct);
5329 5365 /*
5330 5366 * Set response bitmap
5331 5367 */
5332 5368 nfs4_vmask_to_nmask_set(sarg.vap->va_mask, resp);
5333 5369 }
5334 5370
5335 5371 /* Return early and already have a NFSv4 error */
5336 5372 done:
5337 5373 /*
5338 5374 * Except for nfs4_vmask_to_nmask_set(), vattr --> fattr
5339 5375 * conversion sets both readable and writeable NFS4 attrs
5340 5376 * for AT_MTIME and AT_ATIME. The line below masks out
5341 5377 * unrequested attrs from the setattr result bitmap. This
5342 5378 * is placed after the done: label to catch the ATTRNOTSUP
5343 5379 * case.
5344 5380 */
5345 5381 *resp &= fattrp->attrmask;
5346 5382
5347 5383 if (in_crit)
5348 5384 nbl_end_crit(vp);
5349 5385
5350 5386 nfs4_ntov_table_free(&ntov, &sarg);
5351 5387
5352 5388 return (status);
5353 5389 }
5354 5390
5355 5391 /* ARGSUSED */
5356 5392 static void
5357 5393 rfs4_op_setattr(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
5358 5394 struct compound_state *cs)
5359 5395 {
5360 5396 SETATTR4args *args = &argop->nfs_argop4_u.opsetattr;
5361 5397 SETATTR4res *resp = &resop->nfs_resop4_u.opsetattr;
5362 5398 bslabel_t *clabel;
5363 5399
5364 5400 DTRACE_NFSV4_2(op__setattr__start, struct compound_state *, cs,
5365 5401 SETATTR4args *, args);
5366 5402
5367 5403 if (cs->vp == NULL) {
5368 5404 *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
5369 5405 goto out;
5370 5406 }
5371 5407
5372 5408 /*
5373 5409 * If there is an unshared filesystem mounted on this vnode,
5374 5410 * do not allow to setattr on this vnode.
5375 5411 */
5376 5412 if (vn_ismntpt(cs->vp)) {
5377 5413 *cs->statusp = resp->status = NFS4ERR_ACCESS;
5378 5414 goto out;
5379 5415 }
5380 5416
5381 5417 resp->attrsset = 0;
5382 5418
5383 5419 if (rdonly4(req, cs)) {
5384 5420 *cs->statusp = resp->status = NFS4ERR_ROFS;
5385 5421 goto out;
5386 5422 }
5387 5423
5388 5424 /* check label before setting attributes */
5389 5425 if (is_system_labeled()) {
5390 5426 ASSERT(req->rq_label != NULL);
5391 5427 clabel = req->rq_label;
5392 5428 DTRACE_PROBE2(tx__rfs4__log__info__opsetattr__clabel, char *,
5393 5429 "got client label from request(1)",
5394 5430 struct svc_req *, req);
5395 5431 if (!blequal(&l_admin_low->tsl_label, clabel)) {
5396 5432 if (!do_rfs_label_check(clabel, cs->vp,
5397 5433 EQUALITY_CHECK, cs->exi)) {
5398 5434 *cs->statusp = resp->status = NFS4ERR_ACCESS;
5399 5435 goto out;
5400 5436 }
5401 5437 }
5402 5438 }
5403 5439
5404 5440 *cs->statusp = resp->status =
5405 5441 do_rfs4_op_setattr(&resp->attrsset, &args->obj_attributes, cs,
5406 5442 &args->stateid);
5407 5443
5408 5444 out:
5409 5445 DTRACE_NFSV4_2(op__setattr__done, struct compound_state *, cs,
5410 5446 SETATTR4res *, resp);
5411 5447 }
5412 5448
5413 5449 /* ARGSUSED */
5414 5450 static void
5415 5451 rfs4_op_verify(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
5416 5452 struct compound_state *cs)
5417 5453 {
5418 5454 /*
5419 5455 * verify and nverify are exactly the same, except that nverify
5420 5456 * succeeds when some argument changed, and verify succeeds when
5421 5457 * when none changed.
5422 5458 */
5423 5459
5424 5460 VERIFY4args *args = &argop->nfs_argop4_u.opverify;
5425 5461 VERIFY4res *resp = &resop->nfs_resop4_u.opverify;
5426 5462
5427 5463 int error;
5428 5464 struct nfs4_svgetit_arg sarg;
5429 5465 struct statvfs64 sb;
5430 5466 struct nfs4_ntov_table ntov;
5431 5467
5432 5468 DTRACE_NFSV4_2(op__verify__start, struct compound_state *, cs,
5433 5469 VERIFY4args *, args);
5434 5470
5435 5471 if (cs->vp == NULL) {
5436 5472 *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
5437 5473 goto out;
5438 5474 }
5439 5475
5440 5476 sarg.sbp = &sb;
5441 5477 sarg.is_referral = B_FALSE;
5442 5478 nfs4_ntov_table_init(&ntov);
5443 5479 resp->status = do_rfs4_set_attrs(NULL, &args->obj_attributes, cs,
5444 5480 &sarg, &ntov, NFS4ATTR_VERIT);
5445 5481 if (resp->status != NFS4_OK) {
5446 5482 /*
5447 5483 * do_rfs4_set_attrs will try to verify systemwide attrs,
5448 5484 * so could return -1 for "no match".
5449 5485 */
5450 5486 if (resp->status == -1)
5451 5487 resp->status = NFS4ERR_NOT_SAME;
5452 5488 goto done;
5453 5489 }
5454 5490 error = rfs4_verify_attr(&sarg, NULL, &ntov);
5455 5491 switch (error) {
5456 5492 case 0:
5457 5493 resp->status = NFS4_OK;
5458 5494 break;
5459 5495 case -1:
5460 5496 resp->status = NFS4ERR_NOT_SAME;
5461 5497 break;
5462 5498 default:
5463 5499 resp->status = puterrno4(error);
5464 5500 break;
5465 5501 }
5466 5502 done:
5467 5503 *cs->statusp = resp->status;
5468 5504 nfs4_ntov_table_free(&ntov, &sarg);
5469 5505 out:
5470 5506 DTRACE_NFSV4_2(op__verify__done, struct compound_state *, cs,
5471 5507 VERIFY4res *, resp);
5472 5508 }
5473 5509
5474 5510 /* ARGSUSED */
5475 5511 static void
5476 5512 rfs4_op_nverify(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
5477 5513 struct compound_state *cs)
5478 5514 {
5479 5515 /*
5480 5516 * verify and nverify are exactly the same, except that nverify
5481 5517 * succeeds when some argument changed, and verify succeeds when
5482 5518 * when none changed.
5483 5519 */
5484 5520
5485 5521 NVERIFY4args *args = &argop->nfs_argop4_u.opnverify;
5486 5522 NVERIFY4res *resp = &resop->nfs_resop4_u.opnverify;
5487 5523
5488 5524 int error;
5489 5525 struct nfs4_svgetit_arg sarg;
5490 5526 struct statvfs64 sb;
5491 5527 struct nfs4_ntov_table ntov;
5492 5528
5493 5529 DTRACE_NFSV4_2(op__nverify__start, struct compound_state *, cs,
5494 5530 NVERIFY4args *, args);
5495 5531
5496 5532 if (cs->vp == NULL) {
5497 5533 *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
5498 5534 DTRACE_NFSV4_2(op__nverify__done, struct compound_state *, cs,
5499 5535 NVERIFY4res *, resp);
5500 5536 return;
5501 5537 }
5502 5538 sarg.sbp = &sb;
5503 5539 sarg.is_referral = B_FALSE;
5504 5540 nfs4_ntov_table_init(&ntov);
5505 5541 resp->status = do_rfs4_set_attrs(NULL, &args->obj_attributes, cs,
5506 5542 &sarg, &ntov, NFS4ATTR_VERIT);
5507 5543 if (resp->status != NFS4_OK) {
5508 5544 /*
5509 5545 * do_rfs4_set_attrs will try to verify systemwide attrs,
5510 5546 * so could return -1 for "no match".
5511 5547 */
5512 5548 if (resp->status == -1)
5513 5549 resp->status = NFS4_OK;
5514 5550 goto done;
5515 5551 }
5516 5552 error = rfs4_verify_attr(&sarg, NULL, &ntov);
5517 5553 switch (error) {
5518 5554 case 0:
5519 5555 resp->status = NFS4ERR_SAME;
5520 5556 break;
5521 5557 case -1:
5522 5558 resp->status = NFS4_OK;
5523 5559 break;
5524 5560 default:
5525 5561 resp->status = puterrno4(error);
5526 5562 break;
5527 5563 }
5528 5564 done:
5529 5565 *cs->statusp = resp->status;
5530 5566 nfs4_ntov_table_free(&ntov, &sarg);
5531 5567
5532 5568 DTRACE_NFSV4_2(op__nverify__done, struct compound_state *, cs,
5533 5569 NVERIFY4res *, resp);
5534 5570 }
5535 5571
5536 5572 /*
5537 5573 * XXX - This should live in an NFS header file.
5538 5574 */
5539 5575 #define MAX_IOVECS 12
5540 5576
5541 5577 /* ARGSUSED */
5542 5578 static void
5543 5579 rfs4_op_write(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
5544 5580 struct compound_state *cs)
5545 5581 {
5546 5582 WRITE4args *args = &argop->nfs_argop4_u.opwrite;
5547 5583 WRITE4res *resp = &resop->nfs_resop4_u.opwrite;
5548 5584 int error;
5549 5585 vnode_t *vp;
5550 5586 struct vattr bva;
5551 5587 u_offset_t rlimit;
5552 5588 struct uio uio;
5553 5589 struct iovec iov[MAX_IOVECS];
5554 5590 struct iovec *iovp;
5555 5591 int iovcnt;
5556 5592 int ioflag;
5557 5593 cred_t *savecred, *cr;
5558 5594 bool_t *deleg = &cs->deleg;
5559 5595 nfsstat4 stat;
5560 5596 int in_crit = 0;
5561 5597 caller_context_t ct;
5562 5598
5563 5599 DTRACE_NFSV4_2(op__write__start, struct compound_state *, cs,
5564 5600 WRITE4args *, args);
5565 5601
5566 5602 vp = cs->vp;
5567 5603 if (vp == NULL) {
5568 5604 *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
5569 5605 goto out;
5570 5606 }
5571 5607 if (cs->access == CS_ACCESS_DENIED) {
5572 5608 *cs->statusp = resp->status = NFS4ERR_ACCESS;
5573 5609 goto out;
5574 5610 }
5575 5611
5576 5612 cr = cs->cr;
5577 5613
5578 5614 if ((stat = rfs4_check_stateid(FWRITE, vp, &args->stateid, FALSE,
5579 5615 deleg, TRUE, &ct)) != NFS4_OK) {
5580 5616 *cs->statusp = resp->status = stat;
5581 5617 goto out;
5582 5618 }
5583 5619
5584 5620 /*
5585 5621 * We have to enter the critical region before calling VOP_RWLOCK
5586 5622 * to avoid a deadlock with ufs.
5587 5623 */
5588 5624 if (nbl_need_check(vp)) {
5589 5625 nbl_start_crit(vp, RW_READER);
5590 5626 in_crit = 1;
5591 5627 if (nbl_conflict(vp, NBL_WRITE,
5592 5628 args->offset, args->data_len, 0, &ct)) {
5593 5629 *cs->statusp = resp->status = NFS4ERR_LOCKED;
5594 5630 goto out;
5595 5631 }
5596 5632 }
5597 5633
5598 5634 bva.va_mask = AT_MODE | AT_UID;
5599 5635 error = VOP_GETATTR(vp, &bva, 0, cr, &ct);
5600 5636
5601 5637 /*
5602 5638 * If we can't get the attributes, then we can't do the
5603 5639 * right access checking. So, we'll fail the request.
5604 5640 */
5605 5641 if (error) {
5606 5642 *cs->statusp = resp->status = puterrno4(error);
5607 5643 goto out;
5608 5644 }
5609 5645
5610 5646 if (rdonly4(req, cs)) {
5611 5647 *cs->statusp = resp->status = NFS4ERR_ROFS;
5612 5648 goto out;
5613 5649 }
5614 5650
5615 5651 if (vp->v_type != VREG) {
5616 5652 *cs->statusp = resp->status =
5617 5653 ((vp->v_type == VDIR) ? NFS4ERR_ISDIR : NFS4ERR_INVAL);
5618 5654 goto out;
5619 5655 }
5620 5656
5621 5657 if (crgetuid(cr) != bva.va_uid &&
5622 5658 (error = VOP_ACCESS(vp, VWRITE, 0, cr, &ct))) {
5623 5659 *cs->statusp = resp->status = puterrno4(error);
5624 5660 goto out;
5625 5661 }
5626 5662
5627 5663 if (MANDLOCK(vp, bva.va_mode)) {
5628 5664 *cs->statusp = resp->status = NFS4ERR_ACCESS;
5629 5665 goto out;
5630 5666 }
5631 5667
5632 5668 if (args->data_len == 0) {
5633 5669 *cs->statusp = resp->status = NFS4_OK;
5634 5670 resp->count = 0;
5635 5671 resp->committed = args->stable;
5636 5672 resp->writeverf = Write4verf;
5637 5673 goto out;
5638 5674 }
5639 5675
5640 5676 if (args->mblk != NULL) {
5641 5677 mblk_t *m;
5642 5678 uint_t bytes, round_len;
5643 5679
5644 5680 iovcnt = 0;
5645 5681 bytes = 0;
5646 5682 round_len = roundup(args->data_len, BYTES_PER_XDR_UNIT);
5647 5683 for (m = args->mblk;
5648 5684 m != NULL && bytes < round_len;
5649 5685 m = m->b_cont) {
5650 5686 iovcnt++;
5651 5687 bytes += MBLKL(m);
5652 5688 }
5653 5689 #ifdef DEBUG
5654 5690 /* should have ended on an mblk boundary */
5655 5691 if (bytes != round_len) {
5656 5692 printf("bytes=0x%x, round_len=0x%x, req len=0x%x\n",
5657 5693 bytes, round_len, args->data_len);
5658 5694 printf("args=%p, args->mblk=%p, m=%p", (void *)args,
5659 5695 (void *)args->mblk, (void *)m);
5660 5696 ASSERT(bytes == round_len);
5661 5697 }
5662 5698 #endif
5663 5699 if (iovcnt <= MAX_IOVECS) {
5664 5700 iovp = iov;
5665 5701 } else {
5666 5702 iovp = kmem_alloc(sizeof (*iovp) * iovcnt, KM_SLEEP);
5667 5703 }
5668 5704 mblk_to_iov(args->mblk, iovcnt, iovp);
5669 5705 } else if (args->rlist != NULL) {
5670 5706 iovcnt = 1;
5671 5707 iovp = iov;
5672 5708 iovp->iov_base = (char *)((args->rlist)->u.c_daddr3);
5673 5709 iovp->iov_len = args->data_len;
5674 5710 } else {
5675 5711 iovcnt = 1;
5676 5712 iovp = iov;
5677 5713 iovp->iov_base = args->data_val;
5678 5714 iovp->iov_len = args->data_len;
5679 5715 }
5680 5716
5681 5717 uio.uio_iov = iovp;
5682 5718 uio.uio_iovcnt = iovcnt;
5683 5719
5684 5720 uio.uio_segflg = UIO_SYSSPACE;
5685 5721 uio.uio_extflg = UIO_COPY_DEFAULT;
5686 5722 uio.uio_loffset = args->offset;
5687 5723 uio.uio_resid = args->data_len;
5688 5724 uio.uio_llimit = curproc->p_fsz_ctl;
5689 5725 rlimit = uio.uio_llimit - args->offset;
5690 5726 if (rlimit < (u_offset_t)uio.uio_resid)
5691 5727 uio.uio_resid = (int)rlimit;
5692 5728
5693 5729 if (args->stable == UNSTABLE4)
5694 5730 ioflag = 0;
5695 5731 else if (args->stable == FILE_SYNC4)
5696 5732 ioflag = FSYNC;
5697 5733 else if (args->stable == DATA_SYNC4)
5698 5734 ioflag = FDSYNC;
5699 5735 else {
5700 5736 if (iovp != iov)
5701 5737 kmem_free(iovp, sizeof (*iovp) * iovcnt);
5702 5738 *cs->statusp = resp->status = NFS4ERR_INVAL;
5703 5739 goto out;
5704 5740 }
5705 5741
5706 5742 /*
5707 5743 * We're changing creds because VM may fault and we need
5708 5744 * the cred of the current thread to be used if quota
5709 5745 * checking is enabled.
5710 5746 */
5711 5747 savecred = curthread->t_cred;
5712 5748 curthread->t_cred = cr;
5713 5749 error = do_io(FWRITE, vp, &uio, ioflag, cr, &ct);
5714 5750 curthread->t_cred = savecred;
5715 5751
5716 5752 if (iovp != iov)
5717 5753 kmem_free(iovp, sizeof (*iovp) * iovcnt);
5718 5754
5719 5755 if (error) {
5720 5756 *cs->statusp = resp->status = puterrno4(error);
5721 5757 goto out;
5722 5758 }
5723 5759
5724 5760 *cs->statusp = resp->status = NFS4_OK;
5725 5761 resp->count = args->data_len - uio.uio_resid;
5726 5762
5727 5763 if (ioflag == 0)
5728 5764 resp->committed = UNSTABLE4;
5729 5765 else
5730 5766 resp->committed = FILE_SYNC4;
5731 5767
5732 5768 resp->writeverf = Write4verf;
5733 5769
5734 5770 out:
5735 5771 if (in_crit)
5736 5772 nbl_end_crit(vp);
5737 5773
5738 5774 DTRACE_NFSV4_2(op__write__done, struct compound_state *, cs,
5739 5775 WRITE4res *, resp);
5740 5776 }
5741 5777
5742 5778
5743 5779 /* XXX put in a header file */
5744 5780 extern int sec_svc_getcred(struct svc_req *, cred_t *, caddr_t *, int *);
5745 5781
5746 5782 void
5747 5783 rfs4_compound(COMPOUND4args *args, COMPOUND4res *resp, struct exportinfo *exi,
5748 5784 struct svc_req *req, cred_t *cr, int *rv)
5749 5785 {
5750 5786 uint_t i;
5751 5787 struct compound_state cs;
5752 5788
5753 5789 if (rv != NULL)
5754 5790 *rv = 0;
5755 5791 rfs4_init_compound_state(&cs);
5756 5792 /*
5757 5793 * Form a reply tag by copying over the reqeuest tag.
5758 5794 */
5759 5795 resp->tag.utf8string_val =
5760 5796 kmem_alloc(args->tag.utf8string_len, KM_SLEEP);
5761 5797 resp->tag.utf8string_len = args->tag.utf8string_len;
5762 5798 bcopy(args->tag.utf8string_val, resp->tag.utf8string_val,
5763 5799 resp->tag.utf8string_len);
5764 5800
5765 5801 cs.statusp = &resp->status;
5766 5802 cs.req = req;
5767 5803 resp->array = NULL;
5768 5804 resp->array_len = 0;
5769 5805
5770 5806 /*
5771 5807 * XXX for now, minorversion should be zero
5772 5808 */
5773 5809 if (args->minorversion != NFS4_MINORVERSION) {
5774 5810 DTRACE_NFSV4_2(compound__start, struct compound_state *,
5775 5811 &cs, COMPOUND4args *, args);
5776 5812 resp->status = NFS4ERR_MINOR_VERS_MISMATCH;
5777 5813 DTRACE_NFSV4_2(compound__done, struct compound_state *,
5778 5814 &cs, COMPOUND4res *, resp);
5779 5815 return;
5780 5816 }
5781 5817
5782 5818 if (args->array_len == 0) {
5783 5819 resp->status = NFS4_OK;
5784 5820 return;
5785 5821 }
5786 5822
5787 5823 ASSERT(exi == NULL);
5788 5824 ASSERT(cr == NULL);
5789 5825
5790 5826 cr = crget();
5791 5827 ASSERT(cr != NULL);
5792 5828
5793 5829 if (sec_svc_getcred(req, cr, &cs.principal, &cs.nfsflavor) == 0) {
5794 5830 DTRACE_NFSV4_2(compound__start, struct compound_state *,
5795 5831 &cs, COMPOUND4args *, args);
5796 5832 crfree(cr);
5797 5833 DTRACE_NFSV4_2(compound__done, struct compound_state *,
5798 5834 &cs, COMPOUND4res *, resp);
5799 5835 svcerr_badcred(req->rq_xprt);
5800 5836 if (rv != NULL)
5801 5837 *rv = 1;
5802 5838 return;
5803 5839 }
↓ open down ↓ |
944 lines elided |
↑ open up ↑ |
5804 5840 resp->array_len = args->array_len;
5805 5841 resp->array = kmem_zalloc(args->array_len * sizeof (nfs_resop4),
5806 5842 KM_SLEEP);
5807 5843
5808 5844 cs.basecr = cr;
5809 5845
5810 5846 DTRACE_NFSV4_2(compound__start, struct compound_state *, &cs,
5811 5847 COMPOUND4args *, args);
5812 5848
5813 5849 /*
5814 - * For now, NFS4 compound processing must be protected by
5815 - * exported_lock because it can access more than one exportinfo
5816 - * per compound and share/unshare can now change multiple
5817 - * exinfo structs. The NFS2/3 code only refs 1 exportinfo
5818 - * per proc (excluding public exinfo), and exi_count design
5819 - * is sufficient to protect concurrent execution of NFS2/3
5820 - * ops along with unexport. This lock will be removed as
5821 - * part of the NFSv4 phase 2 namespace redesign work.
5822 - */
5823 - rw_enter(&exported_lock, RW_READER);
5824 -
5825 - /*
5826 5850 * If this is the first compound we've seen, we need to start all
5827 5851 * new instances' grace periods.
5828 5852 */
5829 5853 if (rfs4_seen_first_compound == 0) {
5830 5854 rfs4_grace_start_new();
5831 5855 /*
5832 5856 * This must be set after rfs4_grace_start_new(), otherwise
5833 5857 * another thread could proceed past here before the former
5834 5858 * is finished.
5835 5859 */
5836 5860 rfs4_seen_first_compound = 1;
5837 5861 }
5838 5862
5839 5863 for (i = 0; i < args->array_len && cs.cont; i++) {
5840 5864 nfs_argop4 *argop;
5841 5865 nfs_resop4 *resop;
5842 5866 uint_t op;
5843 5867
5844 5868 argop = &args->array[i];
5845 5869 resop = &resp->array[i];
5846 5870 resop->resop = argop->argop;
5847 5871 op = (uint_t)resop->resop;
5848 5872
5849 5873 if (op < rfsv4disp_cnt) {
5850 5874 /*
5851 5875 * Count the individual ops here; NULL and COMPOUND
5852 5876 * are counted in common_dispatch()
5853 5877 */
5854 5878 rfsproccnt_v4_ptr[op].value.ui64++;
5855 5879
5856 5880 NFS4_DEBUG(rfs4_debug > 1,
5857 5881 (CE_NOTE, "Executing %s", rfs4_op_string[op]));
5858 5882 (*rfsv4disptab[op].dis_proc)(argop, resop, req, &cs);
5859 5883 NFS4_DEBUG(rfs4_debug > 1, (CE_NOTE, "%s returned %d",
5860 5884 rfs4_op_string[op], *cs.statusp));
5861 5885 if (*cs.statusp != NFS4_OK)
5862 5886 cs.cont = FALSE;
5863 5887 } else {
5864 5888 /*
5865 5889 * This is effectively dead code since XDR code
5866 5890 * will have already returned BADXDR if op doesn't
5867 5891 * decode to legal value. This only done for a
5868 5892 * day when XDR code doesn't verify v4 opcodes.
5869 5893 */
5870 5894 op = OP_ILLEGAL;
5871 5895 rfsproccnt_v4_ptr[OP_ILLEGAL_IDX].value.ui64++;
5872 5896
5873 5897 rfs4_op_illegal(argop, resop, req, &cs);
5874 5898 cs.cont = FALSE;
5875 5899 }
5876 5900
5877 5901 /*
5878 5902 * If not at last op, and if we are to stop, then
5879 5903 * compact the results array.
5880 5904 */
5881 5905 if ((i + 1) < args->array_len && !cs.cont) {
5882 5906 nfs_resop4 *new_res = kmem_alloc(
5883 5907 (i+1) * sizeof (nfs_resop4), KM_SLEEP);
↓ open down ↓ |
48 lines elided |
↑ open up ↑ |
5884 5908 bcopy(resp->array,
5885 5909 new_res, (i+1) * sizeof (nfs_resop4));
5886 5910 kmem_free(resp->array,
5887 5911 args->array_len * sizeof (nfs_resop4));
5888 5912
5889 5913 resp->array_len = i + 1;
5890 5914 resp->array = new_res;
5891 5915 }
5892 5916 }
5893 5917
5894 - rw_exit(&exported_lock);
5895 5918
5896 5919 DTRACE_NFSV4_2(compound__done, struct compound_state *, &cs,
5897 5920 COMPOUND4res *, resp);
5898 5921
5922 + if (cs.exi)
5923 + exi_rele(cs.exi);
5924 + if (cs.saved_exi)
5925 + exi_rele(cs.saved_exi);
5899 5926 if (cs.vp)
5900 5927 VN_RELE(cs.vp);
5901 5928 if (cs.saved_vp)
5902 5929 VN_RELE(cs.saved_vp);
5903 5930 if (cs.saved_fh.nfs_fh4_val)
5904 5931 kmem_free(cs.saved_fh.nfs_fh4_val, NFS4_FHSIZE);
5905 5932
5906 5933 if (cs.basecr)
5907 5934 crfree(cs.basecr);
5908 5935 if (cs.cr)
5909 5936 crfree(cs.cr);
5910 5937 /*
5911 5938 * done with this compound request, free the label
5912 5939 */
5913 5940
5914 5941 if (req->rq_label != NULL) {
5915 5942 kmem_free(req->rq_label, sizeof (bslabel_t));
5916 5943 req->rq_label = NULL;
5917 5944 }
5918 5945 }
5919 5946
5920 5947 /*
5921 5948 * XXX because of what appears to be duplicate calls to rfs4_compound_free
5922 5949 * XXX zero out the tag and array values. Need to investigate why the
5923 5950 * XXX calls occur, but at least prevent the panic for now.
5924 5951 */
5925 5952 void
5926 5953 rfs4_compound_free(COMPOUND4res *resp)
5927 5954 {
5928 5955 uint_t i;
5929 5956
5930 5957 if (resp->tag.utf8string_val) {
5931 5958 UTF8STRING_FREE(resp->tag)
5932 5959 }
5933 5960
5934 5961 for (i = 0; i < resp->array_len; i++) {
5935 5962 nfs_resop4 *resop;
5936 5963 uint_t op;
5937 5964
5938 5965 resop = &resp->array[i];
5939 5966 op = (uint_t)resop->resop;
5940 5967 if (op < rfsv4disp_cnt) {
5941 5968 (*rfsv4disptab[op].dis_resfree)(resop);
5942 5969 }
5943 5970 }
5944 5971 if (resp->array != NULL) {
5945 5972 kmem_free(resp->array, resp->array_len * sizeof (nfs_resop4));
5946 5973 }
5947 5974 }
5948 5975
5949 5976 /*
5950 5977 * Process the value of the compound request rpc flags, as a bit-AND
5951 5978 * of the individual per-op flags (idempotent, allowork, publicfh_ok)
5952 5979 */
5953 5980 void
5954 5981 rfs4_compound_flagproc(COMPOUND4args *args, int *flagp)
5955 5982 {
5956 5983 int i;
5957 5984 int flag = RPC_ALL;
5958 5985
5959 5986 for (i = 0; flag && i < args->array_len; i++) {
5960 5987 uint_t op;
5961 5988
5962 5989 op = (uint_t)args->array[i].argop;
5963 5990
5964 5991 if (op < rfsv4disp_cnt)
5965 5992 flag &= rfsv4disptab[op].dis_flags;
5966 5993 else
5967 5994 flag = 0;
5968 5995 }
5969 5996 *flagp = flag;
5970 5997 }
5971 5998
5972 5999 nfsstat4
5973 6000 rfs4_client_sysid(rfs4_client_t *cp, sysid_t *sp)
5974 6001 {
5975 6002 nfsstat4 e;
5976 6003
5977 6004 rfs4_dbe_lock(cp->rc_dbe);
5978 6005
5979 6006 if (cp->rc_sysidt != LM_NOSYSID) {
5980 6007 *sp = cp->rc_sysidt;
5981 6008 e = NFS4_OK;
5982 6009
5983 6010 } else if ((cp->rc_sysidt = lm_alloc_sysidt()) != LM_NOSYSID) {
5984 6011 *sp = cp->rc_sysidt;
5985 6012 e = NFS4_OK;
5986 6013
5987 6014 NFS4_DEBUG(rfs4_debug, (CE_NOTE,
5988 6015 "rfs4_client_sysid: allocated 0x%x\n", *sp));
5989 6016 } else
5990 6017 e = NFS4ERR_DELAY;
5991 6018
5992 6019 rfs4_dbe_unlock(cp->rc_dbe);
5993 6020 return (e);
5994 6021 }
5995 6022
5996 6023 #if defined(DEBUG) && ! defined(lint)
5997 6024 static void lock_print(char *str, int operation, struct flock64 *flk)
5998 6025 {
5999 6026 char *op, *type;
6000 6027
6001 6028 switch (operation) {
6002 6029 case F_GETLK: op = "F_GETLK";
6003 6030 break;
6004 6031 case F_SETLK: op = "F_SETLK";
6005 6032 break;
6006 6033 case F_SETLK_NBMAND: op = "F_SETLK_NBMAND";
6007 6034 break;
6008 6035 default: op = "F_UNKNOWN";
6009 6036 break;
6010 6037 }
6011 6038 switch (flk->l_type) {
6012 6039 case F_UNLCK: type = "F_UNLCK";
6013 6040 break;
6014 6041 case F_RDLCK: type = "F_RDLCK";
6015 6042 break;
6016 6043 case F_WRLCK: type = "F_WRLCK";
6017 6044 break;
6018 6045 default: type = "F_UNKNOWN";
6019 6046 break;
6020 6047 }
6021 6048
6022 6049 ASSERT(flk->l_whence == 0);
6023 6050 cmn_err(CE_NOTE, "%s: %s, type = %s, off = %llx len = %llx pid = %d",
6024 6051 str, op, type, (longlong_t)flk->l_start,
6025 6052 flk->l_len ? (longlong_t)flk->l_len : ~0LL, flk->l_pid);
6026 6053 }
6027 6054
6028 6055 #define LOCK_PRINT(d, s, t, f) if (d) lock_print(s, t, f)
6029 6056 #else
6030 6057 #define LOCK_PRINT(d, s, t, f)
6031 6058 #endif
6032 6059
6033 6060 /*ARGSUSED*/
6034 6061 static bool_t
6035 6062 creds_ok(cred_set_t cr_set, struct svc_req *req, struct compound_state *cs)
6036 6063 {
6037 6064 return (TRUE);
6038 6065 }
6039 6066
6040 6067 /*
6041 6068 * Look up the pathname using the vp in cs as the directory vnode.
6042 6069 * cs->vp will be the vnode for the file on success
6043 6070 */
6044 6071
6045 6072 static nfsstat4
6046 6073 rfs4_lookup(component4 *component, struct svc_req *req,
6047 6074 struct compound_state *cs)
6048 6075 {
6049 6076 char *nm;
6050 6077 uint32_t len;
6051 6078 nfsstat4 status;
6052 6079 struct sockaddr *ca;
6053 6080 char *name;
6054 6081
6055 6082 if (cs->vp == NULL) {
6056 6083 return (NFS4ERR_NOFILEHANDLE);
6057 6084 }
6058 6085 if (cs->vp->v_type != VDIR) {
6059 6086 return (NFS4ERR_NOTDIR);
6060 6087 }
6061 6088
6062 6089 status = utf8_dir_verify(component);
6063 6090 if (status != NFS4_OK)
6064 6091 return (status);
6065 6092
6066 6093 nm = utf8_to_fn(component, &len, NULL);
6067 6094 if (nm == NULL) {
6068 6095 return (NFS4ERR_INVAL);
6069 6096 }
6070 6097
6071 6098 if (len > MAXNAMELEN) {
6072 6099 kmem_free(nm, len);
6073 6100 return (NFS4ERR_NAMETOOLONG);
6074 6101 }
6075 6102
6076 6103 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
6077 6104 name = nfscmd_convname(ca, cs->exi, nm, NFSCMD_CONV_INBOUND,
6078 6105 MAXPATHLEN + 1);
6079 6106
6080 6107 if (name == NULL) {
6081 6108 kmem_free(nm, len);
6082 6109 return (NFS4ERR_INVAL);
6083 6110 }
6084 6111
6085 6112 status = do_rfs4_op_lookup(name, req, cs);
6086 6113
6087 6114 if (name != nm)
6088 6115 kmem_free(name, MAXPATHLEN + 1);
6089 6116
6090 6117 kmem_free(nm, len);
6091 6118
6092 6119 return (status);
6093 6120 }
6094 6121
6095 6122 static nfsstat4
6096 6123 rfs4_lookupfile(component4 *component, struct svc_req *req,
6097 6124 struct compound_state *cs, uint32_t access, change_info4 *cinfo)
6098 6125 {
6099 6126 nfsstat4 status;
6100 6127 vnode_t *dvp = cs->vp;
6101 6128 vattr_t bva, ava, fva;
6102 6129 int error;
6103 6130
6104 6131 /* Get "before" change value */
6105 6132 bva.va_mask = AT_CTIME|AT_SEQ;
6106 6133 error = VOP_GETATTR(dvp, &bva, 0, cs->cr, NULL);
6107 6134 if (error)
6108 6135 return (puterrno4(error));
6109 6136
6110 6137 /* rfs4_lookup may VN_RELE directory */
6111 6138 VN_HOLD(dvp);
6112 6139
6113 6140 status = rfs4_lookup(component, req, cs);
6114 6141 if (status != NFS4_OK) {
6115 6142 VN_RELE(dvp);
6116 6143 return (status);
6117 6144 }
6118 6145
6119 6146 /*
6120 6147 * Get "after" change value, if it fails, simply return the
6121 6148 * before value.
6122 6149 */
6123 6150 ava.va_mask = AT_CTIME|AT_SEQ;
6124 6151 if (VOP_GETATTR(dvp, &ava, 0, cs->cr, NULL)) {
6125 6152 ava.va_ctime = bva.va_ctime;
6126 6153 ava.va_seq = 0;
6127 6154 }
6128 6155 VN_RELE(dvp);
6129 6156
6130 6157 /*
6131 6158 * Validate the file is a file
6132 6159 */
6133 6160 fva.va_mask = AT_TYPE|AT_MODE;
6134 6161 error = VOP_GETATTR(cs->vp, &fva, 0, cs->cr, NULL);
6135 6162 if (error)
6136 6163 return (puterrno4(error));
6137 6164
6138 6165 if (fva.va_type != VREG) {
6139 6166 if (fva.va_type == VDIR)
6140 6167 return (NFS4ERR_ISDIR);
6141 6168 if (fva.va_type == VLNK)
6142 6169 return (NFS4ERR_SYMLINK);
6143 6170 return (NFS4ERR_INVAL);
6144 6171 }
6145 6172
6146 6173 NFS4_SET_FATTR4_CHANGE(cinfo->before, bva.va_ctime);
6147 6174 NFS4_SET_FATTR4_CHANGE(cinfo->after, ava.va_ctime);
6148 6175
6149 6176 /*
6150 6177 * It is undefined if VOP_LOOKUP will change va_seq, so
6151 6178 * cinfo.atomic = TRUE only if we have
6152 6179 * non-zero va_seq's, and they have not changed.
6153 6180 */
6154 6181 if (bva.va_seq && ava.va_seq && ava.va_seq == bva.va_seq)
6155 6182 cinfo->atomic = TRUE;
6156 6183 else
6157 6184 cinfo->atomic = FALSE;
6158 6185
6159 6186 /* Check for mandatory locking */
6160 6187 cs->mandlock = MANDLOCK(cs->vp, fva.va_mode);
6161 6188 return (check_open_access(access, cs, req));
6162 6189 }
6163 6190
6164 6191 static nfsstat4
6165 6192 create_vnode(vnode_t *dvp, char *nm, vattr_t *vap, createmode4 mode,
6166 6193 timespec32_t *mtime, cred_t *cr, vnode_t **vpp, bool_t *created)
6167 6194 {
6168 6195 int error;
6169 6196 nfsstat4 status = NFS4_OK;
6170 6197 vattr_t va;
6171 6198
6172 6199 tryagain:
6173 6200
6174 6201 /*
6175 6202 * The file open mode used is VWRITE. If the client needs
6176 6203 * some other semantic, then it should do the access checking
6177 6204 * itself. It would have been nice to have the file open mode
6178 6205 * passed as part of the arguments.
6179 6206 */
6180 6207
6181 6208 *created = TRUE;
6182 6209 error = VOP_CREATE(dvp, nm, vap, EXCL, VWRITE, vpp, cr, 0, NULL, NULL);
6183 6210
6184 6211 if (error) {
6185 6212 *created = FALSE;
6186 6213
6187 6214 /*
6188 6215 * If we got something other than file already exists
6189 6216 * then just return this error. Otherwise, we got
6190 6217 * EEXIST. If we were doing a GUARDED create, then
6191 6218 * just return this error. Otherwise, we need to
6192 6219 * make sure that this wasn't a duplicate of an
6193 6220 * exclusive create request.
6194 6221 *
6195 6222 * The assumption is made that a non-exclusive create
6196 6223 * request will never return EEXIST.
6197 6224 */
6198 6225
6199 6226 if (error != EEXIST || mode == GUARDED4) {
6200 6227 status = puterrno4(error);
6201 6228 return (status);
6202 6229 }
6203 6230 error = VOP_LOOKUP(dvp, nm, vpp, NULL, 0, NULL, cr,
6204 6231 NULL, NULL, NULL);
6205 6232
6206 6233 if (error) {
6207 6234 /*
6208 6235 * We couldn't find the file that we thought that
6209 6236 * we just created. So, we'll just try creating
6210 6237 * it again.
6211 6238 */
6212 6239 if (error == ENOENT)
6213 6240 goto tryagain;
6214 6241
6215 6242 status = puterrno4(error);
6216 6243 return (status);
6217 6244 }
6218 6245
6219 6246 if (mode == UNCHECKED4) {
6220 6247 /* existing object must be regular file */
6221 6248 if ((*vpp)->v_type != VREG) {
6222 6249 if ((*vpp)->v_type == VDIR)
6223 6250 status = NFS4ERR_ISDIR;
6224 6251 else if ((*vpp)->v_type == VLNK)
6225 6252 status = NFS4ERR_SYMLINK;
6226 6253 else
6227 6254 status = NFS4ERR_INVAL;
6228 6255 VN_RELE(*vpp);
6229 6256 return (status);
6230 6257 }
6231 6258
6232 6259 return (NFS4_OK);
6233 6260 }
6234 6261
6235 6262 /* Check for duplicate request */
6236 6263 ASSERT(mtime != 0);
6237 6264 va.va_mask = AT_MTIME;
6238 6265 error = VOP_GETATTR(*vpp, &va, 0, cr, NULL);
6239 6266 if (!error) {
6240 6267 /* We found the file */
6241 6268 if (va.va_mtime.tv_sec != mtime->tv_sec ||
6242 6269 va.va_mtime.tv_nsec != mtime->tv_nsec) {
6243 6270 /* but its not our creation */
6244 6271 VN_RELE(*vpp);
6245 6272 return (NFS4ERR_EXIST);
6246 6273 }
6247 6274 *created = TRUE; /* retrans of create == created */
6248 6275 return (NFS4_OK);
6249 6276 }
6250 6277 VN_RELE(*vpp);
6251 6278 return (NFS4ERR_EXIST);
6252 6279 }
6253 6280
6254 6281 return (NFS4_OK);
6255 6282 }
6256 6283
6257 6284 static nfsstat4
6258 6285 check_open_access(uint32_t access, struct compound_state *cs,
6259 6286 struct svc_req *req)
6260 6287 {
6261 6288 int error;
6262 6289 vnode_t *vp;
6263 6290 bool_t readonly;
6264 6291 cred_t *cr = cs->cr;
6265 6292
6266 6293 /* For now we don't allow mandatory locking as per V2/V3 */
6267 6294 if (cs->access == CS_ACCESS_DENIED || cs->mandlock) {
6268 6295 return (NFS4ERR_ACCESS);
6269 6296 }
6270 6297
6271 6298 vp = cs->vp;
6272 6299 ASSERT(cr != NULL && vp->v_type == VREG);
6273 6300
6274 6301 /*
6275 6302 * If the file system is exported read only and we are trying
6276 6303 * to open for write, then return NFS4ERR_ROFS
6277 6304 */
6278 6305
6279 6306 readonly = rdonly4(req, cs);
6280 6307
6281 6308 if ((access & OPEN4_SHARE_ACCESS_WRITE) && readonly)
6282 6309 return (NFS4ERR_ROFS);
6283 6310
6284 6311 if (access & OPEN4_SHARE_ACCESS_READ) {
6285 6312 if ((VOP_ACCESS(vp, VREAD, 0, cr, NULL) != 0) &&
6286 6313 (VOP_ACCESS(vp, VEXEC, 0, cr, NULL) != 0)) {
6287 6314 return (NFS4ERR_ACCESS);
6288 6315 }
6289 6316 }
6290 6317
6291 6318 if (access & OPEN4_SHARE_ACCESS_WRITE) {
6292 6319 error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL);
6293 6320 if (error)
6294 6321 return (NFS4ERR_ACCESS);
6295 6322 }
6296 6323
6297 6324 return (NFS4_OK);
6298 6325 }
6299 6326
6300 6327 static nfsstat4
6301 6328 rfs4_createfile(OPEN4args *args, struct svc_req *req, struct compound_state *cs,
6302 6329 change_info4 *cinfo, bitmap4 *attrset, clientid4 clientid)
6303 6330 {
6304 6331 struct nfs4_svgetit_arg sarg;
6305 6332 struct nfs4_ntov_table ntov;
6306 6333
6307 6334 bool_t ntov_table_init = FALSE;
6308 6335 struct statvfs64 sb;
6309 6336 nfsstat4 status;
6310 6337 vnode_t *vp;
6311 6338 vattr_t bva, ava, iva, cva, *vap;
6312 6339 vnode_t *dvp;
6313 6340 timespec32_t *mtime;
6314 6341 char *nm = NULL;
6315 6342 uint_t buflen;
6316 6343 bool_t created;
6317 6344 bool_t setsize = FALSE;
6318 6345 len_t reqsize;
6319 6346 int error;
6320 6347 bool_t trunc;
6321 6348 caller_context_t ct;
6322 6349 component4 *component;
6323 6350 bslabel_t *clabel;
6324 6351 struct sockaddr *ca;
6325 6352 char *name = NULL;
6326 6353
6327 6354 sarg.sbp = &sb;
6328 6355 sarg.is_referral = B_FALSE;
6329 6356
6330 6357 dvp = cs->vp;
6331 6358
6332 6359 /* Check if the file system is read only */
6333 6360 if (rdonly4(req, cs))
6334 6361 return (NFS4ERR_ROFS);
6335 6362
6336 6363 /* check the label of including directory */
6337 6364 if (is_system_labeled()) {
6338 6365 ASSERT(req->rq_label != NULL);
6339 6366 clabel = req->rq_label;
6340 6367 DTRACE_PROBE2(tx__rfs4__log__info__opremove__clabel, char *,
6341 6368 "got client label from request(1)",
6342 6369 struct svc_req *, req);
6343 6370 if (!blequal(&l_admin_low->tsl_label, clabel)) {
6344 6371 if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK,
6345 6372 cs->exi)) {
6346 6373 return (NFS4ERR_ACCESS);
6347 6374 }
6348 6375 }
6349 6376 }
6350 6377
6351 6378 /*
6352 6379 * Get the last component of path name in nm. cs will reference
6353 6380 * the including directory on success.
6354 6381 */
6355 6382 component = &args->open_claim4_u.file;
6356 6383 status = utf8_dir_verify(component);
6357 6384 if (status != NFS4_OK)
6358 6385 return (status);
6359 6386
6360 6387 nm = utf8_to_fn(component, &buflen, NULL);
6361 6388
6362 6389 if (nm == NULL)
6363 6390 return (NFS4ERR_RESOURCE);
6364 6391
6365 6392 if (buflen > MAXNAMELEN) {
6366 6393 kmem_free(nm, buflen);
6367 6394 return (NFS4ERR_NAMETOOLONG);
6368 6395 }
6369 6396
6370 6397 bva.va_mask = AT_TYPE|AT_CTIME|AT_SEQ;
6371 6398 error = VOP_GETATTR(dvp, &bva, 0, cs->cr, NULL);
6372 6399 if (error) {
6373 6400 kmem_free(nm, buflen);
6374 6401 return (puterrno4(error));
6375 6402 }
6376 6403
6377 6404 if (bva.va_type != VDIR) {
6378 6405 kmem_free(nm, buflen);
6379 6406 return (NFS4ERR_NOTDIR);
6380 6407 }
6381 6408
6382 6409 NFS4_SET_FATTR4_CHANGE(cinfo->before, bva.va_ctime)
6383 6410
6384 6411 switch (args->mode) {
6385 6412 case GUARDED4:
6386 6413 /*FALLTHROUGH*/
6387 6414 case UNCHECKED4:
6388 6415 nfs4_ntov_table_init(&ntov);
6389 6416 ntov_table_init = TRUE;
6390 6417
6391 6418 *attrset = 0;
6392 6419 status = do_rfs4_set_attrs(attrset,
6393 6420 &args->createhow4_u.createattrs,
6394 6421 cs, &sarg, &ntov, NFS4ATTR_SETIT);
6395 6422
6396 6423 if (status == NFS4_OK && (sarg.vap->va_mask & AT_TYPE) &&
6397 6424 sarg.vap->va_type != VREG) {
6398 6425 if (sarg.vap->va_type == VDIR)
6399 6426 status = NFS4ERR_ISDIR;
6400 6427 else if (sarg.vap->va_type == VLNK)
6401 6428 status = NFS4ERR_SYMLINK;
6402 6429 else
6403 6430 status = NFS4ERR_INVAL;
6404 6431 }
6405 6432
6406 6433 if (status != NFS4_OK) {
6407 6434 kmem_free(nm, buflen);
6408 6435 nfs4_ntov_table_free(&ntov, &sarg);
6409 6436 *attrset = 0;
6410 6437 return (status);
6411 6438 }
6412 6439
6413 6440 vap = sarg.vap;
6414 6441 vap->va_type = VREG;
6415 6442 vap->va_mask |= AT_TYPE;
6416 6443
6417 6444 if ((vap->va_mask & AT_MODE) == 0) {
6418 6445 vap->va_mask |= AT_MODE;
6419 6446 vap->va_mode = (mode_t)0600;
6420 6447 }
6421 6448
6422 6449 if (vap->va_mask & AT_SIZE) {
6423 6450
6424 6451 /* Disallow create with a non-zero size */
6425 6452
6426 6453 if ((reqsize = sarg.vap->va_size) != 0) {
6427 6454 kmem_free(nm, buflen);
6428 6455 nfs4_ntov_table_free(&ntov, &sarg);
6429 6456 *attrset = 0;
6430 6457 return (NFS4ERR_INVAL);
6431 6458 }
6432 6459 setsize = TRUE;
6433 6460 }
6434 6461 break;
6435 6462
6436 6463 case EXCLUSIVE4:
6437 6464 /* prohibit EXCL create of named attributes */
6438 6465 if (dvp->v_flag & V_XATTRDIR) {
6439 6466 kmem_free(nm, buflen);
6440 6467 *attrset = 0;
6441 6468 return (NFS4ERR_INVAL);
6442 6469 }
6443 6470
6444 6471 cva.va_mask = AT_TYPE | AT_MTIME | AT_MODE;
6445 6472 cva.va_type = VREG;
6446 6473 /*
6447 6474 * Ensure no time overflows. Assumes underlying
6448 6475 * filesystem supports at least 32 bits.
6449 6476 * Truncate nsec to usec resolution to allow valid
6450 6477 * compares even if the underlying filesystem truncates.
6451 6478 */
6452 6479 mtime = (timespec32_t *)&args->createhow4_u.createverf;
6453 6480 cva.va_mtime.tv_sec = mtime->tv_sec % TIME32_MAX;
6454 6481 cva.va_mtime.tv_nsec = (mtime->tv_nsec / 1000) * 1000;
6455 6482 cva.va_mode = (mode_t)0;
6456 6483 vap = &cva;
6457 6484
6458 6485 /*
6459 6486 * For EXCL create, attrset is set to the server attr
6460 6487 * used to cache the client's verifier.
6461 6488 */
6462 6489 *attrset = FATTR4_TIME_MODIFY_MASK;
6463 6490 break;
6464 6491 }
6465 6492
6466 6493 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
6467 6494 name = nfscmd_convname(ca, cs->exi, nm, NFSCMD_CONV_INBOUND,
6468 6495 MAXPATHLEN + 1);
6469 6496
6470 6497 if (name == NULL) {
6471 6498 kmem_free(nm, buflen);
6472 6499 return (NFS4ERR_SERVERFAULT);
6473 6500 }
6474 6501
6475 6502 status = create_vnode(dvp, name, vap, args->mode, mtime,
6476 6503 cs->cr, &vp, &created);
6477 6504 if (nm != name)
6478 6505 kmem_free(name, MAXPATHLEN + 1);
6479 6506 kmem_free(nm, buflen);
6480 6507
6481 6508 if (status != NFS4_OK) {
6482 6509 if (ntov_table_init)
6483 6510 nfs4_ntov_table_free(&ntov, &sarg);
6484 6511 *attrset = 0;
6485 6512 return (status);
6486 6513 }
6487 6514
6488 6515 trunc = (setsize && !created);
6489 6516
6490 6517 if (args->mode != EXCLUSIVE4) {
6491 6518 bitmap4 createmask = args->createhow4_u.createattrs.attrmask;
6492 6519
6493 6520 /*
6494 6521 * True verification that object was created with correct
6495 6522 * attrs is impossible. The attrs could have been changed
6496 6523 * immediately after object creation. If attributes did
6497 6524 * not verify, the only recourse for the server is to
6498 6525 * destroy the object. Maybe if some attrs (like gid)
6499 6526 * are set incorrectly, the object should be destroyed;
6500 6527 * however, seems bad as a default policy. Do we really
6501 6528 * want to destroy an object over one of the times not
6502 6529 * verifying correctly? For these reasons, the server
6503 6530 * currently sets bits in attrset for createattrs
6504 6531 * that were set; however, no verification is done.
6505 6532 *
6506 6533 * vmask_to_nmask accounts for vattr bits set on create
6507 6534 * [do_rfs4_set_attrs() only sets resp bits for
6508 6535 * non-vattr/vfs bits.]
6509 6536 * Mask off any bits we set by default so as not to return
6510 6537 * more attrset bits than were requested in createattrs
6511 6538 */
6512 6539 if (created) {
6513 6540 nfs4_vmask_to_nmask(sarg.vap->va_mask, attrset);
6514 6541 *attrset &= createmask;
6515 6542 } else {
6516 6543 /*
6517 6544 * We did not create the vnode (we tried but it
6518 6545 * already existed). In this case, the only createattr
6519 6546 * that the spec allows the server to set is size,
6520 6547 * and even then, it can only be set if it is 0.
6521 6548 */
6522 6549 *attrset = 0;
6523 6550 if (trunc)
6524 6551 *attrset = FATTR4_SIZE_MASK;
6525 6552 }
6526 6553 }
6527 6554 if (ntov_table_init)
6528 6555 nfs4_ntov_table_free(&ntov, &sarg);
6529 6556
6530 6557 /*
6531 6558 * Get the initial "after" sequence number, if it fails,
6532 6559 * set to zero, time to before.
6533 6560 */
6534 6561 iva.va_mask = AT_CTIME|AT_SEQ;
6535 6562 if (VOP_GETATTR(dvp, &iva, 0, cs->cr, NULL)) {
6536 6563 iva.va_seq = 0;
6537 6564 iva.va_ctime = bva.va_ctime;
6538 6565 }
6539 6566
6540 6567 /*
6541 6568 * create_vnode attempts to create the file exclusive,
6542 6569 * if it already exists the VOP_CREATE will fail and
6543 6570 * may not increase va_seq. It is atomic if
6544 6571 * we haven't changed the directory, but if it has changed
6545 6572 * we don't know what changed it.
6546 6573 */
6547 6574 if (!created) {
6548 6575 if (bva.va_seq && iva.va_seq &&
6549 6576 bva.va_seq == iva.va_seq)
6550 6577 cinfo->atomic = TRUE;
6551 6578 else
6552 6579 cinfo->atomic = FALSE;
6553 6580 NFS4_SET_FATTR4_CHANGE(cinfo->after, iva.va_ctime);
6554 6581 } else {
6555 6582 /*
6556 6583 * The entry was created, we need to sync the
6557 6584 * directory metadata.
6558 6585 */
6559 6586 (void) VOP_FSYNC(dvp, 0, cs->cr, NULL);
6560 6587
6561 6588 /*
6562 6589 * Get "after" change value, if it fails, simply return the
6563 6590 * before value.
6564 6591 */
6565 6592 ava.va_mask = AT_CTIME|AT_SEQ;
6566 6593 if (VOP_GETATTR(dvp, &ava, 0, cs->cr, NULL)) {
6567 6594 ava.va_ctime = bva.va_ctime;
6568 6595 ava.va_seq = 0;
6569 6596 }
6570 6597
6571 6598 NFS4_SET_FATTR4_CHANGE(cinfo->after, ava.va_ctime);
6572 6599
6573 6600 /*
6574 6601 * The cinfo->atomic = TRUE only if we have
6575 6602 * non-zero va_seq's, and it has incremented by exactly one
6576 6603 * during the create_vnode and it didn't
6577 6604 * change during the VOP_FSYNC.
6578 6605 */
6579 6606 if (bva.va_seq && iva.va_seq && ava.va_seq &&
6580 6607 iva.va_seq == (bva.va_seq + 1) && iva.va_seq == ava.va_seq)
6581 6608 cinfo->atomic = TRUE;
6582 6609 else
6583 6610 cinfo->atomic = FALSE;
6584 6611 }
6585 6612
6586 6613 /* Check for mandatory locking and that the size gets set. */
6587 6614 cva.va_mask = AT_MODE;
6588 6615 if (setsize)
6589 6616 cva.va_mask |= AT_SIZE;
6590 6617
6591 6618 /* Assume the worst */
6592 6619 cs->mandlock = TRUE;
6593 6620
6594 6621 if (VOP_GETATTR(vp, &cva, 0, cs->cr, NULL) == 0) {
6595 6622 cs->mandlock = MANDLOCK(cs->vp, cva.va_mode);
6596 6623
6597 6624 /*
6598 6625 * Truncate the file if necessary; this would be
6599 6626 * the case for create over an existing file.
6600 6627 */
6601 6628
6602 6629 if (trunc) {
6603 6630 int in_crit = 0;
6604 6631 rfs4_file_t *fp;
6605 6632 bool_t create = FALSE;
6606 6633
6607 6634 /*
6608 6635 * We are writing over an existing file.
6609 6636 * Check to see if we need to recall a delegation.
6610 6637 */
6611 6638 rfs4_hold_deleg_policy();
6612 6639 if ((fp = rfs4_findfile(vp, NULL, &create)) != NULL) {
6613 6640 if (rfs4_check_delegated_byfp(FWRITE, fp,
6614 6641 (reqsize == 0), FALSE, FALSE, &clientid)) {
6615 6642 rfs4_file_rele(fp);
6616 6643 rfs4_rele_deleg_policy();
6617 6644 VN_RELE(vp);
6618 6645 *attrset = 0;
6619 6646 return (NFS4ERR_DELAY);
6620 6647 }
6621 6648 rfs4_file_rele(fp);
6622 6649 }
6623 6650 rfs4_rele_deleg_policy();
6624 6651
6625 6652 if (nbl_need_check(vp)) {
6626 6653 in_crit = 1;
6627 6654
6628 6655 ASSERT(reqsize == 0);
6629 6656
6630 6657 nbl_start_crit(vp, RW_READER);
6631 6658 if (nbl_conflict(vp, NBL_WRITE, 0,
6632 6659 cva.va_size, 0, NULL)) {
6633 6660 in_crit = 0;
6634 6661 nbl_end_crit(vp);
6635 6662 VN_RELE(vp);
6636 6663 *attrset = 0;
6637 6664 return (NFS4ERR_ACCESS);
6638 6665 }
6639 6666 }
6640 6667 ct.cc_sysid = 0;
6641 6668 ct.cc_pid = 0;
6642 6669 ct.cc_caller_id = nfs4_srv_caller_id;
6643 6670 ct.cc_flags = CC_DONTBLOCK;
6644 6671
6645 6672 cva.va_mask = AT_SIZE;
6646 6673 cva.va_size = reqsize;
6647 6674 (void) VOP_SETATTR(vp, &cva, 0, cs->cr, &ct);
6648 6675 if (in_crit)
6649 6676 nbl_end_crit(vp);
6650 6677 }
6651 6678 }
6652 6679
6653 6680 error = makefh4(&cs->fh, vp, cs->exi);
6654 6681
6655 6682 /*
6656 6683 * Force modified data and metadata out to stable storage.
6657 6684 */
6658 6685 (void) VOP_FSYNC(vp, FNODSYNC, cs->cr, NULL);
6659 6686
6660 6687 if (error) {
6661 6688 VN_RELE(vp);
6662 6689 *attrset = 0;
6663 6690 return (puterrno4(error));
6664 6691 }
6665 6692
6666 6693 /* if parent dir is attrdir, set namedattr fh flag */
6667 6694 if (dvp->v_flag & V_XATTRDIR)
6668 6695 set_fh4_flag(&cs->fh, FH4_NAMEDATTR);
6669 6696
6670 6697 if (cs->vp)
6671 6698 VN_RELE(cs->vp);
6672 6699
6673 6700 cs->vp = vp;
6674 6701
6675 6702 /*
6676 6703 * if we did not create the file, we will need to check
6677 6704 * the access bits on the file
6678 6705 */
6679 6706
6680 6707 if (!created) {
6681 6708 if (setsize)
6682 6709 args->share_access |= OPEN4_SHARE_ACCESS_WRITE;
6683 6710 status = check_open_access(args->share_access, cs, req);
6684 6711 if (status != NFS4_OK)
6685 6712 *attrset = 0;
6686 6713 }
6687 6714 return (status);
6688 6715 }
6689 6716
6690 6717 /*ARGSUSED*/
6691 6718 static void
6692 6719 rfs4_do_open(struct compound_state *cs, struct svc_req *req,
6693 6720 rfs4_openowner_t *oo, delegreq_t deleg,
6694 6721 uint32_t access, uint32_t deny,
6695 6722 OPEN4res *resp, int deleg_cur)
6696 6723 {
6697 6724 /* XXX Currently not using req */
6698 6725 rfs4_state_t *sp;
6699 6726 rfs4_file_t *fp;
6700 6727 bool_t screate = TRUE;
6701 6728 bool_t fcreate = TRUE;
6702 6729 uint32_t open_a, share_a;
6703 6730 uint32_t open_d, share_d;
6704 6731 rfs4_deleg_state_t *dsp;
6705 6732 sysid_t sysid;
6706 6733 nfsstat4 status;
6707 6734 caller_context_t ct;
6708 6735 int fflags = 0;
6709 6736 int recall = 0;
6710 6737 int err;
6711 6738 int first_open;
6712 6739
6713 6740 /* get the file struct and hold a lock on it during initial open */
6714 6741 fp = rfs4_findfile_withlock(cs->vp, &cs->fh, &fcreate);
6715 6742 if (fp == NULL) {
6716 6743 resp->status = NFS4ERR_RESOURCE;
6717 6744 DTRACE_PROBE1(nfss__e__do__open1, nfsstat4, resp->status);
6718 6745 return;
6719 6746 }
6720 6747
6721 6748 sp = rfs4_findstate_by_owner_file(oo, fp, &screate);
6722 6749 if (sp == NULL) {
6723 6750 resp->status = NFS4ERR_RESOURCE;
6724 6751 DTRACE_PROBE1(nfss__e__do__open2, nfsstat4, resp->status);
6725 6752 /* No need to keep any reference */
6726 6753 rw_exit(&fp->rf_file_rwlock);
6727 6754 rfs4_file_rele(fp);
6728 6755 return;
6729 6756 }
6730 6757
6731 6758 /* try to get the sysid before continuing */
6732 6759 if ((status = rfs4_client_sysid(oo->ro_client, &sysid)) != NFS4_OK) {
6733 6760 resp->status = status;
6734 6761 rfs4_file_rele(fp);
6735 6762 /* Not a fully formed open; "close" it */
6736 6763 if (screate == TRUE)
6737 6764 rfs4_state_close(sp, FALSE, FALSE, cs->cr);
6738 6765 rfs4_state_rele(sp);
6739 6766 return;
6740 6767 }
6741 6768
6742 6769 /* Calculate the fflags for this OPEN. */
6743 6770 if (access & OPEN4_SHARE_ACCESS_READ)
6744 6771 fflags |= FREAD;
6745 6772 if (access & OPEN4_SHARE_ACCESS_WRITE)
6746 6773 fflags |= FWRITE;
6747 6774
6748 6775 rfs4_dbe_lock(sp->rs_dbe);
6749 6776
6750 6777 /*
6751 6778 * Calculate the new deny and access mode that this open is adding to
6752 6779 * the file for this open owner;
6753 6780 */
6754 6781 open_d = (deny & ~sp->rs_open_deny);
6755 6782 open_a = (access & ~sp->rs_open_access);
6756 6783
6757 6784 /*
6758 6785 * Calculate the new share access and share deny modes that this open
6759 6786 * is adding to the file for this open owner;
6760 6787 */
6761 6788 share_a = (access & ~sp->rs_share_access);
6762 6789 share_d = (deny & ~sp->rs_share_deny);
6763 6790
6764 6791 first_open = (sp->rs_open_access & OPEN4_SHARE_ACCESS_BOTH) == 0;
6765 6792
6766 6793 /*
6767 6794 * Check to see the client has already sent an open for this
6768 6795 * open owner on this file with the same share/deny modes.
6769 6796 * If so, we don't need to check for a conflict and we don't
6770 6797 * need to add another shrlock. If not, then we need to
6771 6798 * check for conflicts in deny and access before checking for
6772 6799 * conflicts in delegation. We don't want to recall a
6773 6800 * delegation based on an open that will eventually fail based
6774 6801 * on shares modes.
6775 6802 */
6776 6803
6777 6804 if (share_a || share_d) {
6778 6805 if ((err = rfs4_share(sp, access, deny)) != 0) {
6779 6806 rfs4_dbe_unlock(sp->rs_dbe);
6780 6807 resp->status = err;
6781 6808
6782 6809 rfs4_file_rele(fp);
6783 6810 /* Not a fully formed open; "close" it */
6784 6811 if (screate == TRUE)
6785 6812 rfs4_state_close(sp, FALSE, FALSE, cs->cr);
6786 6813 rfs4_state_rele(sp);
6787 6814 return;
6788 6815 }
6789 6816 }
6790 6817
6791 6818 rfs4_dbe_lock(fp->rf_dbe);
6792 6819
6793 6820 /*
6794 6821 * Check to see if this file is delegated and if so, if a
6795 6822 * recall needs to be done.
6796 6823 */
6797 6824 if (rfs4_check_recall(sp, access)) {
6798 6825 rfs4_dbe_unlock(fp->rf_dbe);
6799 6826 rfs4_dbe_unlock(sp->rs_dbe);
6800 6827 rfs4_recall_deleg(fp, FALSE, sp->rs_owner->ro_client);
6801 6828 delay(NFS4_DELEGATION_CONFLICT_DELAY);
6802 6829 rfs4_dbe_lock(sp->rs_dbe);
6803 6830
6804 6831 /* if state closed while lock was dropped */
6805 6832 if (sp->rs_closed) {
6806 6833 if (share_a || share_d)
6807 6834 (void) rfs4_unshare(sp);
6808 6835 rfs4_dbe_unlock(sp->rs_dbe);
6809 6836 rfs4_file_rele(fp);
6810 6837 /* Not a fully formed open; "close" it */
6811 6838 if (screate == TRUE)
6812 6839 rfs4_state_close(sp, FALSE, FALSE, cs->cr);
6813 6840 rfs4_state_rele(sp);
6814 6841 resp->status = NFS4ERR_OLD_STATEID;
6815 6842 return;
6816 6843 }
6817 6844
6818 6845 rfs4_dbe_lock(fp->rf_dbe);
6819 6846 /* Let's see if the delegation was returned */
6820 6847 if (rfs4_check_recall(sp, access)) {
6821 6848 rfs4_dbe_unlock(fp->rf_dbe);
6822 6849 if (share_a || share_d)
6823 6850 (void) rfs4_unshare(sp);
6824 6851 rfs4_dbe_unlock(sp->rs_dbe);
6825 6852 rfs4_file_rele(fp);
6826 6853 rfs4_update_lease(sp->rs_owner->ro_client);
6827 6854
6828 6855 /* Not a fully formed open; "close" it */
6829 6856 if (screate == TRUE)
6830 6857 rfs4_state_close(sp, FALSE, FALSE, cs->cr);
6831 6858 rfs4_state_rele(sp);
6832 6859 resp->status = NFS4ERR_DELAY;
6833 6860 return;
6834 6861 }
6835 6862 }
6836 6863 /*
6837 6864 * the share check passed and any delegation conflict has been
6838 6865 * taken care of, now call vop_open.
6839 6866 * if this is the first open then call vop_open with fflags.
6840 6867 * if not, call vn_open_upgrade with just the upgrade flags.
6841 6868 *
6842 6869 * if the file has been opened already, it will have the current
6843 6870 * access mode in the state struct. if it has no share access, then
6844 6871 * this is a new open.
6845 6872 *
6846 6873 * However, if this is open with CLAIM_DLEGATE_CUR, then don't
6847 6874 * call VOP_OPEN(), just do the open upgrade.
6848 6875 */
6849 6876 if (first_open && !deleg_cur) {
6850 6877 ct.cc_sysid = sysid;
6851 6878 ct.cc_pid = rfs4_dbe_getid(sp->rs_owner->ro_dbe);
6852 6879 ct.cc_caller_id = nfs4_srv_caller_id;
6853 6880 ct.cc_flags = CC_DONTBLOCK;
6854 6881 err = VOP_OPEN(&cs->vp, fflags, cs->cr, &ct);
6855 6882 if (err) {
6856 6883 rfs4_dbe_unlock(fp->rf_dbe);
6857 6884 if (share_a || share_d)
6858 6885 (void) rfs4_unshare(sp);
6859 6886 rfs4_dbe_unlock(sp->rs_dbe);
6860 6887 rfs4_file_rele(fp);
6861 6888
6862 6889 /* Not a fully formed open; "close" it */
6863 6890 if (screate == TRUE)
6864 6891 rfs4_state_close(sp, FALSE, FALSE, cs->cr);
6865 6892 rfs4_state_rele(sp);
6866 6893 /* check if a monitor detected a delegation conflict */
6867 6894 if (err == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK))
6868 6895 resp->status = NFS4ERR_DELAY;
6869 6896 else
6870 6897 resp->status = NFS4ERR_SERVERFAULT;
6871 6898 return;
6872 6899 }
6873 6900 } else { /* open upgrade */
6874 6901 /*
6875 6902 * calculate the fflags for the new mode that is being added
6876 6903 * by this upgrade.
6877 6904 */
6878 6905 fflags = 0;
6879 6906 if (open_a & OPEN4_SHARE_ACCESS_READ)
6880 6907 fflags |= FREAD;
6881 6908 if (open_a & OPEN4_SHARE_ACCESS_WRITE)
6882 6909 fflags |= FWRITE;
6883 6910 vn_open_upgrade(cs->vp, fflags);
6884 6911 }
6885 6912 sp->rs_open_access |= access;
6886 6913 sp->rs_open_deny |= deny;
6887 6914
6888 6915 if (open_d & OPEN4_SHARE_DENY_READ)
6889 6916 fp->rf_deny_read++;
6890 6917 if (open_d & OPEN4_SHARE_DENY_WRITE)
6891 6918 fp->rf_deny_write++;
6892 6919 fp->rf_share_deny |= deny;
6893 6920
6894 6921 if (open_a & OPEN4_SHARE_ACCESS_READ)
6895 6922 fp->rf_access_read++;
6896 6923 if (open_a & OPEN4_SHARE_ACCESS_WRITE)
6897 6924 fp->rf_access_write++;
6898 6925 fp->rf_share_access |= access;
6899 6926
6900 6927 /*
6901 6928 * Check for delegation here. if the deleg argument is not
6902 6929 * DELEG_ANY, then this is a reclaim from a client and
6903 6930 * we must honor the delegation requested. If necessary we can
6904 6931 * set the recall flag.
6905 6932 */
6906 6933
6907 6934 dsp = rfs4_grant_delegation(deleg, sp, &recall);
6908 6935
6909 6936 cs->deleg = (fp->rf_dinfo.rd_dtype == OPEN_DELEGATE_WRITE);
6910 6937
6911 6938 next_stateid(&sp->rs_stateid);
6912 6939
6913 6940 resp->stateid = sp->rs_stateid.stateid;
6914 6941
6915 6942 rfs4_dbe_unlock(fp->rf_dbe);
6916 6943 rfs4_dbe_unlock(sp->rs_dbe);
6917 6944
6918 6945 if (dsp) {
6919 6946 rfs4_set_deleg_response(dsp, &resp->delegation, NULL, recall);
6920 6947 rfs4_deleg_state_rele(dsp);
6921 6948 }
6922 6949
6923 6950 rfs4_file_rele(fp);
6924 6951 rfs4_state_rele(sp);
6925 6952
6926 6953 resp->status = NFS4_OK;
6927 6954 }
6928 6955
6929 6956 /*ARGSUSED*/
6930 6957 static void
6931 6958 rfs4_do_opennull(struct compound_state *cs, struct svc_req *req,
6932 6959 OPEN4args *args, rfs4_openowner_t *oo, OPEN4res *resp)
6933 6960 {
6934 6961 change_info4 *cinfo = &resp->cinfo;
6935 6962 bitmap4 *attrset = &resp->attrset;
6936 6963
6937 6964 if (args->opentype == OPEN4_NOCREATE)
6938 6965 resp->status = rfs4_lookupfile(&args->open_claim4_u.file,
6939 6966 req, cs, args->share_access, cinfo);
6940 6967 else {
6941 6968 /* inhibit delegation grants during exclusive create */
6942 6969
6943 6970 if (args->mode == EXCLUSIVE4)
6944 6971 rfs4_disable_delegation();
6945 6972
6946 6973 resp->status = rfs4_createfile(args, req, cs, cinfo, attrset,
6947 6974 oo->ro_client->rc_clientid);
6948 6975 }
6949 6976
6950 6977 if (resp->status == NFS4_OK) {
6951 6978
6952 6979 /* cs->vp cs->fh now reference the desired file */
6953 6980
6954 6981 rfs4_do_open(cs, req, oo,
6955 6982 oo->ro_need_confirm ? DELEG_NONE : DELEG_ANY,
6956 6983 args->share_access, args->share_deny, resp, 0);
6957 6984
6958 6985 /*
6959 6986 * If rfs4_createfile set attrset, we must
6960 6987 * clear this attrset before the response is copied.
6961 6988 */
6962 6989 if (resp->status != NFS4_OK && resp->attrset) {
6963 6990 resp->attrset = 0;
6964 6991 }
6965 6992 }
6966 6993 else
6967 6994 *cs->statusp = resp->status;
6968 6995
6969 6996 if (args->mode == EXCLUSIVE4)
6970 6997 rfs4_enable_delegation();
6971 6998 }
6972 6999
6973 7000 /*ARGSUSED*/
6974 7001 static void
6975 7002 rfs4_do_openprev(struct compound_state *cs, struct svc_req *req,
6976 7003 OPEN4args *args, rfs4_openowner_t *oo, OPEN4res *resp)
6977 7004 {
6978 7005 change_info4 *cinfo = &resp->cinfo;
6979 7006 vattr_t va;
6980 7007 vtype_t v_type = cs->vp->v_type;
6981 7008 int error = 0;
6982 7009
6983 7010 /* Verify that we have a regular file */
6984 7011 if (v_type != VREG) {
6985 7012 if (v_type == VDIR)
6986 7013 resp->status = NFS4ERR_ISDIR;
6987 7014 else if (v_type == VLNK)
6988 7015 resp->status = NFS4ERR_SYMLINK;
6989 7016 else
6990 7017 resp->status = NFS4ERR_INVAL;
6991 7018 return;
6992 7019 }
6993 7020
6994 7021 va.va_mask = AT_MODE|AT_UID;
6995 7022 error = VOP_GETATTR(cs->vp, &va, 0, cs->cr, NULL);
6996 7023 if (error) {
6997 7024 resp->status = puterrno4(error);
6998 7025 return;
6999 7026 }
7000 7027
7001 7028 cs->mandlock = MANDLOCK(cs->vp, va.va_mode);
7002 7029
7003 7030 /*
7004 7031 * Check if we have access to the file, Note the the file
7005 7032 * could have originally been open UNCHECKED or GUARDED
7006 7033 * with mode bits that will now fail, but there is nothing
7007 7034 * we can really do about that except in the case that the
7008 7035 * owner of the file is the one requesting the open.
7009 7036 */
7010 7037 if (crgetuid(cs->cr) != va.va_uid) {
7011 7038 resp->status = check_open_access(args->share_access, cs, req);
7012 7039 if (resp->status != NFS4_OK) {
7013 7040 return;
7014 7041 }
7015 7042 }
7016 7043
7017 7044 /*
7018 7045 * cinfo on a CLAIM_PREVIOUS is undefined, initialize to zero
7019 7046 */
7020 7047 cinfo->before = 0;
7021 7048 cinfo->after = 0;
7022 7049 cinfo->atomic = FALSE;
7023 7050
7024 7051 rfs4_do_open(cs, req, oo,
7025 7052 NFS4_DELEG4TYPE2REQTYPE(args->open_claim4_u.delegate_type),
7026 7053 args->share_access, args->share_deny, resp, 0);
7027 7054 }
7028 7055
7029 7056 static void
7030 7057 rfs4_do_opendelcur(struct compound_state *cs, struct svc_req *req,
7031 7058 OPEN4args *args, rfs4_openowner_t *oo, OPEN4res *resp)
7032 7059 {
7033 7060 int error;
7034 7061 nfsstat4 status;
7035 7062 stateid4 stateid =
7036 7063 args->open_claim4_u.delegate_cur_info.delegate_stateid;
7037 7064 rfs4_deleg_state_t *dsp;
7038 7065
7039 7066 /*
7040 7067 * Find the state info from the stateid and confirm that the
7041 7068 * file is delegated. If the state openowner is the same as
7042 7069 * the supplied openowner we're done. If not, get the file
7043 7070 * info from the found state info. Use that file info to
7044 7071 * create the state for this lock owner. Note solaris doen't
7045 7072 * really need the pathname to find the file. We may want to
7046 7073 * lookup the pathname and make sure that the vp exist and
7047 7074 * matches the vp in the file structure. However it is
7048 7075 * possible that the pathname nolonger exists (local process
7049 7076 * unlinks the file), so this may not be that useful.
7050 7077 */
7051 7078
7052 7079 status = rfs4_get_deleg_state(&stateid, &dsp);
7053 7080 if (status != NFS4_OK) {
7054 7081 resp->status = status;
7055 7082 return;
7056 7083 }
7057 7084
7058 7085 ASSERT(dsp->rds_finfo->rf_dinfo.rd_dtype != OPEN_DELEGATE_NONE);
7059 7086
7060 7087 /*
7061 7088 * New lock owner, create state. Since this was probably called
7062 7089 * in response to a CB_RECALL we set deleg to DELEG_NONE
7063 7090 */
7064 7091
7065 7092 ASSERT(cs->vp != NULL);
7066 7093 VN_RELE(cs->vp);
7067 7094 VN_HOLD(dsp->rds_finfo->rf_vp);
7068 7095 cs->vp = dsp->rds_finfo->rf_vp;
7069 7096
7070 7097 if (error = makefh4(&cs->fh, cs->vp, cs->exi)) {
7071 7098 rfs4_deleg_state_rele(dsp);
7072 7099 *cs->statusp = resp->status = puterrno4(error);
7073 7100 return;
7074 7101 }
7075 7102
7076 7103 /* Mark progress for delegation returns */
7077 7104 dsp->rds_finfo->rf_dinfo.rd_time_lastwrite = gethrestime_sec();
7078 7105 rfs4_deleg_state_rele(dsp);
7079 7106 rfs4_do_open(cs, req, oo, DELEG_NONE,
7080 7107 args->share_access, args->share_deny, resp, 1);
7081 7108 }
7082 7109
7083 7110 /*ARGSUSED*/
7084 7111 static void
7085 7112 rfs4_do_opendelprev(struct compound_state *cs, struct svc_req *req,
7086 7113 OPEN4args *args, rfs4_openowner_t *oo, OPEN4res *resp)
7087 7114 {
7088 7115 /*
7089 7116 * Lookup the pathname, it must already exist since this file
7090 7117 * was delegated.
7091 7118 *
7092 7119 * Find the file and state info for this vp and open owner pair.
7093 7120 * check that they are in fact delegated.
7094 7121 * check that the state access and deny modes are the same.
7095 7122 *
7096 7123 * Return the delgation possibly seting the recall flag.
7097 7124 */
7098 7125 rfs4_file_t *fp;
7099 7126 rfs4_state_t *sp;
7100 7127 bool_t create = FALSE;
7101 7128 bool_t dcreate = FALSE;
7102 7129 rfs4_deleg_state_t *dsp;
7103 7130 nfsace4 *ace;
7104 7131
7105 7132 /* Note we ignore oflags */
7106 7133 resp->status = rfs4_lookupfile(&args->open_claim4_u.file_delegate_prev,
7107 7134 req, cs, args->share_access, &resp->cinfo);
7108 7135
7109 7136 if (resp->status != NFS4_OK) {
7110 7137 return;
7111 7138 }
7112 7139
7113 7140 /* get the file struct and hold a lock on it during initial open */
7114 7141 fp = rfs4_findfile_withlock(cs->vp, NULL, &create);
7115 7142 if (fp == NULL) {
7116 7143 resp->status = NFS4ERR_RESOURCE;
7117 7144 DTRACE_PROBE1(nfss__e__do_opendelprev1, nfsstat4, resp->status);
7118 7145 return;
7119 7146 }
7120 7147
7121 7148 sp = rfs4_findstate_by_owner_file(oo, fp, &create);
7122 7149 if (sp == NULL) {
7123 7150 resp->status = NFS4ERR_SERVERFAULT;
7124 7151 DTRACE_PROBE1(nfss__e__do_opendelprev2, nfsstat4, resp->status);
7125 7152 rw_exit(&fp->rf_file_rwlock);
7126 7153 rfs4_file_rele(fp);
7127 7154 return;
7128 7155 }
7129 7156
7130 7157 rfs4_dbe_lock(sp->rs_dbe);
7131 7158 rfs4_dbe_lock(fp->rf_dbe);
7132 7159 if (args->share_access != sp->rs_share_access ||
7133 7160 args->share_deny != sp->rs_share_deny ||
7134 7161 sp->rs_finfo->rf_dinfo.rd_dtype == OPEN_DELEGATE_NONE) {
7135 7162 NFS4_DEBUG(rfs4_debug,
7136 7163 (CE_NOTE, "rfs4_do_opendelprev: state mixup"));
7137 7164 rfs4_dbe_unlock(fp->rf_dbe);
7138 7165 rfs4_dbe_unlock(sp->rs_dbe);
7139 7166 rfs4_file_rele(fp);
7140 7167 rfs4_state_rele(sp);
7141 7168 resp->status = NFS4ERR_SERVERFAULT;
7142 7169 return;
7143 7170 }
7144 7171 rfs4_dbe_unlock(fp->rf_dbe);
7145 7172 rfs4_dbe_unlock(sp->rs_dbe);
7146 7173
7147 7174 dsp = rfs4_finddeleg(sp, &dcreate);
7148 7175 if (dsp == NULL) {
7149 7176 rfs4_state_rele(sp);
7150 7177 rfs4_file_rele(fp);
7151 7178 resp->status = NFS4ERR_SERVERFAULT;
7152 7179 return;
7153 7180 }
7154 7181
7155 7182 next_stateid(&sp->rs_stateid);
7156 7183
7157 7184 resp->stateid = sp->rs_stateid.stateid;
7158 7185
7159 7186 resp->delegation.delegation_type = dsp->rds_dtype;
7160 7187
7161 7188 if (dsp->rds_dtype == OPEN_DELEGATE_READ) {
7162 7189 open_read_delegation4 *rv =
7163 7190 &resp->delegation.open_delegation4_u.read;
7164 7191
7165 7192 rv->stateid = dsp->rds_delegid.stateid;
7166 7193 rv->recall = FALSE; /* no policy in place to set to TRUE */
7167 7194 ace = &rv->permissions;
7168 7195 } else {
7169 7196 open_write_delegation4 *rv =
7170 7197 &resp->delegation.open_delegation4_u.write;
7171 7198
7172 7199 rv->stateid = dsp->rds_delegid.stateid;
7173 7200 rv->recall = FALSE; /* no policy in place to set to TRUE */
7174 7201 ace = &rv->permissions;
7175 7202 rv->space_limit.limitby = NFS_LIMIT_SIZE;
7176 7203 rv->space_limit.nfs_space_limit4_u.filesize = UINT64_MAX;
7177 7204 }
7178 7205
7179 7206 /* XXX For now */
7180 7207 ace->type = ACE4_ACCESS_ALLOWED_ACE_TYPE;
7181 7208 ace->flag = 0;
7182 7209 ace->access_mask = 0;
7183 7210 ace->who.utf8string_len = 0;
7184 7211 ace->who.utf8string_val = 0;
7185 7212
7186 7213 rfs4_deleg_state_rele(dsp);
7187 7214 rfs4_state_rele(sp);
7188 7215 rfs4_file_rele(fp);
7189 7216 }
7190 7217
7191 7218 typedef enum {
7192 7219 NFS4_CHKSEQ_OKAY = 0,
7193 7220 NFS4_CHKSEQ_REPLAY = 1,
7194 7221 NFS4_CHKSEQ_BAD = 2
7195 7222 } rfs4_chkseq_t;
7196 7223
7197 7224 /*
7198 7225 * Generic function for sequence number checks.
7199 7226 */
7200 7227 static rfs4_chkseq_t
7201 7228 rfs4_check_seqid(seqid4 seqid, nfs_resop4 *lastop,
7202 7229 seqid4 rqst_seq, nfs_resop4 *resop, bool_t copyres)
7203 7230 {
7204 7231 /* Same sequence ids and matching operations? */
7205 7232 if (seqid == rqst_seq && resop->resop == lastop->resop) {
7206 7233 if (copyres == TRUE) {
7207 7234 rfs4_free_reply(resop);
7208 7235 rfs4_copy_reply(resop, lastop);
7209 7236 }
7210 7237 NFS4_DEBUG(rfs4_debug, (CE_NOTE,
7211 7238 "Replayed SEQID %d\n", seqid));
7212 7239 return (NFS4_CHKSEQ_REPLAY);
7213 7240 }
7214 7241
7215 7242 /* If the incoming sequence is not the next expected then it is bad */
7216 7243 if (rqst_seq != seqid + 1) {
7217 7244 if (rqst_seq == seqid) {
7218 7245 NFS4_DEBUG(rfs4_debug,
7219 7246 (CE_NOTE, "BAD SEQID: Replayed sequence id "
7220 7247 "but last op was %d current op is %d\n",
7221 7248 lastop->resop, resop->resop));
7222 7249 return (NFS4_CHKSEQ_BAD);
7223 7250 }
7224 7251 NFS4_DEBUG(rfs4_debug,
7225 7252 (CE_NOTE, "BAD SEQID: got %u expecting %u\n",
7226 7253 rqst_seq, seqid));
7227 7254 return (NFS4_CHKSEQ_BAD);
7228 7255 }
7229 7256
7230 7257 /* Everything okay -- next expected */
7231 7258 return (NFS4_CHKSEQ_OKAY);
7232 7259 }
7233 7260
7234 7261
7235 7262 static rfs4_chkseq_t
7236 7263 rfs4_check_open_seqid(seqid4 seqid, rfs4_openowner_t *op, nfs_resop4 *resop)
7237 7264 {
7238 7265 rfs4_chkseq_t rc;
7239 7266
7240 7267 rfs4_dbe_lock(op->ro_dbe);
7241 7268 rc = rfs4_check_seqid(op->ro_open_seqid, &op->ro_reply, seqid, resop,
7242 7269 TRUE);
7243 7270 rfs4_dbe_unlock(op->ro_dbe);
7244 7271
7245 7272 if (rc == NFS4_CHKSEQ_OKAY)
7246 7273 rfs4_update_lease(op->ro_client);
7247 7274
7248 7275 return (rc);
7249 7276 }
7250 7277
7251 7278 static rfs4_chkseq_t
7252 7279 rfs4_check_olo_seqid(seqid4 olo_seqid, rfs4_openowner_t *op, nfs_resop4 *resop)
7253 7280 {
7254 7281 rfs4_chkseq_t rc;
7255 7282
7256 7283 rfs4_dbe_lock(op->ro_dbe);
7257 7284 rc = rfs4_check_seqid(op->ro_open_seqid, &op->ro_reply,
7258 7285 olo_seqid, resop, FALSE);
7259 7286 rfs4_dbe_unlock(op->ro_dbe);
7260 7287
7261 7288 return (rc);
7262 7289 }
7263 7290
7264 7291 static rfs4_chkseq_t
7265 7292 rfs4_check_lock_seqid(seqid4 seqid, rfs4_lo_state_t *lsp, nfs_resop4 *resop)
7266 7293 {
7267 7294 rfs4_chkseq_t rc = NFS4_CHKSEQ_OKAY;
7268 7295
7269 7296 rfs4_dbe_lock(lsp->rls_dbe);
7270 7297 if (!lsp->rls_skip_seqid_check)
7271 7298 rc = rfs4_check_seqid(lsp->rls_seqid, &lsp->rls_reply, seqid,
7272 7299 resop, TRUE);
7273 7300 rfs4_dbe_unlock(lsp->rls_dbe);
7274 7301
7275 7302 return (rc);
7276 7303 }
7277 7304
7278 7305 static void
7279 7306 rfs4_op_open(nfs_argop4 *argop, nfs_resop4 *resop,
7280 7307 struct svc_req *req, struct compound_state *cs)
7281 7308 {
7282 7309 OPEN4args *args = &argop->nfs_argop4_u.opopen;
7283 7310 OPEN4res *resp = &resop->nfs_resop4_u.opopen;
7284 7311 open_owner4 *owner = &args->owner;
7285 7312 open_claim_type4 claim = args->claim;
7286 7313 rfs4_client_t *cp;
7287 7314 rfs4_openowner_t *oo;
7288 7315 bool_t create;
7289 7316 bool_t replay = FALSE;
7290 7317 int can_reclaim;
7291 7318
7292 7319 DTRACE_NFSV4_2(op__open__start, struct compound_state *, cs,
7293 7320 OPEN4args *, args);
7294 7321
7295 7322 if (cs->vp == NULL) {
7296 7323 *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
7297 7324 goto end;
7298 7325 }
7299 7326
7300 7327 /*
7301 7328 * Need to check clientid and lease expiration first based on
7302 7329 * error ordering and incrementing sequence id.
7303 7330 */
7304 7331 cp = rfs4_findclient_by_id(owner->clientid, FALSE);
7305 7332 if (cp == NULL) {
7306 7333 *cs->statusp = resp->status =
7307 7334 rfs4_check_clientid(&owner->clientid, 0);
7308 7335 goto end;
7309 7336 }
7310 7337
7311 7338 if (rfs4_lease_expired(cp)) {
7312 7339 rfs4_client_close(cp);
7313 7340 *cs->statusp = resp->status = NFS4ERR_EXPIRED;
7314 7341 goto end;
7315 7342 }
7316 7343 can_reclaim = cp->rc_can_reclaim;
7317 7344
7318 7345 /*
7319 7346 * Find the open_owner for use from this point forward. Take
7320 7347 * care in updating the sequence id based on the type of error
7321 7348 * being returned.
7322 7349 */
7323 7350 retry:
7324 7351 create = TRUE;
7325 7352 oo = rfs4_findopenowner(owner, &create, args->seqid);
7326 7353 if (oo == NULL) {
7327 7354 *cs->statusp = resp->status = NFS4ERR_RESOURCE;
7328 7355 rfs4_client_rele(cp);
7329 7356 goto end;
7330 7357 }
7331 7358
7332 7359 /* Hold off access to the sequence space while the open is done */
7333 7360 rfs4_sw_enter(&oo->ro_sw);
7334 7361
7335 7362 /*
7336 7363 * If the open_owner existed before at the server, then check
7337 7364 * the sequence id.
7338 7365 */
7339 7366 if (!create && !oo->ro_postpone_confirm) {
7340 7367 switch (rfs4_check_open_seqid(args->seqid, oo, resop)) {
7341 7368 case NFS4_CHKSEQ_BAD:
7342 7369 if ((args->seqid > oo->ro_open_seqid) &&
7343 7370 oo->ro_need_confirm) {
7344 7371 rfs4_free_opens(oo, TRUE, FALSE);
7345 7372 rfs4_sw_exit(&oo->ro_sw);
7346 7373 rfs4_openowner_rele(oo);
7347 7374 goto retry;
7348 7375 }
7349 7376 resp->status = NFS4ERR_BAD_SEQID;
7350 7377 goto out;
7351 7378 case NFS4_CHKSEQ_REPLAY: /* replay of previous request */
7352 7379 replay = TRUE;
7353 7380 goto out;
7354 7381 default:
7355 7382 break;
7356 7383 }
7357 7384
7358 7385 /*
7359 7386 * Sequence was ok and open owner exists
7360 7387 * check to see if we have yet to see an
7361 7388 * open_confirm.
7362 7389 */
7363 7390 if (oo->ro_need_confirm) {
7364 7391 rfs4_free_opens(oo, TRUE, FALSE);
7365 7392 rfs4_sw_exit(&oo->ro_sw);
7366 7393 rfs4_openowner_rele(oo);
7367 7394 goto retry;
7368 7395 }
7369 7396 }
7370 7397 /* Grace only applies to regular-type OPENs */
7371 7398 if (rfs4_clnt_in_grace(cp) &&
7372 7399 (claim == CLAIM_NULL || claim == CLAIM_DELEGATE_CUR)) {
7373 7400 *cs->statusp = resp->status = NFS4ERR_GRACE;
7374 7401 goto out;
7375 7402 }
7376 7403
7377 7404 /*
7378 7405 * If previous state at the server existed then can_reclaim
7379 7406 * will be set. If not reply NFS4ERR_NO_GRACE to the
7380 7407 * client.
7381 7408 */
7382 7409 if (rfs4_clnt_in_grace(cp) && claim == CLAIM_PREVIOUS && !can_reclaim) {
7383 7410 *cs->statusp = resp->status = NFS4ERR_NO_GRACE;
7384 7411 goto out;
7385 7412 }
7386 7413
7387 7414
7388 7415 /*
7389 7416 * Reject the open if the client has missed the grace period
7390 7417 */
7391 7418 if (!rfs4_clnt_in_grace(cp) && claim == CLAIM_PREVIOUS) {
7392 7419 *cs->statusp = resp->status = NFS4ERR_NO_GRACE;
7393 7420 goto out;
7394 7421 }
7395 7422
7396 7423 /* Couple of up-front bookkeeping items */
7397 7424 if (oo->ro_need_confirm) {
7398 7425 /*
7399 7426 * If this is a reclaim OPEN then we should not ask
7400 7427 * for a confirmation of the open_owner per the
7401 7428 * protocol specification.
7402 7429 */
7403 7430 if (claim == CLAIM_PREVIOUS)
7404 7431 oo->ro_need_confirm = FALSE;
7405 7432 else
7406 7433 resp->rflags |= OPEN4_RESULT_CONFIRM;
7407 7434 }
7408 7435 resp->rflags |= OPEN4_RESULT_LOCKTYPE_POSIX;
7409 7436
7410 7437 /*
7411 7438 * If there is an unshared filesystem mounted on this vnode,
7412 7439 * do not allow to open/create in this directory.
7413 7440 */
7414 7441 if (vn_ismntpt(cs->vp)) {
7415 7442 *cs->statusp = resp->status = NFS4ERR_ACCESS;
7416 7443 goto out;
7417 7444 }
7418 7445
7419 7446 /*
7420 7447 * access must READ, WRITE, or BOTH. No access is invalid.
7421 7448 * deny can be READ, WRITE, BOTH, or NONE.
7422 7449 * bits not defined for access/deny are invalid.
7423 7450 */
7424 7451 if (! (args->share_access & OPEN4_SHARE_ACCESS_BOTH) ||
7425 7452 (args->share_access & ~OPEN4_SHARE_ACCESS_BOTH) ||
7426 7453 (args->share_deny & ~OPEN4_SHARE_DENY_BOTH)) {
7427 7454 *cs->statusp = resp->status = NFS4ERR_INVAL;
7428 7455 goto out;
7429 7456 }
7430 7457
7431 7458
7432 7459 /*
7433 7460 * make sure attrset is zero before response is built.
7434 7461 */
7435 7462 resp->attrset = 0;
7436 7463
7437 7464 switch (claim) {
7438 7465 case CLAIM_NULL:
7439 7466 rfs4_do_opennull(cs, req, args, oo, resp);
7440 7467 break;
7441 7468 case CLAIM_PREVIOUS:
7442 7469 rfs4_do_openprev(cs, req, args, oo, resp);
7443 7470 break;
7444 7471 case CLAIM_DELEGATE_CUR:
7445 7472 rfs4_do_opendelcur(cs, req, args, oo, resp);
7446 7473 break;
7447 7474 case CLAIM_DELEGATE_PREV:
7448 7475 rfs4_do_opendelprev(cs, req, args, oo, resp);
7449 7476 break;
7450 7477 default:
7451 7478 resp->status = NFS4ERR_INVAL;
7452 7479 break;
7453 7480 }
7454 7481
7455 7482 out:
7456 7483 rfs4_client_rele(cp);
7457 7484
7458 7485 /* Catch sequence id handling here to make it a little easier */
7459 7486 switch (resp->status) {
7460 7487 case NFS4ERR_BADXDR:
7461 7488 case NFS4ERR_BAD_SEQID:
7462 7489 case NFS4ERR_BAD_STATEID:
7463 7490 case NFS4ERR_NOFILEHANDLE:
7464 7491 case NFS4ERR_RESOURCE:
7465 7492 case NFS4ERR_STALE_CLIENTID:
7466 7493 case NFS4ERR_STALE_STATEID:
7467 7494 /*
7468 7495 * The protocol states that if any of these errors are
7469 7496 * being returned, the sequence id should not be
7470 7497 * incremented. Any other return requires an
7471 7498 * increment.
7472 7499 */
7473 7500 break;
7474 7501 default:
7475 7502 /* Always update the lease in this case */
7476 7503 rfs4_update_lease(oo->ro_client);
7477 7504
7478 7505 /* Regular response - copy the result */
7479 7506 if (!replay)
7480 7507 rfs4_update_open_resp(oo, resop, &cs->fh);
7481 7508
7482 7509 /*
7483 7510 * REPLAY case: Only if the previous response was OK
7484 7511 * do we copy the filehandle. If not OK, no
7485 7512 * filehandle to copy.
7486 7513 */
7487 7514 if (replay == TRUE &&
7488 7515 resp->status == NFS4_OK &&
↓ open down ↓ |
1580 lines elided |
↑ open up ↑ |
7489 7516 oo->ro_reply_fh.nfs_fh4_val) {
7490 7517 /*
7491 7518 * If this is a replay, we must restore the
7492 7519 * current filehandle/vp to that of what was
7493 7520 * returned originally. Try our best to do
7494 7521 * it.
7495 7522 */
7496 7523 nfs_fh4_fmt_t *fh_fmtp =
7497 7524 (nfs_fh4_fmt_t *)oo->ro_reply_fh.nfs_fh4_val;
7498 7525
7499 - cs->exi = checkexport4(&fh_fmtp->fh4_fsid,
7526 + if (cs->exi)
7527 + exi_rele(cs->exi);
7528 + cs->exi = checkexport(&fh_fmtp->fh4_fsid,
7500 7529 (fid_t *)&fh_fmtp->fh4_xlen, NULL);
7501 7530
7502 7531 if (cs->exi == NULL) {
7503 7532 resp->status = NFS4ERR_STALE;
7504 7533 goto finish;
7505 7534 }
7506 7535
7507 7536 VN_RELE(cs->vp);
7508 7537
7509 7538 cs->vp = nfs4_fhtovp(&oo->ro_reply_fh, cs->exi,
7510 7539 &resp->status);
7511 7540
7512 7541 if (cs->vp == NULL)
7513 7542 goto finish;
7514 7543
7515 7544 nfs_fh4_copy(&oo->ro_reply_fh, &cs->fh);
7516 7545 }
7517 7546
7518 7547 /*
7519 7548 * If this was a replay, no need to update the
7520 7549 * sequence id. If the open_owner was not created on
7521 7550 * this pass, then update. The first use of an
7522 7551 * open_owner will not bump the sequence id.
7523 7552 */
7524 7553 if (replay == FALSE && !create)
7525 7554 rfs4_update_open_sequence(oo);
7526 7555 /*
7527 7556 * If the client is receiving an error and the
7528 7557 * open_owner needs to be confirmed, there is no way
7529 7558 * to notify the client of this fact ignoring the fact
7530 7559 * that the server has no method of returning a
7531 7560 * stateid to confirm. Therefore, the server needs to
7532 7561 * mark this open_owner in a way as to avoid the
7533 7562 * sequence id checking the next time the client uses
7534 7563 * this open_owner.
7535 7564 */
7536 7565 if (resp->status != NFS4_OK && oo->ro_need_confirm)
7537 7566 oo->ro_postpone_confirm = TRUE;
7538 7567 /*
7539 7568 * If OK response then clear the postpone flag and
7540 7569 * reset the sequence id to keep in sync with the
7541 7570 * client.
7542 7571 */
7543 7572 if (resp->status == NFS4_OK && oo->ro_postpone_confirm) {
7544 7573 oo->ro_postpone_confirm = FALSE;
7545 7574 oo->ro_open_seqid = args->seqid;
7546 7575 }
7547 7576 break;
7548 7577 }
7549 7578
7550 7579 finish:
7551 7580 *cs->statusp = resp->status;
7552 7581
7553 7582 rfs4_sw_exit(&oo->ro_sw);
7554 7583 rfs4_openowner_rele(oo);
7555 7584
7556 7585 end:
7557 7586 DTRACE_NFSV4_2(op__open__done, struct compound_state *, cs,
7558 7587 OPEN4res *, resp);
7559 7588 }
7560 7589
7561 7590 /*ARGSUSED*/
7562 7591 void
7563 7592 rfs4_op_open_confirm(nfs_argop4 *argop, nfs_resop4 *resop,
7564 7593 struct svc_req *req, struct compound_state *cs)
7565 7594 {
7566 7595 OPEN_CONFIRM4args *args = &argop->nfs_argop4_u.opopen_confirm;
7567 7596 OPEN_CONFIRM4res *resp = &resop->nfs_resop4_u.opopen_confirm;
7568 7597 rfs4_state_t *sp;
7569 7598 nfsstat4 status;
7570 7599
7571 7600 DTRACE_NFSV4_2(op__open__confirm__start, struct compound_state *, cs,
7572 7601 OPEN_CONFIRM4args *, args);
7573 7602
7574 7603 if (cs->vp == NULL) {
7575 7604 *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
7576 7605 goto out;
7577 7606 }
7578 7607
7579 7608 if (cs->vp->v_type != VREG) {
7580 7609 *cs->statusp = resp->status =
7581 7610 cs->vp->v_type == VDIR ? NFS4ERR_ISDIR : NFS4ERR_INVAL;
7582 7611 return;
7583 7612 }
7584 7613
7585 7614 status = rfs4_get_state(&args->open_stateid, &sp, RFS4_DBS_VALID);
7586 7615 if (status != NFS4_OK) {
7587 7616 *cs->statusp = resp->status = status;
7588 7617 goto out;
7589 7618 }
7590 7619
7591 7620 /* Ensure specified filehandle matches */
7592 7621 if (cs->vp != sp->rs_finfo->rf_vp) {
7593 7622 rfs4_state_rele(sp);
7594 7623 *cs->statusp = resp->status = NFS4ERR_BAD_STATEID;
7595 7624 goto out;
7596 7625 }
7597 7626
7598 7627 /* hold off other access to open_owner while we tinker */
7599 7628 rfs4_sw_enter(&sp->rs_owner->ro_sw);
7600 7629
7601 7630 switch (rfs4_check_stateid_seqid(sp, &args->open_stateid)) {
7602 7631 case NFS4_CHECK_STATEID_OKAY:
7603 7632 if (rfs4_check_open_seqid(args->seqid, sp->rs_owner,
7604 7633 resop) != 0) {
7605 7634 *cs->statusp = resp->status = NFS4ERR_BAD_SEQID;
7606 7635 break;
7607 7636 }
7608 7637 /*
7609 7638 * If it is the appropriate stateid and determined to
7610 7639 * be "OKAY" then this means that the stateid does not
7611 7640 * need to be confirmed and the client is in error for
7612 7641 * sending an OPEN_CONFIRM.
7613 7642 */
7614 7643 *cs->statusp = resp->status = NFS4ERR_BAD_STATEID;
7615 7644 break;
7616 7645 case NFS4_CHECK_STATEID_OLD:
7617 7646 *cs->statusp = resp->status = NFS4ERR_OLD_STATEID;
7618 7647 break;
7619 7648 case NFS4_CHECK_STATEID_BAD:
7620 7649 *cs->statusp = resp->status = NFS4ERR_BAD_STATEID;
7621 7650 break;
7622 7651 case NFS4_CHECK_STATEID_EXPIRED:
7623 7652 *cs->statusp = resp->status = NFS4ERR_EXPIRED;
7624 7653 break;
7625 7654 case NFS4_CHECK_STATEID_CLOSED:
7626 7655 *cs->statusp = resp->status = NFS4ERR_OLD_STATEID;
7627 7656 break;
7628 7657 case NFS4_CHECK_STATEID_REPLAY:
7629 7658 switch (rfs4_check_open_seqid(args->seqid, sp->rs_owner,
7630 7659 resop)) {
7631 7660 case NFS4_CHKSEQ_OKAY:
7632 7661 /*
7633 7662 * This is replayed stateid; if seqid matches
7634 7663 * next expected, then client is using wrong seqid.
7635 7664 */
7636 7665 /* fall through */
7637 7666 case NFS4_CHKSEQ_BAD:
7638 7667 *cs->statusp = resp->status = NFS4ERR_BAD_SEQID;
7639 7668 break;
7640 7669 case NFS4_CHKSEQ_REPLAY:
7641 7670 /*
7642 7671 * Note this case is the duplicate case so
7643 7672 * resp->status is already set.
7644 7673 */
7645 7674 *cs->statusp = resp->status;
7646 7675 rfs4_update_lease(sp->rs_owner->ro_client);
7647 7676 break;
7648 7677 }
7649 7678 break;
7650 7679 case NFS4_CHECK_STATEID_UNCONFIRMED:
7651 7680 if (rfs4_check_open_seqid(args->seqid, sp->rs_owner,
7652 7681 resop) != NFS4_CHKSEQ_OKAY) {
7653 7682 *cs->statusp = resp->status = NFS4ERR_BAD_SEQID;
7654 7683 break;
7655 7684 }
7656 7685 *cs->statusp = resp->status = NFS4_OK;
7657 7686
7658 7687 next_stateid(&sp->rs_stateid);
7659 7688 resp->open_stateid = sp->rs_stateid.stateid;
7660 7689 sp->rs_owner->ro_need_confirm = FALSE;
7661 7690 rfs4_update_lease(sp->rs_owner->ro_client);
7662 7691 rfs4_update_open_sequence(sp->rs_owner);
7663 7692 rfs4_update_open_resp(sp->rs_owner, resop, NULL);
7664 7693 break;
7665 7694 default:
7666 7695 ASSERT(FALSE);
7667 7696 *cs->statusp = resp->status = NFS4ERR_SERVERFAULT;
7668 7697 break;
7669 7698 }
7670 7699 rfs4_sw_exit(&sp->rs_owner->ro_sw);
7671 7700 rfs4_state_rele(sp);
7672 7701
7673 7702 out:
7674 7703 DTRACE_NFSV4_2(op__open__confirm__done, struct compound_state *, cs,
7675 7704 OPEN_CONFIRM4res *, resp);
7676 7705 }
7677 7706
7678 7707 /*ARGSUSED*/
7679 7708 void
7680 7709 rfs4_op_open_downgrade(nfs_argop4 *argop, nfs_resop4 *resop,
7681 7710 struct svc_req *req, struct compound_state *cs)
7682 7711 {
7683 7712 OPEN_DOWNGRADE4args *args = &argop->nfs_argop4_u.opopen_downgrade;
7684 7713 OPEN_DOWNGRADE4res *resp = &resop->nfs_resop4_u.opopen_downgrade;
7685 7714 uint32_t access = args->share_access;
7686 7715 uint32_t deny = args->share_deny;
7687 7716 nfsstat4 status;
7688 7717 rfs4_state_t *sp;
7689 7718 rfs4_file_t *fp;
7690 7719 int fflags = 0;
7691 7720
7692 7721 DTRACE_NFSV4_2(op__open__downgrade__start, struct compound_state *, cs,
7693 7722 OPEN_DOWNGRADE4args *, args);
7694 7723
7695 7724 if (cs->vp == NULL) {
7696 7725 *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
7697 7726 goto out;
7698 7727 }
7699 7728
7700 7729 if (cs->vp->v_type != VREG) {
7701 7730 *cs->statusp = resp->status = NFS4ERR_INVAL;
7702 7731 return;
7703 7732 }
7704 7733
7705 7734 status = rfs4_get_state(&args->open_stateid, &sp, RFS4_DBS_VALID);
7706 7735 if (status != NFS4_OK) {
7707 7736 *cs->statusp = resp->status = status;
7708 7737 goto out;
7709 7738 }
7710 7739
7711 7740 /* Ensure specified filehandle matches */
7712 7741 if (cs->vp != sp->rs_finfo->rf_vp) {
7713 7742 rfs4_state_rele(sp);
7714 7743 *cs->statusp = resp->status = NFS4ERR_BAD_STATEID;
7715 7744 goto out;
7716 7745 }
7717 7746
7718 7747 /* hold off other access to open_owner while we tinker */
7719 7748 rfs4_sw_enter(&sp->rs_owner->ro_sw);
7720 7749
7721 7750 switch (rfs4_check_stateid_seqid(sp, &args->open_stateid)) {
7722 7751 case NFS4_CHECK_STATEID_OKAY:
7723 7752 if (rfs4_check_open_seqid(args->seqid, sp->rs_owner,
7724 7753 resop) != NFS4_CHKSEQ_OKAY) {
7725 7754 *cs->statusp = resp->status = NFS4ERR_BAD_SEQID;
7726 7755 goto end;
7727 7756 }
7728 7757 break;
7729 7758 case NFS4_CHECK_STATEID_OLD:
7730 7759 *cs->statusp = resp->status = NFS4ERR_OLD_STATEID;
7731 7760 goto end;
7732 7761 case NFS4_CHECK_STATEID_BAD:
7733 7762 *cs->statusp = resp->status = NFS4ERR_BAD_STATEID;
7734 7763 goto end;
7735 7764 case NFS4_CHECK_STATEID_EXPIRED:
7736 7765 *cs->statusp = resp->status = NFS4ERR_EXPIRED;
7737 7766 goto end;
7738 7767 case NFS4_CHECK_STATEID_CLOSED:
7739 7768 *cs->statusp = resp->status = NFS4ERR_OLD_STATEID;
7740 7769 goto end;
7741 7770 case NFS4_CHECK_STATEID_UNCONFIRMED:
7742 7771 *cs->statusp = resp->status = NFS4ERR_BAD_STATEID;
7743 7772 goto end;
7744 7773 case NFS4_CHECK_STATEID_REPLAY:
7745 7774 /* Check the sequence id for the open owner */
7746 7775 switch (rfs4_check_open_seqid(args->seqid, sp->rs_owner,
7747 7776 resop)) {
7748 7777 case NFS4_CHKSEQ_OKAY:
7749 7778 /*
7750 7779 * This is replayed stateid; if seqid matches
7751 7780 * next expected, then client is using wrong seqid.
7752 7781 */
7753 7782 /* fall through */
7754 7783 case NFS4_CHKSEQ_BAD:
7755 7784 *cs->statusp = resp->status = NFS4ERR_BAD_SEQID;
7756 7785 goto end;
7757 7786 case NFS4_CHKSEQ_REPLAY:
7758 7787 /*
7759 7788 * Note this case is the duplicate case so
7760 7789 * resp->status is already set.
7761 7790 */
7762 7791 *cs->statusp = resp->status;
7763 7792 rfs4_update_lease(sp->rs_owner->ro_client);
7764 7793 goto end;
7765 7794 }
7766 7795 break;
7767 7796 default:
7768 7797 ASSERT(FALSE);
7769 7798 break;
7770 7799 }
7771 7800
7772 7801 rfs4_dbe_lock(sp->rs_dbe);
7773 7802 /*
7774 7803 * Check that the new access modes and deny modes are valid.
7775 7804 * Check that no invalid bits are set.
7776 7805 */
7777 7806 if ((access & ~(OPEN4_SHARE_ACCESS_READ | OPEN4_SHARE_ACCESS_WRITE)) ||
7778 7807 (deny & ~(OPEN4_SHARE_DENY_READ | OPEN4_SHARE_DENY_WRITE))) {
7779 7808 *cs->statusp = resp->status = NFS4ERR_INVAL;
7780 7809 rfs4_update_open_sequence(sp->rs_owner);
7781 7810 rfs4_dbe_unlock(sp->rs_dbe);
7782 7811 goto end;
7783 7812 }
7784 7813
7785 7814 /*
7786 7815 * The new modes must be a subset of the current modes and
7787 7816 * the access must specify at least one mode. To test that
7788 7817 * the new mode is a subset of the current modes we bitwise
7789 7818 * AND them together and check that the result equals the new
7790 7819 * mode. For example:
7791 7820 * New mode, access == R and current mode, sp->rs_open_access == RW
7792 7821 * access & sp->rs_open_access == R == access, so the new access mode
7793 7822 * is valid. Consider access == RW, sp->rs_open_access = R
7794 7823 * access & sp->rs_open_access == R != access, so the new access mode
7795 7824 * is invalid.
7796 7825 */
7797 7826 if ((access & sp->rs_open_access) != access ||
7798 7827 (deny & sp->rs_open_deny) != deny ||
7799 7828 (access &
7800 7829 (OPEN4_SHARE_ACCESS_READ | OPEN4_SHARE_ACCESS_WRITE)) == 0) {
7801 7830 *cs->statusp = resp->status = NFS4ERR_INVAL;
7802 7831 rfs4_update_open_sequence(sp->rs_owner);
7803 7832 rfs4_dbe_unlock(sp->rs_dbe);
7804 7833 goto end;
7805 7834 }
7806 7835
7807 7836 /*
7808 7837 * Release any share locks associated with this stateID.
7809 7838 * Strictly speaking, this violates the spec because the
7810 7839 * spec effectively requires that open downgrade be atomic.
7811 7840 * At present, fs_shrlock does not have this capability.
7812 7841 */
7813 7842 (void) rfs4_unshare(sp);
7814 7843
7815 7844 status = rfs4_share(sp, access, deny);
7816 7845 if (status != NFS4_OK) {
7817 7846 *cs->statusp = resp->status = NFS4ERR_SERVERFAULT;
7818 7847 rfs4_update_open_sequence(sp->rs_owner);
7819 7848 rfs4_dbe_unlock(sp->rs_dbe);
7820 7849 goto end;
7821 7850 }
7822 7851
7823 7852 fp = sp->rs_finfo;
7824 7853 rfs4_dbe_lock(fp->rf_dbe);
7825 7854
7826 7855 /*
7827 7856 * If the current mode has deny read and the new mode
7828 7857 * does not, decrement the number of deny read mode bits
7829 7858 * and if it goes to zero turn off the deny read bit
7830 7859 * on the file.
7831 7860 */
7832 7861 if ((sp->rs_open_deny & OPEN4_SHARE_DENY_READ) &&
7833 7862 (deny & OPEN4_SHARE_DENY_READ) == 0) {
7834 7863 fp->rf_deny_read--;
7835 7864 if (fp->rf_deny_read == 0)
7836 7865 fp->rf_share_deny &= ~OPEN4_SHARE_DENY_READ;
7837 7866 }
7838 7867
7839 7868 /*
7840 7869 * If the current mode has deny write and the new mode
7841 7870 * does not, decrement the number of deny write mode bits
7842 7871 * and if it goes to zero turn off the deny write bit
7843 7872 * on the file.
7844 7873 */
7845 7874 if ((sp->rs_open_deny & OPEN4_SHARE_DENY_WRITE) &&
7846 7875 (deny & OPEN4_SHARE_DENY_WRITE) == 0) {
7847 7876 fp->rf_deny_write--;
7848 7877 if (fp->rf_deny_write == 0)
7849 7878 fp->rf_share_deny &= ~OPEN4_SHARE_DENY_WRITE;
7850 7879 }
7851 7880
7852 7881 /*
7853 7882 * If the current mode has access read and the new mode
7854 7883 * does not, decrement the number of access read mode bits
7855 7884 * and if it goes to zero turn off the access read bit
7856 7885 * on the file. set fflags to FREAD for the call to
7857 7886 * vn_open_downgrade().
7858 7887 */
7859 7888 if ((sp->rs_open_access & OPEN4_SHARE_ACCESS_READ) &&
7860 7889 (access & OPEN4_SHARE_ACCESS_READ) == 0) {
7861 7890 fp->rf_access_read--;
7862 7891 if (fp->rf_access_read == 0)
7863 7892 fp->rf_share_access &= ~OPEN4_SHARE_ACCESS_READ;
7864 7893 fflags |= FREAD;
7865 7894 }
7866 7895
7867 7896 /*
7868 7897 * If the current mode has access write and the new mode
7869 7898 * does not, decrement the number of access write mode bits
7870 7899 * and if it goes to zero turn off the access write bit
7871 7900 * on the file. set fflags to FWRITE for the call to
7872 7901 * vn_open_downgrade().
7873 7902 */
7874 7903 if ((sp->rs_open_access & OPEN4_SHARE_ACCESS_WRITE) &&
7875 7904 (access & OPEN4_SHARE_ACCESS_WRITE) == 0) {
7876 7905 fp->rf_access_write--;
7877 7906 if (fp->rf_access_write == 0)
7878 7907 fp->rf_share_deny &= ~OPEN4_SHARE_ACCESS_WRITE;
7879 7908 fflags |= FWRITE;
7880 7909 }
7881 7910
7882 7911 /* Check that the file is still accessible */
7883 7912 ASSERT(fp->rf_share_access);
7884 7913
7885 7914 rfs4_dbe_unlock(fp->rf_dbe);
7886 7915
7887 7916 /* now set the new open access and deny modes */
7888 7917 sp->rs_open_access = access;
7889 7918 sp->rs_open_deny = deny;
7890 7919
7891 7920 /*
7892 7921 * we successfully downgraded the share lock, now we need to downgrade
7893 7922 * the open. it is possible that the downgrade was only for a deny
7894 7923 * mode and we have nothing else to do.
7895 7924 */
7896 7925 if ((fflags & (FREAD|FWRITE)) != 0)
7897 7926 vn_open_downgrade(cs->vp, fflags);
7898 7927
7899 7928 /* Update the stateid */
7900 7929 next_stateid(&sp->rs_stateid);
7901 7930 resp->open_stateid = sp->rs_stateid.stateid;
7902 7931
7903 7932 rfs4_dbe_unlock(sp->rs_dbe);
7904 7933
7905 7934 *cs->statusp = resp->status = NFS4_OK;
7906 7935 /* Update the lease */
7907 7936 rfs4_update_lease(sp->rs_owner->ro_client);
7908 7937 /* And the sequence */
7909 7938 rfs4_update_open_sequence(sp->rs_owner);
7910 7939 rfs4_update_open_resp(sp->rs_owner, resop, NULL);
7911 7940
7912 7941 end:
7913 7942 rfs4_sw_exit(&sp->rs_owner->ro_sw);
7914 7943 rfs4_state_rele(sp);
7915 7944 out:
7916 7945 DTRACE_NFSV4_2(op__open__downgrade__done, struct compound_state *, cs,
7917 7946 OPEN_DOWNGRADE4res *, resp);
7918 7947 }
7919 7948
7920 7949 static void *
7921 7950 memstr(const void *s1, const char *s2, size_t n)
7922 7951 {
7923 7952 size_t l = strlen(s2);
7924 7953 char *p = (char *)s1;
7925 7954
7926 7955 while (n >= l) {
7927 7956 if (bcmp(p, s2, l) == 0)
7928 7957 return (p);
7929 7958 p++;
7930 7959 n--;
7931 7960 }
7932 7961
7933 7962 return (NULL);
7934 7963 }
7935 7964
7936 7965 /*
7937 7966 * The logic behind this function is detailed in the NFSv4 RFC in the
7938 7967 * SETCLIENTID operation description under IMPLEMENTATION. Refer to
7939 7968 * that section for explicit guidance to server behavior for
7940 7969 * SETCLIENTID.
7941 7970 */
7942 7971 void
7943 7972 rfs4_op_setclientid(nfs_argop4 *argop, nfs_resop4 *resop,
7944 7973 struct svc_req *req, struct compound_state *cs)
7945 7974 {
7946 7975 SETCLIENTID4args *args = &argop->nfs_argop4_u.opsetclientid;
7947 7976 SETCLIENTID4res *res = &resop->nfs_resop4_u.opsetclientid;
7948 7977 rfs4_client_t *cp, *newcp, *cp_confirmed, *cp_unconfirmed;
7949 7978 rfs4_clntip_t *ci;
7950 7979 bool_t create;
7951 7980 char *addr, *netid;
7952 7981 int len;
7953 7982
7954 7983 DTRACE_NFSV4_2(op__setclientid__start, struct compound_state *, cs,
7955 7984 SETCLIENTID4args *, args);
7956 7985 retry:
7957 7986 newcp = cp_confirmed = cp_unconfirmed = NULL;
7958 7987
7959 7988 /*
7960 7989 * Save the caller's IP address
7961 7990 */
7962 7991 args->client.cl_addr =
7963 7992 (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
7964 7993
7965 7994 /*
7966 7995 * Record if it is a Solaris client that cannot handle referrals.
7967 7996 */
7968 7997 if (memstr(args->client.id_val, "Solaris", args->client.id_len) &&
7969 7998 !memstr(args->client.id_val, "+referrals", args->client.id_len)) {
7970 7999 /* Add a "yes, it's downrev" record */
7971 8000 create = TRUE;
7972 8001 ci = rfs4_find_clntip(args->client.cl_addr, &create);
7973 8002 ASSERT(ci != NULL);
7974 8003 rfs4_dbe_rele(ci->ri_dbe);
7975 8004 } else {
7976 8005 /* Remove any previous record */
7977 8006 rfs4_invalidate_clntip(args->client.cl_addr);
7978 8007 }
7979 8008
7980 8009 /*
7981 8010 * In search of an EXISTING client matching the incoming
7982 8011 * request to establish a new client identifier at the server
7983 8012 */
7984 8013 create = TRUE;
7985 8014 cp = rfs4_findclient(&args->client, &create, NULL);
7986 8015
7987 8016 /* Should never happen */
7988 8017 ASSERT(cp != NULL);
7989 8018
7990 8019 if (cp == NULL) {
7991 8020 *cs->statusp = res->status = NFS4ERR_SERVERFAULT;
7992 8021 goto out;
7993 8022 }
7994 8023
7995 8024 /*
7996 8025 * Easiest case. Client identifier is newly created and is
7997 8026 * unconfirmed. Also note that for this case, no other
7998 8027 * entries exist for the client identifier. Nothing else to
7999 8028 * check. Just setup the response and respond.
8000 8029 */
8001 8030 if (create) {
8002 8031 *cs->statusp = res->status = NFS4_OK;
8003 8032 res->SETCLIENTID4res_u.resok4.clientid = cp->rc_clientid;
8004 8033 res->SETCLIENTID4res_u.resok4.setclientid_confirm =
8005 8034 cp->rc_confirm_verf;
8006 8035 /* Setup callback information; CB_NULL confirmation later */
8007 8036 rfs4_client_setcb(cp, &args->callback, args->callback_ident);
8008 8037
8009 8038 rfs4_client_rele(cp);
8010 8039 goto out;
8011 8040 }
8012 8041
8013 8042 /*
8014 8043 * An existing, confirmed client may exist but it may not have
8015 8044 * been active for at least one lease period. If so, then
8016 8045 * "close" the client and create a new client identifier
8017 8046 */
8018 8047 if (rfs4_lease_expired(cp)) {
8019 8048 rfs4_client_close(cp);
8020 8049 goto retry;
8021 8050 }
8022 8051
8023 8052 if (cp->rc_need_confirm == TRUE)
8024 8053 cp_unconfirmed = cp;
8025 8054 else
8026 8055 cp_confirmed = cp;
8027 8056
8028 8057 cp = NULL;
8029 8058
8030 8059 /*
8031 8060 * We have a confirmed client, now check for an
8032 8061 * unconfimred entry
8033 8062 */
8034 8063 if (cp_confirmed) {
8035 8064 /* If creds don't match then client identifier is inuse */
8036 8065 if (!creds_ok(cp_confirmed->rc_cr_set, req, cs)) {
8037 8066 rfs4_cbinfo_t *cbp;
8038 8067 /*
8039 8068 * Some one else has established this client
8040 8069 * id. Try and say * who they are. We will use
8041 8070 * the call back address supplied by * the
8042 8071 * first client.
8043 8072 */
8044 8073 *cs->statusp = res->status = NFS4ERR_CLID_INUSE;
8045 8074
8046 8075 addr = netid = NULL;
8047 8076
8048 8077 cbp = &cp_confirmed->rc_cbinfo;
8049 8078 if (cbp->cb_callback.cb_location.r_addr &&
8050 8079 cbp->cb_callback.cb_location.r_netid) {
8051 8080 cb_client4 *cbcp = &cbp->cb_callback;
8052 8081
8053 8082 len = strlen(cbcp->cb_location.r_addr)+1;
8054 8083 addr = kmem_alloc(len, KM_SLEEP);
8055 8084 bcopy(cbcp->cb_location.r_addr, addr, len);
8056 8085 len = strlen(cbcp->cb_location.r_netid)+1;
8057 8086 netid = kmem_alloc(len, KM_SLEEP);
8058 8087 bcopy(cbcp->cb_location.r_netid, netid, len);
8059 8088 }
8060 8089
8061 8090 res->SETCLIENTID4res_u.client_using.r_addr = addr;
8062 8091 res->SETCLIENTID4res_u.client_using.r_netid = netid;
8063 8092
8064 8093 rfs4_client_rele(cp_confirmed);
8065 8094 }
8066 8095
8067 8096 /*
8068 8097 * Confirmed, creds match, and verifier matches; must
8069 8098 * be an update of the callback info
8070 8099 */
8071 8100 if (cp_confirmed->rc_nfs_client.verifier ==
8072 8101 args->client.verifier) {
8073 8102 /* Setup callback information */
8074 8103 rfs4_client_setcb(cp_confirmed, &args->callback,
8075 8104 args->callback_ident);
8076 8105
8077 8106 /* everything okay -- move ahead */
8078 8107 *cs->statusp = res->status = NFS4_OK;
8079 8108 res->SETCLIENTID4res_u.resok4.clientid =
8080 8109 cp_confirmed->rc_clientid;
8081 8110
8082 8111 /* update the confirm_verifier and return it */
8083 8112 rfs4_client_scv_next(cp_confirmed);
8084 8113 res->SETCLIENTID4res_u.resok4.setclientid_confirm =
8085 8114 cp_confirmed->rc_confirm_verf;
8086 8115
8087 8116 rfs4_client_rele(cp_confirmed);
8088 8117 goto out;
8089 8118 }
8090 8119
8091 8120 /*
8092 8121 * Creds match but the verifier doesn't. Must search
8093 8122 * for an unconfirmed client that would be replaced by
8094 8123 * this request.
8095 8124 */
8096 8125 create = FALSE;
8097 8126 cp_unconfirmed = rfs4_findclient(&args->client, &create,
8098 8127 cp_confirmed);
8099 8128 }
8100 8129
8101 8130 /*
8102 8131 * At this point, we have taken care of the brand new client
8103 8132 * struct, INUSE case, update of an existing, and confirmed
8104 8133 * client struct.
8105 8134 */
8106 8135
8107 8136 /*
8108 8137 * check to see if things have changed while we originally
8109 8138 * picked up the client struct. If they have, then return and
8110 8139 * retry the processing of this SETCLIENTID request.
8111 8140 */
8112 8141 if (cp_unconfirmed) {
8113 8142 rfs4_dbe_lock(cp_unconfirmed->rc_dbe);
8114 8143 if (!cp_unconfirmed->rc_need_confirm) {
8115 8144 rfs4_dbe_unlock(cp_unconfirmed->rc_dbe);
8116 8145 rfs4_client_rele(cp_unconfirmed);
8117 8146 if (cp_confirmed)
8118 8147 rfs4_client_rele(cp_confirmed);
8119 8148 goto retry;
8120 8149 }
8121 8150 /* do away with the old unconfirmed one */
8122 8151 rfs4_dbe_invalidate(cp_unconfirmed->rc_dbe);
8123 8152 rfs4_dbe_unlock(cp_unconfirmed->rc_dbe);
8124 8153 rfs4_client_rele(cp_unconfirmed);
8125 8154 cp_unconfirmed = NULL;
8126 8155 }
8127 8156
8128 8157 /*
8129 8158 * This search will temporarily hide the confirmed client
8130 8159 * struct while a new client struct is created as the
8131 8160 * unconfirmed one.
8132 8161 */
8133 8162 create = TRUE;
8134 8163 newcp = rfs4_findclient(&args->client, &create, cp_confirmed);
8135 8164
8136 8165 ASSERT(newcp != NULL);
8137 8166
8138 8167 if (newcp == NULL) {
8139 8168 *cs->statusp = res->status = NFS4ERR_SERVERFAULT;
8140 8169 rfs4_client_rele(cp_confirmed);
8141 8170 goto out;
8142 8171 }
8143 8172
8144 8173 /*
8145 8174 * If one was not created, then a similar request must be in
8146 8175 * process so release and start over with this one
8147 8176 */
8148 8177 if (create != TRUE) {
8149 8178 rfs4_client_rele(newcp);
8150 8179 if (cp_confirmed)
8151 8180 rfs4_client_rele(cp_confirmed);
8152 8181 goto retry;
8153 8182 }
8154 8183
8155 8184 *cs->statusp = res->status = NFS4_OK;
8156 8185 res->SETCLIENTID4res_u.resok4.clientid = newcp->rc_clientid;
8157 8186 res->SETCLIENTID4res_u.resok4.setclientid_confirm =
8158 8187 newcp->rc_confirm_verf;
8159 8188 /* Setup callback information; CB_NULL confirmation later */
8160 8189 rfs4_client_setcb(newcp, &args->callback, args->callback_ident);
8161 8190
8162 8191 newcp->rc_cp_confirmed = cp_confirmed;
8163 8192
8164 8193 rfs4_client_rele(newcp);
8165 8194
8166 8195 out:
8167 8196 DTRACE_NFSV4_2(op__setclientid__done, struct compound_state *, cs,
8168 8197 SETCLIENTID4res *, res);
8169 8198 }
8170 8199
8171 8200 /*ARGSUSED*/
8172 8201 void
8173 8202 rfs4_op_setclientid_confirm(nfs_argop4 *argop, nfs_resop4 *resop,
8174 8203 struct svc_req *req, struct compound_state *cs)
8175 8204 {
8176 8205 SETCLIENTID_CONFIRM4args *args =
8177 8206 &argop->nfs_argop4_u.opsetclientid_confirm;
8178 8207 SETCLIENTID_CONFIRM4res *res =
8179 8208 &resop->nfs_resop4_u.opsetclientid_confirm;
8180 8209 rfs4_client_t *cp, *cptoclose = NULL;
8181 8210
8182 8211 DTRACE_NFSV4_2(op__setclientid__confirm__start,
8183 8212 struct compound_state *, cs,
8184 8213 SETCLIENTID_CONFIRM4args *, args);
8185 8214
8186 8215 *cs->statusp = res->status = NFS4_OK;
8187 8216
8188 8217 cp = rfs4_findclient_by_id(args->clientid, TRUE);
8189 8218
8190 8219 if (cp == NULL) {
8191 8220 *cs->statusp = res->status =
8192 8221 rfs4_check_clientid(&args->clientid, 1);
8193 8222 goto out;
8194 8223 }
8195 8224
8196 8225 if (!creds_ok(cp, req, cs)) {
8197 8226 *cs->statusp = res->status = NFS4ERR_CLID_INUSE;
8198 8227 rfs4_client_rele(cp);
8199 8228 goto out;
8200 8229 }
8201 8230
8202 8231 /* If the verifier doesn't match, the record doesn't match */
8203 8232 if (cp->rc_confirm_verf != args->setclientid_confirm) {
8204 8233 *cs->statusp = res->status = NFS4ERR_STALE_CLIENTID;
8205 8234 rfs4_client_rele(cp);
8206 8235 goto out;
8207 8236 }
8208 8237
8209 8238 rfs4_dbe_lock(cp->rc_dbe);
8210 8239 cp->rc_need_confirm = FALSE;
8211 8240 if (cp->rc_cp_confirmed) {
8212 8241 cptoclose = cp->rc_cp_confirmed;
8213 8242 cptoclose->rc_ss_remove = 1;
8214 8243 cp->rc_cp_confirmed = NULL;
8215 8244 }
8216 8245
8217 8246 /*
8218 8247 * Update the client's associated server instance, if it's changed
8219 8248 * since the client was created.
8220 8249 */
8221 8250 if (rfs4_servinst(cp) != rfs4_cur_servinst)
8222 8251 rfs4_servinst_assign(cp, rfs4_cur_servinst);
8223 8252
8224 8253 /*
8225 8254 * Record clientid in stable storage.
8226 8255 * Must be done after server instance has been assigned.
8227 8256 */
8228 8257 rfs4_ss_clid(cp);
8229 8258
8230 8259 rfs4_dbe_unlock(cp->rc_dbe);
8231 8260
8232 8261 if (cptoclose)
8233 8262 /* don't need to rele, client_close does it */
8234 8263 rfs4_client_close(cptoclose);
8235 8264
8236 8265 /* If needed, initiate CB_NULL call for callback path */
8237 8266 rfs4_deleg_cb_check(cp);
8238 8267 rfs4_update_lease(cp);
8239 8268
8240 8269 /*
8241 8270 * Check to see if client can perform reclaims
8242 8271 */
8243 8272 rfs4_ss_chkclid(cp);
8244 8273
8245 8274 rfs4_client_rele(cp);
8246 8275
8247 8276 out:
8248 8277 DTRACE_NFSV4_2(op__setclientid__confirm__done,
8249 8278 struct compound_state *, cs,
8250 8279 SETCLIENTID_CONFIRM4 *, res);
8251 8280 }
8252 8281
8253 8282
8254 8283 /*ARGSUSED*/
8255 8284 void
8256 8285 rfs4_op_close(nfs_argop4 *argop, nfs_resop4 *resop,
8257 8286 struct svc_req *req, struct compound_state *cs)
8258 8287 {
8259 8288 CLOSE4args *args = &argop->nfs_argop4_u.opclose;
8260 8289 CLOSE4res *resp = &resop->nfs_resop4_u.opclose;
8261 8290 rfs4_state_t *sp;
8262 8291 nfsstat4 status;
8263 8292
8264 8293 DTRACE_NFSV4_2(op__close__start, struct compound_state *, cs,
8265 8294 CLOSE4args *, args);
8266 8295
8267 8296 if (cs->vp == NULL) {
8268 8297 *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
8269 8298 goto out;
8270 8299 }
8271 8300
8272 8301 status = rfs4_get_state(&args->open_stateid, &sp, RFS4_DBS_INVALID);
8273 8302 if (status != NFS4_OK) {
8274 8303 *cs->statusp = resp->status = status;
8275 8304 goto out;
8276 8305 }
8277 8306
8278 8307 /* Ensure specified filehandle matches */
8279 8308 if (cs->vp != sp->rs_finfo->rf_vp) {
8280 8309 rfs4_state_rele(sp);
8281 8310 *cs->statusp = resp->status = NFS4ERR_BAD_STATEID;
8282 8311 goto out;
8283 8312 }
8284 8313
8285 8314 /* hold off other access to open_owner while we tinker */
8286 8315 rfs4_sw_enter(&sp->rs_owner->ro_sw);
8287 8316
8288 8317 switch (rfs4_check_stateid_seqid(sp, &args->open_stateid)) {
8289 8318 case NFS4_CHECK_STATEID_OKAY:
8290 8319 if (rfs4_check_open_seqid(args->seqid, sp->rs_owner,
8291 8320 resop) != NFS4_CHKSEQ_OKAY) {
8292 8321 *cs->statusp = resp->status = NFS4ERR_BAD_SEQID;
8293 8322 goto end;
8294 8323 }
8295 8324 break;
8296 8325 case NFS4_CHECK_STATEID_OLD:
8297 8326 *cs->statusp = resp->status = NFS4ERR_OLD_STATEID;
8298 8327 goto end;
8299 8328 case NFS4_CHECK_STATEID_BAD:
8300 8329 *cs->statusp = resp->status = NFS4ERR_BAD_STATEID;
8301 8330 goto end;
8302 8331 case NFS4_CHECK_STATEID_EXPIRED:
8303 8332 *cs->statusp = resp->status = NFS4ERR_EXPIRED;
8304 8333 goto end;
8305 8334 case NFS4_CHECK_STATEID_CLOSED:
8306 8335 *cs->statusp = resp->status = NFS4ERR_OLD_STATEID;
8307 8336 goto end;
8308 8337 case NFS4_CHECK_STATEID_UNCONFIRMED:
8309 8338 *cs->statusp = resp->status = NFS4ERR_BAD_STATEID;
8310 8339 goto end;
8311 8340 case NFS4_CHECK_STATEID_REPLAY:
8312 8341 /* Check the sequence id for the open owner */
8313 8342 switch (rfs4_check_open_seqid(args->seqid, sp->rs_owner,
8314 8343 resop)) {
8315 8344 case NFS4_CHKSEQ_OKAY:
8316 8345 /*
8317 8346 * This is replayed stateid; if seqid matches
8318 8347 * next expected, then client is using wrong seqid.
8319 8348 */
8320 8349 /* FALL THROUGH */
8321 8350 case NFS4_CHKSEQ_BAD:
8322 8351 *cs->statusp = resp->status = NFS4ERR_BAD_SEQID;
8323 8352 goto end;
8324 8353 case NFS4_CHKSEQ_REPLAY:
8325 8354 /*
8326 8355 * Note this case is the duplicate case so
8327 8356 * resp->status is already set.
8328 8357 */
8329 8358 *cs->statusp = resp->status;
8330 8359 rfs4_update_lease(sp->rs_owner->ro_client);
8331 8360 goto end;
8332 8361 }
8333 8362 break;
8334 8363 default:
8335 8364 ASSERT(FALSE);
8336 8365 break;
8337 8366 }
8338 8367
8339 8368 rfs4_dbe_lock(sp->rs_dbe);
8340 8369
8341 8370 /* Update the stateid. */
8342 8371 next_stateid(&sp->rs_stateid);
8343 8372 resp->open_stateid = sp->rs_stateid.stateid;
8344 8373
8345 8374 rfs4_dbe_unlock(sp->rs_dbe);
8346 8375
8347 8376 rfs4_update_lease(sp->rs_owner->ro_client);
8348 8377 rfs4_update_open_sequence(sp->rs_owner);
8349 8378 rfs4_update_open_resp(sp->rs_owner, resop, NULL);
8350 8379
8351 8380 rfs4_state_close(sp, FALSE, FALSE, cs->cr);
8352 8381
8353 8382 *cs->statusp = resp->status = status;
8354 8383
8355 8384 end:
8356 8385 rfs4_sw_exit(&sp->rs_owner->ro_sw);
8357 8386 rfs4_state_rele(sp);
8358 8387 out:
8359 8388 DTRACE_NFSV4_2(op__close__done, struct compound_state *, cs,
8360 8389 CLOSE4res *, resp);
8361 8390 }
8362 8391
8363 8392 /*
8364 8393 * Manage the counts on the file struct and close all file locks
8365 8394 */
8366 8395 /*ARGSUSED*/
8367 8396 void
8368 8397 rfs4_release_share_lock_state(rfs4_state_t *sp, cred_t *cr,
8369 8398 bool_t close_of_client)
8370 8399 {
8371 8400 rfs4_file_t *fp = sp->rs_finfo;
8372 8401 rfs4_lo_state_t *lsp;
8373 8402 int fflags = 0;
8374 8403
8375 8404 /*
8376 8405 * If this call is part of the larger closing down of client
8377 8406 * state then it is just easier to release all locks
8378 8407 * associated with this client instead of going through each
8379 8408 * individual file and cleaning locks there.
8380 8409 */
8381 8410 if (close_of_client) {
8382 8411 if (sp->rs_owner->ro_client->rc_unlksys_completed == FALSE &&
8383 8412 !list_is_empty(&sp->rs_lostatelist) &&
8384 8413 sp->rs_owner->ro_client->rc_sysidt != LM_NOSYSID) {
8385 8414 /* Is the PxFS kernel module loaded? */
8386 8415 if (lm_remove_file_locks != NULL) {
8387 8416 int new_sysid;
8388 8417
8389 8418 /* Encode the cluster nodeid in new sysid */
8390 8419 new_sysid = sp->rs_owner->ro_client->rc_sysidt;
8391 8420 lm_set_nlmid_flk(&new_sysid);
8392 8421
8393 8422 /*
8394 8423 * This PxFS routine removes file locks for a
8395 8424 * client over all nodes of a cluster.
8396 8425 */
8397 8426 NFS4_DEBUG(rfs4_debug, (CE_NOTE,
8398 8427 "lm_remove_file_locks(sysid=0x%x)\n",
8399 8428 new_sysid));
8400 8429 (*lm_remove_file_locks)(new_sysid);
8401 8430 } else {
8402 8431 struct flock64 flk;
8403 8432
8404 8433 /* Release all locks for this client */
8405 8434 flk.l_type = F_UNLKSYS;
8406 8435 flk.l_whence = 0;
8407 8436 flk.l_start = 0;
8408 8437 flk.l_len = 0;
8409 8438 flk.l_sysid =
8410 8439 sp->rs_owner->ro_client->rc_sysidt;
8411 8440 flk.l_pid = 0;
8412 8441 (void) VOP_FRLOCK(sp->rs_finfo->rf_vp, F_SETLK,
8413 8442 &flk, F_REMOTELOCK | FREAD | FWRITE,
8414 8443 (u_offset_t)0, NULL, CRED(), NULL);
8415 8444 }
8416 8445
8417 8446 sp->rs_owner->ro_client->rc_unlksys_completed = TRUE;
8418 8447 }
8419 8448 }
8420 8449
8421 8450 /*
8422 8451 * Release all locks on this file by this lock owner or at
8423 8452 * least mark the locks as having been released
8424 8453 */
8425 8454 for (lsp = list_head(&sp->rs_lostatelist); lsp != NULL;
8426 8455 lsp = list_next(&sp->rs_lostatelist, lsp)) {
8427 8456 lsp->rls_locks_cleaned = TRUE;
8428 8457
8429 8458 /* Was this already taken care of above? */
8430 8459 if (!close_of_client &&
8431 8460 sp->rs_owner->ro_client->rc_sysidt != LM_NOSYSID)
8432 8461 (void) cleanlocks(sp->rs_finfo->rf_vp,
8433 8462 lsp->rls_locker->rl_pid,
8434 8463 lsp->rls_locker->rl_client->rc_sysidt);
8435 8464 }
8436 8465
8437 8466 /*
8438 8467 * Release any shrlocks associated with this open state ID.
8439 8468 * This must be done before the rfs4_state gets marked closed.
8440 8469 */
8441 8470 if (sp->rs_owner->ro_client->rc_sysidt != LM_NOSYSID)
8442 8471 (void) rfs4_unshare(sp);
8443 8472
8444 8473 if (sp->rs_open_access) {
8445 8474 rfs4_dbe_lock(fp->rf_dbe);
8446 8475
8447 8476 /*
8448 8477 * Decrement the count for each access and deny bit that this
8449 8478 * state has contributed to the file.
8450 8479 * If the file counts go to zero
8451 8480 * clear the appropriate bit in the appropriate mask.
8452 8481 */
8453 8482 if (sp->rs_open_access & OPEN4_SHARE_ACCESS_READ) {
8454 8483 fp->rf_access_read--;
8455 8484 fflags |= FREAD;
8456 8485 if (fp->rf_access_read == 0)
8457 8486 fp->rf_share_access &= ~OPEN4_SHARE_ACCESS_READ;
8458 8487 }
8459 8488 if (sp->rs_open_access & OPEN4_SHARE_ACCESS_WRITE) {
8460 8489 fp->rf_access_write--;
8461 8490 fflags |= FWRITE;
8462 8491 if (fp->rf_access_write == 0)
8463 8492 fp->rf_share_access &=
8464 8493 ~OPEN4_SHARE_ACCESS_WRITE;
8465 8494 }
8466 8495 if (sp->rs_open_deny & OPEN4_SHARE_DENY_READ) {
8467 8496 fp->rf_deny_read--;
8468 8497 if (fp->rf_deny_read == 0)
8469 8498 fp->rf_share_deny &= ~OPEN4_SHARE_DENY_READ;
8470 8499 }
8471 8500 if (sp->rs_open_deny & OPEN4_SHARE_DENY_WRITE) {
8472 8501 fp->rf_deny_write--;
8473 8502 if (fp->rf_deny_write == 0)
8474 8503 fp->rf_share_deny &= ~OPEN4_SHARE_DENY_WRITE;
8475 8504 }
8476 8505
8477 8506 (void) VOP_CLOSE(fp->rf_vp, fflags, 1, (offset_t)0, cr, NULL);
8478 8507
8479 8508 rfs4_dbe_unlock(fp->rf_dbe);
8480 8509
8481 8510 sp->rs_open_access = 0;
8482 8511 sp->rs_open_deny = 0;
8483 8512 }
8484 8513 }
8485 8514
8486 8515 /*
8487 8516 * lock_denied: Fill in a LOCK4deneid structure given an flock64 structure.
8488 8517 */
8489 8518 static nfsstat4
8490 8519 lock_denied(LOCK4denied *dp, struct flock64 *flk)
8491 8520 {
8492 8521 rfs4_lockowner_t *lo;
8493 8522 rfs4_client_t *cp;
8494 8523 uint32_t len;
8495 8524
8496 8525 lo = rfs4_findlockowner_by_pid(flk->l_pid);
8497 8526 if (lo != NULL) {
8498 8527 cp = lo->rl_client;
8499 8528 if (rfs4_lease_expired(cp)) {
8500 8529 rfs4_lockowner_rele(lo);
8501 8530 rfs4_dbe_hold(cp->rc_dbe);
8502 8531 rfs4_client_close(cp);
8503 8532 return (NFS4ERR_EXPIRED);
8504 8533 }
8505 8534 dp->owner.clientid = lo->rl_owner.clientid;
8506 8535 len = lo->rl_owner.owner_len;
8507 8536 dp->owner.owner_val = kmem_alloc(len, KM_SLEEP);
8508 8537 bcopy(lo->rl_owner.owner_val, dp->owner.owner_val, len);
8509 8538 dp->owner.owner_len = len;
8510 8539 rfs4_lockowner_rele(lo);
8511 8540 goto finish;
8512 8541 }
8513 8542
8514 8543 /*
8515 8544 * Its not a NFS4 lock. We take advantage that the upper 32 bits
8516 8545 * of the client id contain the boot time for a NFS4 lock. So we
8517 8546 * fabricate and identity by setting clientid to the sysid, and
8518 8547 * the lock owner to the pid.
8519 8548 */
8520 8549 dp->owner.clientid = flk->l_sysid;
8521 8550 len = sizeof (pid_t);
8522 8551 dp->owner.owner_len = len;
8523 8552 dp->owner.owner_val = kmem_alloc(len, KM_SLEEP);
8524 8553 bcopy(&flk->l_pid, dp->owner.owner_val, len);
8525 8554 finish:
8526 8555 dp->offset = flk->l_start;
8527 8556 dp->length = flk->l_len;
8528 8557
8529 8558 if (flk->l_type == F_RDLCK)
8530 8559 dp->locktype = READ_LT;
8531 8560 else if (flk->l_type == F_WRLCK)
8532 8561 dp->locktype = WRITE_LT;
8533 8562 else
8534 8563 return (NFS4ERR_INVAL); /* no mapping from POSIX ltype to v4 */
8535 8564
8536 8565 return (NFS4_OK);
8537 8566 }
8538 8567
8539 8568 /*
8540 8569 * The NFSv4.0 LOCK operation does not support the blocking lock (at the
8541 8570 * NFSv4.0 protocol level) so the client needs to resend the LOCK request in a
8542 8571 * case the lock is denied by the NFSv4.0 server. NFSv4.0 clients are prepared
8543 8572 * for that (obviously); they are sending the LOCK requests with some delays
8544 8573 * between the attempts. See nfs4frlock() and nfs4_block_and_wait() for the
8545 8574 * locking and delay implementation at the client side.
8546 8575 *
8547 8576 * To make the life of the clients easier, the NFSv4.0 server tries to do some
8548 8577 * fast retries on its own (the for loop below) in a hope the lock will be
8549 8578 * available soon. And if not, the client won't need to resend the LOCK
8550 8579 * requests so fast to check the lock availability. This basically saves some
8551 8580 * network traffic and tries to make sure the client gets the lock ASAP.
8552 8581 */
8553 8582 static int
8554 8583 setlock(vnode_t *vp, struct flock64 *flock, int flag, cred_t *cred)
8555 8584 {
8556 8585 int error;
8557 8586 struct flock64 flk;
8558 8587 int i;
8559 8588 clock_t delaytime;
8560 8589 int cmd;
8561 8590 int spin_cnt = 0;
8562 8591
8563 8592 cmd = nbl_need_check(vp) ? F_SETLK_NBMAND : F_SETLK;
8564 8593 retry:
8565 8594 delaytime = MSEC_TO_TICK_ROUNDUP(rfs4_lock_delay);
8566 8595
8567 8596 for (i = 0; i < rfs4_maxlock_tries; i++) {
8568 8597 LOCK_PRINT(rfs4_debug, "setlock", cmd, flock);
8569 8598 error = VOP_FRLOCK(vp, cmd,
8570 8599 flock, flag, (u_offset_t)0, NULL, cred, NULL);
8571 8600
8572 8601 if (error != EAGAIN && error != EACCES)
8573 8602 break;
8574 8603
8575 8604 if (i < rfs4_maxlock_tries - 1) {
8576 8605 delay(delaytime);
8577 8606 delaytime *= 2;
8578 8607 }
8579 8608 }
8580 8609
8581 8610 if (error == EAGAIN || error == EACCES) {
8582 8611 /* Get the owner of the lock */
8583 8612 flk = *flock;
8584 8613 LOCK_PRINT(rfs4_debug, "setlock", F_GETLK, &flk);
8585 8614 if (VOP_FRLOCK(vp, F_GETLK, &flk, flag, 0, NULL, cred,
8586 8615 NULL) == 0) {
8587 8616 /*
8588 8617 * There's a race inherent in the current VOP_FRLOCK
8589 8618 * design where:
8590 8619 * a: "other guy" takes a lock that conflicts with a
8591 8620 * lock we want
8592 8621 * b: we attempt to take our lock (non-blocking) and
8593 8622 * the attempt fails.
8594 8623 * c: "other guy" releases the conflicting lock
8595 8624 * d: we ask what lock conflicts with the lock we want,
8596 8625 * getting F_UNLCK (no lock blocks us)
8597 8626 *
8598 8627 * If we retry the non-blocking lock attempt in this
8599 8628 * case (restart at step 'b') there's some possibility
8600 8629 * that many such attempts might fail. However a test
8601 8630 * designed to actually provoke this race shows that
8602 8631 * the vast majority of cases require no retry, and
8603 8632 * only a few took as many as three retries. Here's
8604 8633 * the test outcome:
8605 8634 *
8606 8635 * number of retries how many times we needed
8607 8636 * that many retries
8608 8637 * 0 79461
8609 8638 * 1 862
8610 8639 * 2 49
8611 8640 * 3 5
8612 8641 *
8613 8642 * Given those empirical results, we arbitrarily limit
8614 8643 * the retry count to ten.
8615 8644 *
8616 8645 * If we actually make to ten retries and give up,
8617 8646 * nothing catastrophic happens, but we're unable to
8618 8647 * return the information about the conflicting lock to
8619 8648 * the NFS client. That's an acceptable trade off vs.
8620 8649 * letting this retry loop run forever.
8621 8650 */
8622 8651 if (flk.l_type == F_UNLCK) {
8623 8652 if (spin_cnt++ < 10) {
8624 8653 /* No longer locked, retry */
8625 8654 goto retry;
8626 8655 }
8627 8656 } else {
8628 8657 *flock = flk;
8629 8658 LOCK_PRINT(rfs4_debug, "setlock(blocking lock)",
8630 8659 F_GETLK, &flk);
8631 8660 }
8632 8661 }
8633 8662 }
8634 8663
8635 8664 return (error);
8636 8665 }
8637 8666
8638 8667 /*ARGSUSED*/
8639 8668 static nfsstat4
8640 8669 rfs4_do_lock(rfs4_lo_state_t *lsp, nfs_lock_type4 locktype,
8641 8670 offset4 offset, length4 length, cred_t *cred, nfs_resop4 *resop)
8642 8671 {
8643 8672 nfsstat4 status;
8644 8673 rfs4_lockowner_t *lo = lsp->rls_locker;
8645 8674 rfs4_state_t *sp = lsp->rls_state;
8646 8675 struct flock64 flock;
8647 8676 int16_t ltype;
8648 8677 int flag;
8649 8678 int error;
8650 8679 sysid_t sysid;
8651 8680 LOCK4res *lres;
8652 8681 vnode_t *vp;
8653 8682
8654 8683 if (rfs4_lease_expired(lo->rl_client)) {
8655 8684 return (NFS4ERR_EXPIRED);
8656 8685 }
8657 8686
8658 8687 if ((status = rfs4_client_sysid(lo->rl_client, &sysid)) != NFS4_OK)
8659 8688 return (status);
8660 8689
8661 8690 /* Check for zero length. To lock to end of file use all ones for V4 */
8662 8691 if (length == 0)
8663 8692 return (NFS4ERR_INVAL);
8664 8693 else if (length == (length4)(~0))
8665 8694 length = 0; /* Posix to end of file */
8666 8695
8667 8696 retry:
8668 8697 rfs4_dbe_lock(sp->rs_dbe);
8669 8698 if (sp->rs_closed == TRUE) {
8670 8699 rfs4_dbe_unlock(sp->rs_dbe);
8671 8700 return (NFS4ERR_OLD_STATEID);
8672 8701 }
8673 8702
8674 8703 if (resop->resop != OP_LOCKU) {
8675 8704 switch (locktype) {
8676 8705 case READ_LT:
8677 8706 case READW_LT:
8678 8707 if ((sp->rs_share_access
8679 8708 & OPEN4_SHARE_ACCESS_READ) == 0) {
8680 8709 rfs4_dbe_unlock(sp->rs_dbe);
8681 8710
8682 8711 return (NFS4ERR_OPENMODE);
8683 8712 }
8684 8713 ltype = F_RDLCK;
8685 8714 break;
8686 8715 case WRITE_LT:
8687 8716 case WRITEW_LT:
8688 8717 if ((sp->rs_share_access
8689 8718 & OPEN4_SHARE_ACCESS_WRITE) == 0) {
8690 8719 rfs4_dbe_unlock(sp->rs_dbe);
8691 8720
8692 8721 return (NFS4ERR_OPENMODE);
8693 8722 }
8694 8723 ltype = F_WRLCK;
8695 8724 break;
8696 8725 }
8697 8726 } else
8698 8727 ltype = F_UNLCK;
8699 8728
8700 8729 flock.l_type = ltype;
8701 8730 flock.l_whence = 0; /* SEEK_SET */
8702 8731 flock.l_start = offset;
8703 8732 flock.l_len = length;
8704 8733 flock.l_sysid = sysid;
8705 8734 flock.l_pid = lsp->rls_locker->rl_pid;
8706 8735
8707 8736 /* Note that length4 is uint64_t but l_len and l_start are off64_t */
8708 8737 if (flock.l_len < 0 || flock.l_start < 0) {
8709 8738 rfs4_dbe_unlock(sp->rs_dbe);
8710 8739 return (NFS4ERR_INVAL);
8711 8740 }
8712 8741
8713 8742 /*
8714 8743 * N.B. FREAD has the same value as OPEN4_SHARE_ACCESS_READ and
8715 8744 * FWRITE has the same value as OPEN4_SHARE_ACCESS_WRITE.
8716 8745 */
8717 8746 flag = (int)sp->rs_share_access | F_REMOTELOCK;
8718 8747
8719 8748 vp = sp->rs_finfo->rf_vp;
8720 8749 VN_HOLD(vp);
8721 8750
8722 8751 /*
8723 8752 * We need to unlock sp before we call the underlying filesystem to
8724 8753 * acquire the file lock.
8725 8754 */
8726 8755 rfs4_dbe_unlock(sp->rs_dbe);
8727 8756
8728 8757 error = setlock(vp, &flock, flag, cred);
8729 8758
8730 8759 /*
8731 8760 * Make sure the file is still open. In a case the file was closed in
8732 8761 * the meantime, clean the lock we acquired using the setlock() call
8733 8762 * above, and return the appropriate error.
8734 8763 */
8735 8764 rfs4_dbe_lock(sp->rs_dbe);
8736 8765 if (sp->rs_closed == TRUE) {
8737 8766 cleanlocks(vp, lsp->rls_locker->rl_pid, sysid);
8738 8767 rfs4_dbe_unlock(sp->rs_dbe);
8739 8768
8740 8769 VN_RELE(vp);
8741 8770
8742 8771 return (NFS4ERR_OLD_STATEID);
8743 8772 }
8744 8773 rfs4_dbe_unlock(sp->rs_dbe);
8745 8774
8746 8775 VN_RELE(vp);
8747 8776
8748 8777 if (error == 0) {
8749 8778 rfs4_dbe_lock(lsp->rls_dbe);
8750 8779 next_stateid(&lsp->rls_lockid);
8751 8780 rfs4_dbe_unlock(lsp->rls_dbe);
8752 8781 }
8753 8782
8754 8783 /*
8755 8784 * N.B. We map error values to nfsv4 errors. This is differrent
8756 8785 * than puterrno4 routine.
8757 8786 */
8758 8787 switch (error) {
8759 8788 case 0:
8760 8789 status = NFS4_OK;
8761 8790 break;
8762 8791 case EAGAIN:
8763 8792 case EACCES: /* Old value */
8764 8793 /* Can only get here if op is OP_LOCK */
8765 8794 ASSERT(resop->resop == OP_LOCK);
8766 8795 lres = &resop->nfs_resop4_u.oplock;
8767 8796 status = NFS4ERR_DENIED;
8768 8797 if (lock_denied(&lres->LOCK4res_u.denied, &flock)
8769 8798 == NFS4ERR_EXPIRED)
8770 8799 goto retry;
8771 8800 break;
8772 8801 case ENOLCK:
8773 8802 status = NFS4ERR_DELAY;
8774 8803 break;
8775 8804 case EOVERFLOW:
8776 8805 status = NFS4ERR_INVAL;
8777 8806 break;
8778 8807 case EINVAL:
8779 8808 status = NFS4ERR_NOTSUPP;
8780 8809 break;
8781 8810 default:
8782 8811 status = NFS4ERR_SERVERFAULT;
8783 8812 break;
8784 8813 }
8785 8814
8786 8815 return (status);
8787 8816 }
8788 8817
8789 8818 /*ARGSUSED*/
8790 8819 void
8791 8820 rfs4_op_lock(nfs_argop4 *argop, nfs_resop4 *resop,
8792 8821 struct svc_req *req, struct compound_state *cs)
8793 8822 {
8794 8823 LOCK4args *args = &argop->nfs_argop4_u.oplock;
8795 8824 LOCK4res *resp = &resop->nfs_resop4_u.oplock;
8796 8825 nfsstat4 status;
8797 8826 stateid4 *stateid;
8798 8827 rfs4_lockowner_t *lo;
8799 8828 rfs4_client_t *cp;
8800 8829 rfs4_state_t *sp = NULL;
8801 8830 rfs4_lo_state_t *lsp = NULL;
8802 8831 bool_t ls_sw_held = FALSE;
8803 8832 bool_t create = TRUE;
8804 8833 bool_t lcreate = TRUE;
8805 8834 bool_t dup_lock = FALSE;
8806 8835 int rc;
8807 8836
8808 8837 DTRACE_NFSV4_2(op__lock__start, struct compound_state *, cs,
8809 8838 LOCK4args *, args);
8810 8839
8811 8840 if (cs->vp == NULL) {
8812 8841 *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
8813 8842 DTRACE_NFSV4_2(op__lock__done, struct compound_state *,
8814 8843 cs, LOCK4res *, resp);
8815 8844 return;
8816 8845 }
8817 8846
8818 8847 if (args->locker.new_lock_owner) {
8819 8848 /* Create a new lockowner for this instance */
8820 8849 open_to_lock_owner4 *olo = &args->locker.locker4_u.open_owner;
8821 8850
8822 8851 NFS4_DEBUG(rfs4_debug, (CE_NOTE, "Creating new lock owner"));
8823 8852
8824 8853 stateid = &olo->open_stateid;
8825 8854 status = rfs4_get_state(stateid, &sp, RFS4_DBS_VALID);
8826 8855 if (status != NFS4_OK) {
8827 8856 NFS4_DEBUG(rfs4_debug,
8828 8857 (CE_NOTE, "Get state failed in lock %d", status));
8829 8858 *cs->statusp = resp->status = status;
8830 8859 DTRACE_NFSV4_2(op__lock__done, struct compound_state *,
8831 8860 cs, LOCK4res *, resp);
8832 8861 return;
8833 8862 }
8834 8863
8835 8864 /* Ensure specified filehandle matches */
8836 8865 if (cs->vp != sp->rs_finfo->rf_vp) {
8837 8866 rfs4_state_rele(sp);
8838 8867 *cs->statusp = resp->status = NFS4ERR_BAD_STATEID;
8839 8868 DTRACE_NFSV4_2(op__lock__done, struct compound_state *,
8840 8869 cs, LOCK4res *, resp);
8841 8870 return;
8842 8871 }
8843 8872
8844 8873 /* hold off other access to open_owner while we tinker */
8845 8874 rfs4_sw_enter(&sp->rs_owner->ro_sw);
8846 8875
8847 8876 switch (rc = rfs4_check_stateid_seqid(sp, stateid)) {
8848 8877 case NFS4_CHECK_STATEID_OLD:
8849 8878 *cs->statusp = resp->status = NFS4ERR_OLD_STATEID;
8850 8879 goto end;
8851 8880 case NFS4_CHECK_STATEID_BAD:
8852 8881 *cs->statusp = resp->status = NFS4ERR_BAD_STATEID;
8853 8882 goto end;
8854 8883 case NFS4_CHECK_STATEID_EXPIRED:
8855 8884 *cs->statusp = resp->status = NFS4ERR_EXPIRED;
8856 8885 goto end;
8857 8886 case NFS4_CHECK_STATEID_UNCONFIRMED:
8858 8887 *cs->statusp = resp->status = NFS4ERR_BAD_STATEID;
8859 8888 goto end;
8860 8889 case NFS4_CHECK_STATEID_CLOSED:
8861 8890 *cs->statusp = resp->status = NFS4ERR_OLD_STATEID;
8862 8891 goto end;
8863 8892 case NFS4_CHECK_STATEID_OKAY:
8864 8893 case NFS4_CHECK_STATEID_REPLAY:
8865 8894 switch (rfs4_check_olo_seqid(olo->open_seqid,
8866 8895 sp->rs_owner, resop)) {
8867 8896 case NFS4_CHKSEQ_OKAY:
8868 8897 if (rc == NFS4_CHECK_STATEID_OKAY)
8869 8898 break;
8870 8899 /*
8871 8900 * This is replayed stateid; if seqid
8872 8901 * matches next expected, then client
8873 8902 * is using wrong seqid.
8874 8903 */
8875 8904 /* FALLTHROUGH */
8876 8905 case NFS4_CHKSEQ_BAD:
8877 8906 *cs->statusp = resp->status = NFS4ERR_BAD_SEQID;
8878 8907 goto end;
8879 8908 case NFS4_CHKSEQ_REPLAY:
8880 8909 /* This is a duplicate LOCK request */
8881 8910 dup_lock = TRUE;
8882 8911
8883 8912 /*
8884 8913 * For a duplicate we do not want to
8885 8914 * create a new lockowner as it should
8886 8915 * already exist.
8887 8916 * Turn off the lockowner create flag.
8888 8917 */
8889 8918 lcreate = FALSE;
8890 8919 }
8891 8920 break;
8892 8921 }
8893 8922
8894 8923 lo = rfs4_findlockowner(&olo->lock_owner, &lcreate);
8895 8924 if (lo == NULL) {
8896 8925 NFS4_DEBUG(rfs4_debug,
8897 8926 (CE_NOTE, "rfs4_op_lock: no lock owner"));
8898 8927 *cs->statusp = resp->status = NFS4ERR_RESOURCE;
8899 8928 goto end;
8900 8929 }
8901 8930
8902 8931 lsp = rfs4_findlo_state_by_owner(lo, sp, &create);
8903 8932 if (lsp == NULL) {
8904 8933 rfs4_update_lease(sp->rs_owner->ro_client);
8905 8934 /*
8906 8935 * Only update theh open_seqid if this is not
8907 8936 * a duplicate request
8908 8937 */
8909 8938 if (dup_lock == FALSE) {
8910 8939 rfs4_update_open_sequence(sp->rs_owner);
8911 8940 }
8912 8941
8913 8942 NFS4_DEBUG(rfs4_debug,
8914 8943 (CE_NOTE, "rfs4_op_lock: no state"));
8915 8944 *cs->statusp = resp->status = NFS4ERR_SERVERFAULT;
8916 8945 rfs4_update_open_resp(sp->rs_owner, resop, NULL);
8917 8946 rfs4_lockowner_rele(lo);
8918 8947 goto end;
8919 8948 }
8920 8949
8921 8950 /*
8922 8951 * This is the new_lock_owner branch and the client is
8923 8952 * supposed to be associating a new lock_owner with
8924 8953 * the open file at this point. If we find that a
8925 8954 * lock_owner/state association already exists and a
8926 8955 * successful LOCK request was returned to the client,
8927 8956 * an error is returned to the client since this is
8928 8957 * not appropriate. The client should be using the
8929 8958 * existing lock_owner branch.
8930 8959 */
8931 8960 if (dup_lock == FALSE && create == FALSE) {
8932 8961 if (lsp->rls_lock_completed == TRUE) {
8933 8962 *cs->statusp =
8934 8963 resp->status = NFS4ERR_BAD_SEQID;
8935 8964 rfs4_lockowner_rele(lo);
8936 8965 goto end;
8937 8966 }
8938 8967 }
8939 8968
8940 8969 rfs4_update_lease(sp->rs_owner->ro_client);
8941 8970
8942 8971 /*
8943 8972 * Only update theh open_seqid if this is not
8944 8973 * a duplicate request
8945 8974 */
8946 8975 if (dup_lock == FALSE) {
8947 8976 rfs4_update_open_sequence(sp->rs_owner);
8948 8977 }
8949 8978
8950 8979 /*
8951 8980 * If this is a duplicate lock request, just copy the
8952 8981 * previously saved reply and return.
8953 8982 */
8954 8983 if (dup_lock == TRUE) {
8955 8984 /* verify that lock_seqid's match */
8956 8985 if (lsp->rls_seqid != olo->lock_seqid) {
8957 8986 NFS4_DEBUG(rfs4_debug,
8958 8987 (CE_NOTE, "rfs4_op_lock: Dup-Lock seqid bad"
8959 8988 "lsp->seqid=%d old->seqid=%d",
8960 8989 lsp->rls_seqid, olo->lock_seqid));
8961 8990 *cs->statusp = resp->status = NFS4ERR_BAD_SEQID;
8962 8991 } else {
8963 8992 rfs4_copy_reply(resop, &lsp->rls_reply);
8964 8993 /*
8965 8994 * Make sure to copy the just
8966 8995 * retrieved reply status into the
8967 8996 * overall compound status
8968 8997 */
8969 8998 *cs->statusp = resp->status;
8970 8999 }
8971 9000 rfs4_lockowner_rele(lo);
8972 9001 goto end;
8973 9002 }
8974 9003
8975 9004 rfs4_dbe_lock(lsp->rls_dbe);
8976 9005
8977 9006 /* Make sure to update the lock sequence id */
8978 9007 lsp->rls_seqid = olo->lock_seqid;
8979 9008
8980 9009 NFS4_DEBUG(rfs4_debug,
8981 9010 (CE_NOTE, "Lock seqid established as %d", lsp->rls_seqid));
8982 9011
8983 9012 /*
8984 9013 * This is used to signify the newly created lockowner
8985 9014 * stateid and its sequence number. The checks for
8986 9015 * sequence number and increment don't occur on the
8987 9016 * very first lock request for a lockowner.
8988 9017 */
8989 9018 lsp->rls_skip_seqid_check = TRUE;
8990 9019
8991 9020 /* hold off other access to lsp while we tinker */
8992 9021 rfs4_sw_enter(&lsp->rls_sw);
8993 9022 ls_sw_held = TRUE;
8994 9023
8995 9024 rfs4_dbe_unlock(lsp->rls_dbe);
8996 9025
8997 9026 rfs4_lockowner_rele(lo);
8998 9027 } else {
8999 9028 stateid = &args->locker.locker4_u.lock_owner.lock_stateid;
9000 9029 /* get lsp and hold the lock on the underlying file struct */
9001 9030 if ((status = rfs4_get_lo_state(stateid, &lsp, TRUE))
9002 9031 != NFS4_OK) {
9003 9032 *cs->statusp = resp->status = status;
9004 9033 DTRACE_NFSV4_2(op__lock__done, struct compound_state *,
9005 9034 cs, LOCK4res *, resp);
9006 9035 return;
9007 9036 }
9008 9037 create = FALSE; /* We didn't create lsp */
9009 9038
9010 9039 /* Ensure specified filehandle matches */
9011 9040 if (cs->vp != lsp->rls_state->rs_finfo->rf_vp) {
9012 9041 rfs4_lo_state_rele(lsp, TRUE);
9013 9042 *cs->statusp = resp->status = NFS4ERR_BAD_STATEID;
9014 9043 DTRACE_NFSV4_2(op__lock__done, struct compound_state *,
9015 9044 cs, LOCK4res *, resp);
9016 9045 return;
9017 9046 }
9018 9047
9019 9048 /* hold off other access to lsp while we tinker */
9020 9049 rfs4_sw_enter(&lsp->rls_sw);
9021 9050 ls_sw_held = TRUE;
9022 9051
9023 9052 switch (rfs4_check_lo_stateid_seqid(lsp, stateid)) {
9024 9053 /*
9025 9054 * The stateid looks like it was okay (expected to be
9026 9055 * the next one)
9027 9056 */
9028 9057 case NFS4_CHECK_STATEID_OKAY:
9029 9058 /*
9030 9059 * The sequence id is now checked. Determine
9031 9060 * if this is a replay or if it is in the
9032 9061 * expected (next) sequence. In the case of a
9033 9062 * replay, there are two replay conditions
9034 9063 * that may occur. The first is the normal
9035 9064 * condition where a LOCK is done with a
9036 9065 * NFS4_OK response and the stateid is
9037 9066 * updated. That case is handled below when
9038 9067 * the stateid is identified as a REPLAY. The
9039 9068 * second is the case where an error is
9040 9069 * returned, like NFS4ERR_DENIED, and the
9041 9070 * sequence number is updated but the stateid
9042 9071 * is not updated. This second case is dealt
9043 9072 * with here. So it may seem odd that the
9044 9073 * stateid is okay but the sequence id is a
9045 9074 * replay but it is okay.
9046 9075 */
9047 9076 switch (rfs4_check_lock_seqid(
9048 9077 args->locker.locker4_u.lock_owner.lock_seqid,
9049 9078 lsp, resop)) {
9050 9079 case NFS4_CHKSEQ_REPLAY:
9051 9080 if (resp->status != NFS4_OK) {
9052 9081 /*
9053 9082 * Here is our replay and need
9054 9083 * to verify that the last
9055 9084 * response was an error.
9056 9085 */
9057 9086 *cs->statusp = resp->status;
9058 9087 goto end;
9059 9088 }
9060 9089 /*
9061 9090 * This is done since the sequence id
9062 9091 * looked like a replay but it didn't
9063 9092 * pass our check so a BAD_SEQID is
9064 9093 * returned as a result.
9065 9094 */
9066 9095 /*FALLTHROUGH*/
9067 9096 case NFS4_CHKSEQ_BAD:
9068 9097 *cs->statusp = resp->status = NFS4ERR_BAD_SEQID;
9069 9098 goto end;
9070 9099 case NFS4_CHKSEQ_OKAY:
9071 9100 /* Everything looks okay move ahead */
9072 9101 break;
9073 9102 }
9074 9103 break;
9075 9104 case NFS4_CHECK_STATEID_OLD:
9076 9105 *cs->statusp = resp->status = NFS4ERR_OLD_STATEID;
9077 9106 goto end;
9078 9107 case NFS4_CHECK_STATEID_BAD:
9079 9108 *cs->statusp = resp->status = NFS4ERR_BAD_STATEID;
9080 9109 goto end;
9081 9110 case NFS4_CHECK_STATEID_EXPIRED:
9082 9111 *cs->statusp = resp->status = NFS4ERR_EXPIRED;
9083 9112 goto end;
9084 9113 case NFS4_CHECK_STATEID_CLOSED:
9085 9114 *cs->statusp = resp->status = NFS4ERR_OLD_STATEID;
9086 9115 goto end;
9087 9116 case NFS4_CHECK_STATEID_REPLAY:
9088 9117 switch (rfs4_check_lock_seqid(
9089 9118 args->locker.locker4_u.lock_owner.lock_seqid,
9090 9119 lsp, resop)) {
9091 9120 case NFS4_CHKSEQ_OKAY:
9092 9121 /*
9093 9122 * This is a replayed stateid; if
9094 9123 * seqid matches the next expected,
9095 9124 * then client is using wrong seqid.
9096 9125 */
9097 9126 case NFS4_CHKSEQ_BAD:
9098 9127 *cs->statusp = resp->status = NFS4ERR_BAD_SEQID;
9099 9128 goto end;
9100 9129 case NFS4_CHKSEQ_REPLAY:
9101 9130 rfs4_update_lease(lsp->rls_locker->rl_client);
9102 9131 *cs->statusp = status = resp->status;
9103 9132 goto end;
9104 9133 }
9105 9134 break;
9106 9135 default:
9107 9136 ASSERT(FALSE);
9108 9137 break;
9109 9138 }
9110 9139
9111 9140 rfs4_update_lock_sequence(lsp);
9112 9141 rfs4_update_lease(lsp->rls_locker->rl_client);
9113 9142 }
9114 9143
9115 9144 /*
9116 9145 * NFS4 only allows locking on regular files, so
9117 9146 * verify type of object.
9118 9147 */
9119 9148 if (cs->vp->v_type != VREG) {
9120 9149 if (cs->vp->v_type == VDIR)
9121 9150 status = NFS4ERR_ISDIR;
9122 9151 else
9123 9152 status = NFS4ERR_INVAL;
9124 9153 goto out;
9125 9154 }
9126 9155
9127 9156 cp = lsp->rls_state->rs_owner->ro_client;
9128 9157
9129 9158 if (rfs4_clnt_in_grace(cp) && !args->reclaim) {
9130 9159 status = NFS4ERR_GRACE;
9131 9160 goto out;
9132 9161 }
9133 9162
9134 9163 if (rfs4_clnt_in_grace(cp) && args->reclaim && !cp->rc_can_reclaim) {
9135 9164 status = NFS4ERR_NO_GRACE;
9136 9165 goto out;
9137 9166 }
9138 9167
9139 9168 if (!rfs4_clnt_in_grace(cp) && args->reclaim) {
9140 9169 status = NFS4ERR_NO_GRACE;
9141 9170 goto out;
9142 9171 }
9143 9172
9144 9173 if (lsp->rls_state->rs_finfo->rf_dinfo.rd_dtype == OPEN_DELEGATE_WRITE)
9145 9174 cs->deleg = TRUE;
9146 9175
9147 9176 status = rfs4_do_lock(lsp, args->locktype,
9148 9177 args->offset, args->length, cs->cr, resop);
9149 9178
9150 9179 out:
9151 9180 lsp->rls_skip_seqid_check = FALSE;
9152 9181
9153 9182 *cs->statusp = resp->status = status;
9154 9183
9155 9184 if (status == NFS4_OK) {
9156 9185 resp->LOCK4res_u.lock_stateid = lsp->rls_lockid.stateid;
9157 9186 lsp->rls_lock_completed = TRUE;
9158 9187 }
9159 9188 /*
9160 9189 * Only update the "OPEN" response here if this was a new
9161 9190 * lock_owner
9162 9191 */
9163 9192 if (sp)
9164 9193 rfs4_update_open_resp(sp->rs_owner, resop, NULL);
9165 9194
9166 9195 rfs4_update_lock_resp(lsp, resop);
9167 9196
9168 9197 end:
9169 9198 if (lsp) {
9170 9199 if (ls_sw_held)
9171 9200 rfs4_sw_exit(&lsp->rls_sw);
9172 9201 /*
9173 9202 * If an sp obtained, then the lsp does not represent
9174 9203 * a lock on the file struct.
9175 9204 */
9176 9205 if (sp != NULL)
9177 9206 rfs4_lo_state_rele(lsp, FALSE);
9178 9207 else
9179 9208 rfs4_lo_state_rele(lsp, TRUE);
9180 9209 }
9181 9210 if (sp) {
9182 9211 rfs4_sw_exit(&sp->rs_owner->ro_sw);
9183 9212 rfs4_state_rele(sp);
9184 9213 }
9185 9214
9186 9215 DTRACE_NFSV4_2(op__lock__done, struct compound_state *, cs,
9187 9216 LOCK4res *, resp);
9188 9217 }
9189 9218
9190 9219 /* free function for LOCK/LOCKT */
9191 9220 static void
9192 9221 lock_denied_free(nfs_resop4 *resop)
9193 9222 {
9194 9223 LOCK4denied *dp = NULL;
9195 9224
9196 9225 switch (resop->resop) {
9197 9226 case OP_LOCK:
9198 9227 if (resop->nfs_resop4_u.oplock.status == NFS4ERR_DENIED)
9199 9228 dp = &resop->nfs_resop4_u.oplock.LOCK4res_u.denied;
9200 9229 break;
9201 9230 case OP_LOCKT:
9202 9231 if (resop->nfs_resop4_u.oplockt.status == NFS4ERR_DENIED)
9203 9232 dp = &resop->nfs_resop4_u.oplockt.denied;
9204 9233 break;
9205 9234 default:
9206 9235 break;
9207 9236 }
9208 9237
9209 9238 if (dp)
9210 9239 kmem_free(dp->owner.owner_val, dp->owner.owner_len);
9211 9240 }
9212 9241
9213 9242 /*ARGSUSED*/
9214 9243 void
9215 9244 rfs4_op_locku(nfs_argop4 *argop, nfs_resop4 *resop,
9216 9245 struct svc_req *req, struct compound_state *cs)
9217 9246 {
9218 9247 LOCKU4args *args = &argop->nfs_argop4_u.oplocku;
9219 9248 LOCKU4res *resp = &resop->nfs_resop4_u.oplocku;
9220 9249 nfsstat4 status;
9221 9250 stateid4 *stateid = &args->lock_stateid;
9222 9251 rfs4_lo_state_t *lsp;
9223 9252
9224 9253 DTRACE_NFSV4_2(op__locku__start, struct compound_state *, cs,
9225 9254 LOCKU4args *, args);
9226 9255
9227 9256 if (cs->vp == NULL) {
9228 9257 *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
9229 9258 DTRACE_NFSV4_2(op__locku__done, struct compound_state *, cs,
9230 9259 LOCKU4res *, resp);
9231 9260 return;
9232 9261 }
9233 9262
9234 9263 if ((status = rfs4_get_lo_state(stateid, &lsp, TRUE)) != NFS4_OK) {
9235 9264 *cs->statusp = resp->status = status;
9236 9265 DTRACE_NFSV4_2(op__locku__done, struct compound_state *, cs,
9237 9266 LOCKU4res *, resp);
9238 9267 return;
9239 9268 }
9240 9269
9241 9270 /* Ensure specified filehandle matches */
9242 9271 if (cs->vp != lsp->rls_state->rs_finfo->rf_vp) {
9243 9272 rfs4_lo_state_rele(lsp, TRUE);
9244 9273 *cs->statusp = resp->status = NFS4ERR_BAD_STATEID;
9245 9274 DTRACE_NFSV4_2(op__locku__done, struct compound_state *, cs,
9246 9275 LOCKU4res *, resp);
9247 9276 return;
9248 9277 }
9249 9278
9250 9279 /* hold off other access to lsp while we tinker */
9251 9280 rfs4_sw_enter(&lsp->rls_sw);
9252 9281
9253 9282 switch (rfs4_check_lo_stateid_seqid(lsp, stateid)) {
9254 9283 case NFS4_CHECK_STATEID_OKAY:
9255 9284 if (rfs4_check_lock_seqid(args->seqid, lsp, resop)
9256 9285 != NFS4_CHKSEQ_OKAY) {
9257 9286 *cs->statusp = resp->status = NFS4ERR_BAD_SEQID;
9258 9287 goto end;
9259 9288 }
9260 9289 break;
9261 9290 case NFS4_CHECK_STATEID_OLD:
9262 9291 *cs->statusp = resp->status = NFS4ERR_OLD_STATEID;
9263 9292 goto end;
9264 9293 case NFS4_CHECK_STATEID_BAD:
9265 9294 *cs->statusp = resp->status = NFS4ERR_BAD_STATEID;
9266 9295 goto end;
9267 9296 case NFS4_CHECK_STATEID_EXPIRED:
9268 9297 *cs->statusp = resp->status = NFS4ERR_EXPIRED;
9269 9298 goto end;
9270 9299 case NFS4_CHECK_STATEID_CLOSED:
9271 9300 *cs->statusp = resp->status = NFS4ERR_OLD_STATEID;
9272 9301 goto end;
9273 9302 case NFS4_CHECK_STATEID_REPLAY:
9274 9303 switch (rfs4_check_lock_seqid(args->seqid, lsp, resop)) {
9275 9304 case NFS4_CHKSEQ_OKAY:
9276 9305 /*
9277 9306 * This is a replayed stateid; if
9278 9307 * seqid matches the next expected,
9279 9308 * then client is using wrong seqid.
9280 9309 */
9281 9310 case NFS4_CHKSEQ_BAD:
9282 9311 *cs->statusp = resp->status = NFS4ERR_BAD_SEQID;
9283 9312 goto end;
9284 9313 case NFS4_CHKSEQ_REPLAY:
9285 9314 rfs4_update_lease(lsp->rls_locker->rl_client);
9286 9315 *cs->statusp = status = resp->status;
9287 9316 goto end;
9288 9317 }
9289 9318 break;
9290 9319 default:
9291 9320 ASSERT(FALSE);
9292 9321 break;
9293 9322 }
9294 9323
9295 9324 rfs4_update_lock_sequence(lsp);
9296 9325 rfs4_update_lease(lsp->rls_locker->rl_client);
9297 9326
9298 9327 /*
9299 9328 * NFS4 only allows locking on regular files, so
9300 9329 * verify type of object.
9301 9330 */
9302 9331 if (cs->vp->v_type != VREG) {
9303 9332 if (cs->vp->v_type == VDIR)
9304 9333 status = NFS4ERR_ISDIR;
9305 9334 else
9306 9335 status = NFS4ERR_INVAL;
9307 9336 goto out;
9308 9337 }
9309 9338
9310 9339 if (rfs4_clnt_in_grace(lsp->rls_state->rs_owner->ro_client)) {
9311 9340 status = NFS4ERR_GRACE;
9312 9341 goto out;
9313 9342 }
9314 9343
9315 9344 status = rfs4_do_lock(lsp, args->locktype,
9316 9345 args->offset, args->length, cs->cr, resop);
9317 9346
9318 9347 out:
9319 9348 *cs->statusp = resp->status = status;
9320 9349
9321 9350 if (status == NFS4_OK)
9322 9351 resp->lock_stateid = lsp->rls_lockid.stateid;
9323 9352
9324 9353 rfs4_update_lock_resp(lsp, resop);
9325 9354
9326 9355 end:
9327 9356 rfs4_sw_exit(&lsp->rls_sw);
9328 9357 rfs4_lo_state_rele(lsp, TRUE);
9329 9358
9330 9359 DTRACE_NFSV4_2(op__locku__done, struct compound_state *, cs,
9331 9360 LOCKU4res *, resp);
9332 9361 }
9333 9362
9334 9363 /*
9335 9364 * LOCKT is a best effort routine, the client can not be guaranteed that
9336 9365 * the status return is still in effect by the time the reply is received.
9337 9366 * They are numerous race conditions in this routine, but we are not required
9338 9367 * and can not be accurate.
9339 9368 */
9340 9369 /*ARGSUSED*/
9341 9370 void
9342 9371 rfs4_op_lockt(nfs_argop4 *argop, nfs_resop4 *resop,
9343 9372 struct svc_req *req, struct compound_state *cs)
9344 9373 {
9345 9374 LOCKT4args *args = &argop->nfs_argop4_u.oplockt;
9346 9375 LOCKT4res *resp = &resop->nfs_resop4_u.oplockt;
9347 9376 rfs4_lockowner_t *lo;
9348 9377 rfs4_client_t *cp;
9349 9378 bool_t create = FALSE;
9350 9379 struct flock64 flk;
9351 9380 int error;
9352 9381 int flag = FREAD | FWRITE;
9353 9382 int ltype;
9354 9383 length4 posix_length;
9355 9384 sysid_t sysid;
9356 9385 pid_t pid;
9357 9386
9358 9387 DTRACE_NFSV4_2(op__lockt__start, struct compound_state *, cs,
9359 9388 LOCKT4args *, args);
9360 9389
9361 9390 if (cs->vp == NULL) {
9362 9391 *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
9363 9392 goto out;
9364 9393 }
9365 9394
9366 9395 /*
9367 9396 * NFS4 only allows locking on regular files, so
9368 9397 * verify type of object.
9369 9398 */
9370 9399 if (cs->vp->v_type != VREG) {
9371 9400 if (cs->vp->v_type == VDIR)
9372 9401 *cs->statusp = resp->status = NFS4ERR_ISDIR;
9373 9402 else
9374 9403 *cs->statusp = resp->status = NFS4ERR_INVAL;
9375 9404 goto out;
9376 9405 }
9377 9406
9378 9407 /*
9379 9408 * Check out the clientid to ensure the server knows about it
9380 9409 * so that we correctly inform the client of a server reboot.
9381 9410 */
9382 9411 if ((cp = rfs4_findclient_by_id(args->owner.clientid, FALSE))
9383 9412 == NULL) {
9384 9413 *cs->statusp = resp->status =
9385 9414 rfs4_check_clientid(&args->owner.clientid, 0);
9386 9415 goto out;
9387 9416 }
9388 9417 if (rfs4_lease_expired(cp)) {
9389 9418 rfs4_client_close(cp);
9390 9419 /*
9391 9420 * Protocol doesn't allow returning NFS4ERR_STALE as
9392 9421 * other operations do on this check so STALE_CLIENTID
9393 9422 * is returned instead
9394 9423 */
9395 9424 *cs->statusp = resp->status = NFS4ERR_STALE_CLIENTID;
9396 9425 goto out;
9397 9426 }
9398 9427
9399 9428 if (rfs4_clnt_in_grace(cp) && !(cp->rc_can_reclaim)) {
9400 9429 *cs->statusp = resp->status = NFS4ERR_GRACE;
9401 9430 rfs4_client_rele(cp);
9402 9431 goto out;
9403 9432 }
9404 9433 rfs4_client_rele(cp);
9405 9434
9406 9435 resp->status = NFS4_OK;
9407 9436
9408 9437 switch (args->locktype) {
9409 9438 case READ_LT:
9410 9439 case READW_LT:
9411 9440 ltype = F_RDLCK;
9412 9441 break;
9413 9442 case WRITE_LT:
9414 9443 case WRITEW_LT:
9415 9444 ltype = F_WRLCK;
9416 9445 break;
9417 9446 }
9418 9447
9419 9448 posix_length = args->length;
9420 9449 /* Check for zero length. To lock to end of file use all ones for V4 */
9421 9450 if (posix_length == 0) {
9422 9451 *cs->statusp = resp->status = NFS4ERR_INVAL;
9423 9452 goto out;
9424 9453 } else if (posix_length == (length4)(~0)) {
9425 9454 posix_length = 0; /* Posix to end of file */
9426 9455 }
9427 9456
9428 9457 /* Find or create a lockowner */
9429 9458 lo = rfs4_findlockowner(&args->owner, &create);
9430 9459
9431 9460 if (lo) {
9432 9461 pid = lo->rl_pid;
9433 9462 if ((resp->status =
9434 9463 rfs4_client_sysid(lo->rl_client, &sysid)) != NFS4_OK)
9435 9464 goto err;
9436 9465 } else {
9437 9466 pid = 0;
9438 9467 sysid = lockt_sysid;
9439 9468 }
9440 9469 retry:
9441 9470 flk.l_type = ltype;
9442 9471 flk.l_whence = 0; /* SEEK_SET */
9443 9472 flk.l_start = args->offset;
9444 9473 flk.l_len = posix_length;
9445 9474 flk.l_sysid = sysid;
9446 9475 flk.l_pid = pid;
9447 9476 flag |= F_REMOTELOCK;
9448 9477
9449 9478 LOCK_PRINT(rfs4_debug, "rfs4_op_lockt", F_GETLK, &flk);
9450 9479
9451 9480 /* Note that length4 is uint64_t but l_len and l_start are off64_t */
9452 9481 if (flk.l_len < 0 || flk.l_start < 0) {
9453 9482 resp->status = NFS4ERR_INVAL;
9454 9483 goto err;
9455 9484 }
9456 9485 error = VOP_FRLOCK(cs->vp, F_GETLK, &flk, flag, (u_offset_t)0,
9457 9486 NULL, cs->cr, NULL);
9458 9487
9459 9488 /*
9460 9489 * N.B. We map error values to nfsv4 errors. This is differrent
9461 9490 * than puterrno4 routine.
9462 9491 */
9463 9492 switch (error) {
9464 9493 case 0:
9465 9494 if (flk.l_type == F_UNLCK)
9466 9495 resp->status = NFS4_OK;
9467 9496 else {
9468 9497 if (lock_denied(&resp->denied, &flk) == NFS4ERR_EXPIRED)
9469 9498 goto retry;
9470 9499 resp->status = NFS4ERR_DENIED;
9471 9500 }
9472 9501 break;
9473 9502 case EOVERFLOW:
9474 9503 resp->status = NFS4ERR_INVAL;
9475 9504 break;
9476 9505 case EINVAL:
9477 9506 resp->status = NFS4ERR_NOTSUPP;
9478 9507 break;
9479 9508 default:
9480 9509 cmn_err(CE_WARN, "rfs4_op_lockt: unexpected errno (%d)",
9481 9510 error);
9482 9511 resp->status = NFS4ERR_SERVERFAULT;
9483 9512 break;
9484 9513 }
9485 9514
9486 9515 err:
9487 9516 if (lo)
9488 9517 rfs4_lockowner_rele(lo);
9489 9518 *cs->statusp = resp->status;
9490 9519 out:
9491 9520 DTRACE_NFSV4_2(op__lockt__done, struct compound_state *, cs,
9492 9521 LOCKT4res *, resp);
9493 9522 }
9494 9523
9495 9524 int
9496 9525 rfs4_share(rfs4_state_t *sp, uint32_t access, uint32_t deny)
9497 9526 {
9498 9527 int err;
9499 9528 int cmd;
9500 9529 vnode_t *vp;
9501 9530 struct shrlock shr;
9502 9531 struct shr_locowner shr_loco;
9503 9532 int fflags = 0;
9504 9533
9505 9534 ASSERT(rfs4_dbe_islocked(sp->rs_dbe));
9506 9535 ASSERT(sp->rs_owner->ro_client->rc_sysidt != LM_NOSYSID);
9507 9536
9508 9537 if (sp->rs_closed)
9509 9538 return (NFS4ERR_OLD_STATEID);
9510 9539
9511 9540 vp = sp->rs_finfo->rf_vp;
9512 9541 ASSERT(vp);
9513 9542
9514 9543 shr.s_access = shr.s_deny = 0;
9515 9544
9516 9545 if (access & OPEN4_SHARE_ACCESS_READ) {
9517 9546 fflags |= FREAD;
9518 9547 shr.s_access |= F_RDACC;
9519 9548 }
9520 9549 if (access & OPEN4_SHARE_ACCESS_WRITE) {
9521 9550 fflags |= FWRITE;
9522 9551 shr.s_access |= F_WRACC;
9523 9552 }
9524 9553 ASSERT(shr.s_access);
9525 9554
9526 9555 if (deny & OPEN4_SHARE_DENY_READ)
9527 9556 shr.s_deny |= F_RDDNY;
9528 9557 if (deny & OPEN4_SHARE_DENY_WRITE)
9529 9558 shr.s_deny |= F_WRDNY;
9530 9559
9531 9560 shr.s_pid = rfs4_dbe_getid(sp->rs_owner->ro_dbe);
9532 9561 shr.s_sysid = sp->rs_owner->ro_client->rc_sysidt;
9533 9562 shr_loco.sl_pid = shr.s_pid;
9534 9563 shr_loco.sl_id = shr.s_sysid;
9535 9564 shr.s_owner = (caddr_t)&shr_loco;
9536 9565 shr.s_own_len = sizeof (shr_loco);
9537 9566
9538 9567 cmd = nbl_need_check(vp) ? F_SHARE_NBMAND : F_SHARE;
9539 9568
9540 9569 err = VOP_SHRLOCK(vp, cmd, &shr, fflags, CRED(), NULL);
9541 9570 if (err != 0) {
9542 9571 if (err == EAGAIN)
9543 9572 err = NFS4ERR_SHARE_DENIED;
9544 9573 else
9545 9574 err = puterrno4(err);
9546 9575 return (err);
9547 9576 }
9548 9577
9549 9578 sp->rs_share_access |= access;
9550 9579 sp->rs_share_deny |= deny;
9551 9580
9552 9581 return (0);
9553 9582 }
9554 9583
9555 9584 int
9556 9585 rfs4_unshare(rfs4_state_t *sp)
9557 9586 {
9558 9587 int err;
9559 9588 struct shrlock shr;
9560 9589 struct shr_locowner shr_loco;
9561 9590
9562 9591 ASSERT(rfs4_dbe_islocked(sp->rs_dbe));
9563 9592
9564 9593 if (sp->rs_closed || sp->rs_share_access == 0)
9565 9594 return (0);
9566 9595
9567 9596 ASSERT(sp->rs_owner->ro_client->rc_sysidt != LM_NOSYSID);
9568 9597 ASSERT(sp->rs_finfo->rf_vp);
9569 9598
9570 9599 shr.s_access = shr.s_deny = 0;
9571 9600 shr.s_pid = rfs4_dbe_getid(sp->rs_owner->ro_dbe);
9572 9601 shr.s_sysid = sp->rs_owner->ro_client->rc_sysidt;
9573 9602 shr_loco.sl_pid = shr.s_pid;
9574 9603 shr_loco.sl_id = shr.s_sysid;
9575 9604 shr.s_owner = (caddr_t)&shr_loco;
9576 9605 shr.s_own_len = sizeof (shr_loco);
9577 9606
9578 9607 err = VOP_SHRLOCK(sp->rs_finfo->rf_vp, F_UNSHARE, &shr, 0, CRED(),
9579 9608 NULL);
9580 9609 if (err != 0) {
9581 9610 err = puterrno4(err);
9582 9611 return (err);
9583 9612 }
9584 9613
9585 9614 sp->rs_share_access = 0;
9586 9615 sp->rs_share_deny = 0;
9587 9616
9588 9617 return (0);
9589 9618
9590 9619 }
9591 9620
9592 9621 static int
9593 9622 rdma_setup_read_data4(READ4args *args, READ4res *rok)
9594 9623 {
9595 9624 struct clist *wcl;
9596 9625 count4 count = rok->data_len;
9597 9626 int wlist_len;
9598 9627
9599 9628 wcl = args->wlist;
9600 9629 if (rdma_setup_read_chunks(wcl, count, &wlist_len) == FALSE) {
9601 9630 return (FALSE);
9602 9631 }
9603 9632 wcl = args->wlist;
9604 9633 rok->wlist_len = wlist_len;
9605 9634 rok->wlist = wcl;
9606 9635 return (TRUE);
9607 9636 }
9608 9637
9609 9638 /* tunable to disable server referrals */
9610 9639 int rfs4_no_referrals = 0;
9611 9640
9612 9641 /*
9613 9642 * Find an NFS record in reparse point data.
9614 9643 * Returns 0 for success and <0 or an errno value on failure.
9615 9644 */
9616 9645 int
9617 9646 vn_find_nfs_record(vnode_t *vp, nvlist_t **nvlp, char **svcp, char **datap)
9618 9647 {
9619 9648 int err;
9620 9649 char *stype, *val;
9621 9650 nvlist_t *nvl;
9622 9651 nvpair_t *curr;
9623 9652
9624 9653 if ((nvl = reparse_init()) == NULL)
9625 9654 return (-1);
9626 9655
9627 9656 if ((err = reparse_vnode_parse(vp, nvl)) != 0) {
9628 9657 reparse_free(nvl);
9629 9658 return (err);
9630 9659 }
9631 9660
9632 9661 curr = NULL;
9633 9662 while ((curr = nvlist_next_nvpair(nvl, curr)) != NULL) {
9634 9663 if ((stype = nvpair_name(curr)) == NULL) {
9635 9664 reparse_free(nvl);
9636 9665 return (-2);
9637 9666 }
9638 9667 if (strncasecmp(stype, "NFS", 3) == 0)
9639 9668 break;
9640 9669 }
9641 9670
9642 9671 if ((curr == NULL) ||
9643 9672 (nvpair_value_string(curr, &val))) {
9644 9673 reparse_free(nvl);
9645 9674 return (-3);
9646 9675 }
9647 9676 *nvlp = nvl;
9648 9677 *svcp = stype;
9649 9678 *datap = val;
9650 9679 return (0);
9651 9680 }
9652 9681
9653 9682 int
9654 9683 vn_is_nfs_reparse(vnode_t *vp, cred_t *cr)
9655 9684 {
9656 9685 nvlist_t *nvl;
9657 9686 char *s, *d;
9658 9687
9659 9688 if (rfs4_no_referrals != 0)
9660 9689 return (B_FALSE);
9661 9690
9662 9691 if (vn_is_reparse(vp, cr, NULL) == B_FALSE)
9663 9692 return (B_FALSE);
9664 9693
9665 9694 if (vn_find_nfs_record(vp, &nvl, &s, &d) != 0)
9666 9695 return (B_FALSE);
9667 9696
9668 9697 reparse_free(nvl);
9669 9698
9670 9699 return (B_TRUE);
9671 9700 }
9672 9701
9673 9702 /*
9674 9703 * There is a user-level copy of this routine in ref_subr.c.
9675 9704 * Changes should be kept in sync.
9676 9705 */
9677 9706 static int
9678 9707 nfs4_create_components(char *path, component4 *comp4)
9679 9708 {
9680 9709 int slen, plen, ncomp;
9681 9710 char *ori_path, *nxtc, buf[MAXNAMELEN];
9682 9711
9683 9712 if (path == NULL)
9684 9713 return (0);
9685 9714
9686 9715 plen = strlen(path) + 1; /* include the terminator */
9687 9716 ori_path = path;
9688 9717 ncomp = 0;
9689 9718
9690 9719 /* count number of components in the path */
9691 9720 for (nxtc = path; nxtc < ori_path + plen; nxtc++) {
9692 9721 if (*nxtc == '/' || *nxtc == '\0' || *nxtc == '\n') {
9693 9722 if ((slen = nxtc - path) == 0) {
9694 9723 path = nxtc + 1;
9695 9724 continue;
9696 9725 }
9697 9726
9698 9727 if (comp4 != NULL) {
9699 9728 bcopy(path, buf, slen);
9700 9729 buf[slen] = '\0';
9701 9730 (void) str_to_utf8(buf, &comp4[ncomp]);
9702 9731 }
9703 9732
9704 9733 ncomp++; /* 1 valid component */
9705 9734 path = nxtc + 1;
9706 9735 }
9707 9736 if (*nxtc == '\0' || *nxtc == '\n')
9708 9737 break;
9709 9738 }
9710 9739
9711 9740 return (ncomp);
9712 9741 }
9713 9742
9714 9743 /*
9715 9744 * There is a user-level copy of this routine in ref_subr.c.
9716 9745 * Changes should be kept in sync.
9717 9746 */
9718 9747 static int
9719 9748 make_pathname4(char *path, pathname4 *pathname)
9720 9749 {
9721 9750 int ncomp;
9722 9751 component4 *comp4;
9723 9752
9724 9753 if (pathname == NULL)
9725 9754 return (0);
9726 9755
9727 9756 if (path == NULL) {
9728 9757 pathname->pathname4_val = NULL;
9729 9758 pathname->pathname4_len = 0;
9730 9759 return (0);
9731 9760 }
9732 9761
9733 9762 /* count number of components to alloc buffer */
9734 9763 if ((ncomp = nfs4_create_components(path, NULL)) == 0) {
9735 9764 pathname->pathname4_val = NULL;
9736 9765 pathname->pathname4_len = 0;
9737 9766 return (0);
9738 9767 }
9739 9768 comp4 = kmem_zalloc(ncomp * sizeof (component4), KM_SLEEP);
9740 9769
9741 9770 /* copy components into allocated buffer */
9742 9771 ncomp = nfs4_create_components(path, comp4);
9743 9772
9744 9773 pathname->pathname4_val = comp4;
9745 9774 pathname->pathname4_len = ncomp;
9746 9775
9747 9776 return (ncomp);
9748 9777 }
9749 9778
9750 9779 #define xdr_fs_locations4 xdr_fattr4_fs_locations
9751 9780
9752 9781 fs_locations4 *
9753 9782 fetch_referral(vnode_t *vp, cred_t *cr)
9754 9783 {
9755 9784 nvlist_t *nvl;
9756 9785 char *stype, *sdata;
9757 9786 fs_locations4 *result;
9758 9787 char buf[1024];
9759 9788 size_t bufsize;
9760 9789 XDR xdr;
9761 9790 int err;
9762 9791
9763 9792 /*
9764 9793 * Check attrs to ensure it's a reparse point
9765 9794 */
9766 9795 if (vn_is_reparse(vp, cr, NULL) == B_FALSE)
9767 9796 return (NULL);
9768 9797
9769 9798 /*
9770 9799 * Look for an NFS record and get the type and data
9771 9800 */
9772 9801 if (vn_find_nfs_record(vp, &nvl, &stype, &sdata) != 0)
9773 9802 return (NULL);
9774 9803
9775 9804 /*
9776 9805 * With the type and data, upcall to get the referral
9777 9806 */
9778 9807 bufsize = sizeof (buf);
9779 9808 bzero(buf, sizeof (buf));
9780 9809 err = reparse_kderef((const char *)stype, (const char *)sdata,
9781 9810 buf, &bufsize);
9782 9811 reparse_free(nvl);
9783 9812
9784 9813 DTRACE_PROBE4(nfs4serv__func__referral__upcall,
9785 9814 char *, stype, char *, sdata, char *, buf, int, err);
9786 9815 if (err) {
9787 9816 cmn_err(CE_NOTE,
9788 9817 "reparsed daemon not running: unable to get referral (%d)",
9789 9818 err);
9790 9819 return (NULL);
9791 9820 }
9792 9821
9793 9822 /*
9794 9823 * We get an XDR'ed record back from the kderef call
9795 9824 */
9796 9825 xdrmem_create(&xdr, buf, bufsize, XDR_DECODE);
9797 9826 result = kmem_alloc(sizeof (fs_locations4), KM_SLEEP);
9798 9827 err = xdr_fs_locations4(&xdr, result);
9799 9828 XDR_DESTROY(&xdr);
9800 9829 if (err != TRUE) {
9801 9830 DTRACE_PROBE1(nfs4serv__func__referral__upcall__xdrfail,
9802 9831 int, err);
9803 9832 return (NULL);
9804 9833 }
9805 9834
9806 9835 /*
9807 9836 * Look at path to recover fs_root, ignoring the leading '/'
9808 9837 */
9809 9838 (void) make_pathname4(vp->v_path, &result->fs_root);
9810 9839
9811 9840 return (result);
9812 9841 }
9813 9842
9814 9843 char *
9815 9844 build_symlink(vnode_t *vp, cred_t *cr, size_t *strsz)
9816 9845 {
9817 9846 fs_locations4 *fsl;
9818 9847 fs_location4 *fs;
9819 9848 char *server, *path, *symbuf;
9820 9849 static char *prefix = "/net/";
9821 9850 int i, size, npaths;
9822 9851 uint_t len;
9823 9852
9824 9853 /* Get the referral */
9825 9854 if ((fsl = fetch_referral(vp, cr)) == NULL)
9826 9855 return (NULL);
9827 9856
9828 9857 /* Deal with only the first location and first server */
9829 9858 fs = &fsl->locations_val[0];
9830 9859 server = utf8_to_str(&fs->server_val[0], &len, NULL);
9831 9860 if (server == NULL) {
9832 9861 rfs4_free_fs_locations4(fsl);
9833 9862 kmem_free(fsl, sizeof (fs_locations4));
9834 9863 return (NULL);
9835 9864 }
9836 9865
9837 9866 /* Figure out size for "/net/" + host + /path/path/path + NULL */
9838 9867 size = strlen(prefix) + len;
9839 9868 for (i = 0; i < fs->rootpath.pathname4_len; i++)
9840 9869 size += fs->rootpath.pathname4_val[i].utf8string_len + 1;
9841 9870
9842 9871 /* Allocate the symlink buffer and fill it */
9843 9872 symbuf = kmem_zalloc(size, KM_SLEEP);
9844 9873 (void) strcat(symbuf, prefix);
9845 9874 (void) strcat(symbuf, server);
9846 9875 kmem_free(server, len);
9847 9876
9848 9877 npaths = 0;
9849 9878 for (i = 0; i < fs->rootpath.pathname4_len; i++) {
9850 9879 path = utf8_to_str(&fs->rootpath.pathname4_val[i], &len, NULL);
9851 9880 if (path == NULL)
9852 9881 continue;
9853 9882 (void) strcat(symbuf, "/");
9854 9883 (void) strcat(symbuf, path);
9855 9884 npaths++;
9856 9885 kmem_free(path, len);
9857 9886 }
9858 9887
9859 9888 rfs4_free_fs_locations4(fsl);
9860 9889 kmem_free(fsl, sizeof (fs_locations4));
9861 9890
9862 9891 if (strsz != NULL)
9863 9892 *strsz = size;
9864 9893 return (symbuf);
9865 9894 }
9866 9895
9867 9896 /*
9868 9897 * Check to see if we have a downrev Solaris client, so that we
9869 9898 * can send it a symlink instead of a referral.
9870 9899 */
9871 9900 int
9872 9901 client_is_downrev(struct svc_req *req)
9873 9902 {
9874 9903 struct sockaddr *ca;
9875 9904 rfs4_clntip_t *ci;
9876 9905 bool_t create = FALSE;
9877 9906 int is_downrev;
9878 9907
9879 9908 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
9880 9909 ASSERT(ca);
9881 9910 ci = rfs4_find_clntip(ca, &create);
9882 9911 if (ci == NULL)
9883 9912 return (0);
9884 9913 is_downrev = ci->ri_no_referrals;
9885 9914 rfs4_dbe_rele(ci->ri_dbe);
9886 9915 return (is_downrev);
9887 9916 }
↓ open down ↓ |
2378 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX