1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <sys/systm.h> 29 #include <rpc/auth.h> 30 #include <rpc/clnt.h> 31 #include <nfs/nfs4_kprot.h> 32 #include <nfs/nfs4.h> 33 #include <sys/types.h> 34 #include <sys/mutex.h> 35 #include <sys/condvar.h> 36 #include <sys/vfs.h> 37 #include <sys/vnode.h> 38 #include <sys/time.h> 39 #include <sys/fem.h> 40 #include <sys/cmn_err.h> 41 42 43 extern u_longlong_t nfs4_srv_caller_id; 44 45 /* 46 * This file contains the code for the monitors which are placed on the vnodes 47 * of files that are granted delegations by the nfsV4 server. These monitors 48 * will detect local access, as well as access from other servers 49 * (NFS and CIFS), that conflict with the delegations and recall the 50 * delegation from the client before letting the offending operation continue. 51 * 52 * If the caller does not want to block while waiting for the delegation to 53 * be returned, then it should set CC_DONTBLOCK in the flags of caller context. 54 * This does not work for vnevnents; remove and rename, they always block. 55 */ 56 57 /* 58 * This is the function to recall a delegation. It will check if the caller 59 * wishes to block or not while waiting for the delegation to be returned. 60 * If the caller context flag has CC_DONTBLOCK set, then it will return 61 * an error and set CC_WOULDBLOCK instead of waiting for the delegation. 62 */ 63 64 int 65 recall_all_delegations( 66 rfs4_file_t *fp, 67 bool_t trunc, 68 caller_context_t *ct) 69 { 70 clock_t rc; 71 72 rfs4_recall_deleg(fp, trunc, NULL); 73 74 /* optimization that may not stay */ 75 delay(NFS4_DELEGATION_CONFLICT_DELAY); 76 77 /* if it has been returned, we're done. */ 78 rfs4_dbe_lock(fp->dbe); 79 if (fp->dinfo->dtype == OPEN_DELEGATE_NONE) { 80 rfs4_dbe_unlock(fp->dbe); 81 return (0); 82 } 83 84 if (ct != NULL && ct->cc_flags & CC_DONTBLOCK) { 85 rfs4_dbe_unlock(fp->dbe); 86 ct->cc_flags |= CC_WOULDBLOCK; 87 return (NFS4ERR_DELAY); 88 } 89 90 while (fp->dinfo->dtype != OPEN_DELEGATE_NONE) { 91 rc = rfs4_dbe_twait(fp->dbe, 92 lbolt + SEC_TO_TICK(rfs4_lease_time)); 93 if (rc == -1) { /* timed out */ 94 rfs4_dbe_unlock(fp->dbe); 95 rfs4_recall_deleg(fp, trunc, NULL); 96 rfs4_dbe_lock(fp->dbe); 97 } 98 } 99 rfs4_dbe_unlock(fp->dbe); 100 101 return (0); 102 } 103 104 /* monitor for open on read delegated file */ 105 int 106 deleg_rd_open( 107 femarg_t *arg, 108 int mode, 109 cred_t *cr, 110 caller_context_t *ct) 111 { 112 int rc; 113 rfs4_file_t *fp; 114 115 /* 116 * Now that the NFSv4 server calls VOP_OPEN, we need to check to 117 * to make sure it is not us calling open (like for DELEG_CUR) or 118 * we will end up panicing the system. 119 * Since this monitor is for a read delegated file, we know that 120 * only an open for write will cause a conflict. 121 */ 122 if ((ct == NULL || ct->cc_caller_id != nfs4_srv_caller_id) && 123 (mode & (FWRITE|FTRUNC))) { 124 fp = (rfs4_file_t *)arg->fa_fnode->fn_available; 125 rc = recall_all_delegations(fp, FALSE, ct); 126 if (rc == NFS4ERR_DELAY) 127 return (EAGAIN); 128 } 129 130 return (vnext_open(arg, mode, cr, ct)); 131 } 132 133 /* monitor for open on write delegated file */ 134 int 135 deleg_wr_open( 136 femarg_t *arg, 137 int mode, 138 cred_t *cr, 139 caller_context_t *ct) 140 { 141 int rc; 142 rfs4_file_t *fp; 143 144 /* 145 * Now that the NFSv4 server calls VOP_OPEN, we need to check to 146 * to make sure it is not us calling open (like for DELEG_CUR) or 147 * we will end up panicing the system. 148 * Since this monitor is for a write delegated file, we know that 149 * any open will cause a conflict. 150 */ 151 if (ct == NULL || ct->cc_caller_id != nfs4_srv_caller_id) { 152 fp = (rfs4_file_t *)arg->fa_fnode->fn_available; 153 rc = recall_all_delegations(fp, FALSE, ct); 154 if (rc == NFS4ERR_DELAY) 155 return (EAGAIN); 156 } 157 158 return (vnext_open(arg, mode, cr, ct)); 159 } 160 161 /* 162 * This is op is for write delegations only and should only be hit 163 * by the owner of the delegation. If not, then someone is 164 * doing a read without doing an open first. Like from nfs2/3. 165 */ 166 int 167 deleg_wr_read( 168 femarg_t *arg, 169 uio_t *uiop, 170 int ioflag, 171 cred_t *cr, 172 struct caller_context *ct) 173 { 174 int rc; 175 rfs4_file_t *fp; 176 177 /* Use caller context to compare caller to delegation owner */ 178 if (ct == NULL || ct->cc_caller_id != nfs4_srv_caller_id) { 179 fp = (rfs4_file_t *)arg->fa_fnode->fn_available; 180 rc = recall_all_delegations(fp, FALSE, ct); 181 if (rc == NFS4ERR_DELAY) 182 return (EAGAIN); 183 } 184 return (vnext_read(arg, uiop, ioflag, cr, ct)); 185 } 186 187 /* 188 * If someone is doing a write on a read delegated file, it is a conflict. 189 * conflicts should be caught at open, but NFSv2&3 don't use OPEN. 190 */ 191 int 192 deleg_rd_write( 193 femarg_t *arg, 194 uio_t *uiop, 195 int ioflag, 196 cred_t *cr, 197 struct caller_context *ct) 198 { 199 int rc; 200 rfs4_file_t *fp; 201 202 fp = (rfs4_file_t *)arg->fa_fnode->fn_available; 203 rc = recall_all_delegations(fp, FALSE, ct); 204 if (rc == NFS4ERR_DELAY) 205 return (EAGAIN); 206 207 return (vnext_write(arg, uiop, ioflag, cr, ct)); 208 } 209 210 /* 211 * The owner of the delegation can write the file, but nobody else can. 212 * Conflicts should be caught at open, but NFSv2&3 don't use OPEN. 213 */ 214 int 215 deleg_wr_write( 216 femarg_t *arg, 217 uio_t *uiop, 218 int ioflag, 219 cred_t *cr, 220 struct caller_context *ct) 221 { 222 int rc; 223 rfs4_file_t *fp; 224 225 /* Use caller context to compare caller to delegation owner */ 226 if (ct == NULL || ct->cc_caller_id != nfs4_srv_caller_id) { 227 fp = (rfs4_file_t *)arg->fa_fnode->fn_available; 228 rc = recall_all_delegations(fp, FALSE, ct); 229 if (rc == NFS4ERR_DELAY) 230 return (EAGAIN); 231 } 232 return (vnext_write(arg, uiop, ioflag, cr, ct)); 233 } 234 235 /* Doing a setattr on a read delegated file is a conflict. */ 236 int 237 deleg_rd_setattr( 238 femarg_t *arg, 239 vattr_t *vap, 240 int flags, 241 cred_t *cr, 242 caller_context_t *ct) 243 { 244 int rc; 245 bool_t trunc = FALSE; 246 rfs4_file_t *fp; 247 248 if ((vap->va_mask & AT_SIZE) && (vap->va_size == 0)) 249 trunc = TRUE; 250 251 fp = (rfs4_file_t *)arg->fa_fnode->fn_available; 252 rc = recall_all_delegations(fp, trunc, ct); 253 if (rc == NFS4ERR_DELAY) 254 return (EAGAIN); 255 256 return (vnext_setattr(arg, vap, flags, cr, ct)); 257 } 258 259 /* Only the owner of the write delegation can do a setattr */ 260 int 261 deleg_wr_setattr( 262 femarg_t *arg, 263 vattr_t *vap, 264 int flags, 265 cred_t *cr, 266 caller_context_t *ct) 267 { 268 int rc; 269 bool_t trunc = FALSE; 270 rfs4_file_t *fp; 271 272 /* 273 * Use caller context to compare caller to delegation owner 274 */ 275 if (ct == NULL || (ct->cc_caller_id != nfs4_srv_caller_id)) { 276 if ((vap->va_mask & AT_SIZE) && (vap->va_size == 0)) 277 trunc = TRUE; 278 279 fp = (rfs4_file_t *)arg->fa_fnode->fn_available; 280 rc = recall_all_delegations(fp, trunc, ct); 281 if (rc == NFS4ERR_DELAY) 282 return (EAGAIN); 283 } 284 285 return (vnext_setattr(arg, vap, flags, cr, ct)); 286 } 287 288 int 289 deleg_rd_rwlock( 290 femarg_t *arg, 291 int write_lock, 292 caller_context_t *ct) 293 { 294 int rc; 295 rfs4_file_t *fp; 296 297 /* 298 * If this is a write lock, then we got us a conflict. 299 */ 300 if (write_lock) { 301 fp = (rfs4_file_t *)arg->fa_fnode->fn_available; 302 rc = recall_all_delegations(fp, FALSE, ct); 303 if (rc == NFS4ERR_DELAY) 304 return (EAGAIN); 305 } 306 307 return (vnext_rwlock(arg, write_lock, ct)); 308 } 309 310 /* Only the owner of the write delegation should be doing this. */ 311 int 312 deleg_wr_rwlock( 313 femarg_t *arg, 314 int write_lock, 315 caller_context_t *ct) 316 { 317 int rc; 318 rfs4_file_t *fp; 319 320 /* Use caller context to compare caller to delegation owner */ 321 if (ct == NULL || ct->cc_caller_id != nfs4_srv_caller_id) { 322 fp = (rfs4_file_t *)arg->fa_fnode->fn_available; 323 rc = recall_all_delegations(fp, FALSE, ct); 324 if (rc == NFS4ERR_DELAY) 325 return (EAGAIN); 326 } 327 328 return (vnext_rwlock(arg, write_lock, ct)); 329 } 330 331 int 332 deleg_rd_space( 333 femarg_t *arg, 334 int cmd, 335 flock64_t *bfp, 336 int flag, 337 offset_t offset, 338 cred_t *cr, 339 caller_context_t *ct) 340 { 341 int rc; 342 rfs4_file_t *fp; 343 344 fp = (rfs4_file_t *)arg->fa_fnode->fn_available; 345 rc = recall_all_delegations(fp, FALSE, ct); 346 if (rc == NFS4ERR_DELAY) 347 return (EAGAIN); 348 349 return (vnext_space(arg, cmd, bfp, flag, offset, cr, ct)); 350 } 351 352 int 353 deleg_wr_space( 354 femarg_t *arg, 355 int cmd, 356 flock64_t *bfp, 357 int flag, 358 offset_t offset, 359 cred_t *cr, 360 caller_context_t *ct) 361 { 362 int rc; 363 rfs4_file_t *fp; 364 365 /* Use caller context to compare caller to delegation owner */ 366 if (ct == NULL || ct->cc_caller_id != nfs4_srv_caller_id) { 367 fp = (rfs4_file_t *)arg->fa_fnode->fn_available; 368 rc = recall_all_delegations(fp, FALSE, ct); 369 if (rc == NFS4ERR_DELAY) 370 return (EAGAIN); 371 } 372 373 return (vnext_space(arg, cmd, bfp, flag, offset, cr, ct)); 374 } 375 376 int 377 deleg_rd_setsecattr( 378 femarg_t *arg, 379 vsecattr_t *vsap, 380 int flag, 381 cred_t *cr, 382 caller_context_t *ct) 383 { 384 int rc; 385 rfs4_file_t *fp; 386 387 fp = (rfs4_file_t *)arg->fa_fnode->fn_available; 388 389 /* Changing security attribute triggers recall */ 390 rc = recall_all_delegations(fp, FALSE, ct); 391 if (rc == NFS4ERR_DELAY) 392 return (EAGAIN); 393 394 return (vnext_setsecattr(arg, vsap, flag, cr, ct)); 395 } 396 397 int 398 deleg_wr_setsecattr( 399 femarg_t *arg, 400 vsecattr_t *vsap, 401 int flag, 402 cred_t *cr, 403 caller_context_t *ct) 404 { 405 int rc; 406 rfs4_file_t *fp; 407 408 fp = (rfs4_file_t *)arg->fa_fnode->fn_available; 409 410 /* Changing security attribute triggers recall */ 411 rc = recall_all_delegations(fp, FALSE, ct); 412 if (rc == NFS4ERR_DELAY) 413 return (EAGAIN); 414 415 return (vnext_setsecattr(arg, vsap, flag, cr, ct)); 416 } 417 418 int 419 deleg_rd_vnevent( 420 femarg_t *arg, 421 vnevent_t vnevent, 422 vnode_t *dvp, 423 char *name, 424 caller_context_t *ct) 425 { 426 clock_t rc; 427 rfs4_file_t *fp; 428 bool_t trunc = FALSE; 429 430 switch (vnevent) { 431 case VE_REMOVE: 432 case VE_RENAME_DEST: 433 trunc = TRUE; 434 /*FALLTHROUGH*/ 435 436 case VE_RENAME_SRC: 437 fp = (rfs4_file_t *)arg->fa_fnode->fn_available; 438 rfs4_recall_deleg(fp, trunc, NULL); 439 440 rfs4_dbe_lock(fp->dbe); 441 while (fp->dinfo->dtype != OPEN_DELEGATE_NONE) { 442 rc = rfs4_dbe_twait(fp->dbe, 443 lbolt + SEC_TO_TICK(rfs4_lease_time)); 444 if (rc == -1) { /* timed out */ 445 rfs4_dbe_unlock(fp->dbe); 446 rfs4_recall_deleg(fp, trunc, NULL); 447 rfs4_dbe_lock(fp->dbe); 448 } 449 } 450 rfs4_dbe_unlock(fp->dbe); 451 452 break; 453 454 default: 455 break; 456 } 457 return (vnext_vnevent(arg, vnevent, dvp, name, ct)); 458 } 459 460 int 461 deleg_wr_vnevent( 462 femarg_t *arg, 463 vnevent_t vnevent, 464 vnode_t *dvp, 465 char *name, 466 caller_context_t *ct) 467 { 468 clock_t rc; 469 rfs4_file_t *fp; 470 bool_t trunc = FALSE; 471 472 switch (vnevent) { 473 case VE_REMOVE: 474 case VE_RENAME_DEST: 475 trunc = TRUE; 476 /*FALLTHROUGH*/ 477 478 case VE_RENAME_SRC: 479 fp = (rfs4_file_t *)arg->fa_fnode->fn_available; 480 rfs4_recall_deleg(fp, trunc, NULL); 481 rfs4_dbe_lock(fp->dbe); 482 while (fp->dinfo->dtype != OPEN_DELEGATE_NONE) { 483 rc = rfs4_dbe_twait(fp->dbe, 484 lbolt + SEC_TO_TICK(rfs4_lease_time)); 485 if (rc == -1) { /* timed out */ 486 rfs4_dbe_unlock(fp->dbe); 487 rfs4_recall_deleg(fp, trunc, NULL); 488 rfs4_dbe_lock(fp->dbe); 489 } 490 } 491 rfs4_dbe_unlock(fp->dbe); 492 493 break; 494 495 default: 496 break; 497 } 498 return (vnext_vnevent(arg, vnevent, dvp, name, ct)); 499 } 500