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