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