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 that conflict with the delegations and recall the 49 * delegation from the client before letting the offending operation continue. 50 */ 51 52 /* monitor for open on read delegated file */ 53 int 54 deleg_rdopen( 55 femarg_t *arg, 56 int mode, 57 cred_t *cr) 58 { 59 clock_t rc; 60 rfs4_file_t *fp; 61 62 /* 63 * Since this monitor is for a read delegated file, we know that 64 * only an open for write will cause a conflict. 65 */ 66 if (mode & (FWRITE|FTRUNC)) { 67 fp = (rfs4_file_t *)arg->fa_fnode->fn_available; 68 rfs4_recall_deleg(fp, FALSE, NULL); 69 rfs4_dbe_lock(fp->dbe); 70 while (fp->dinfo->dtype != OPEN_DELEGATE_NONE) { 71 rc = rfs4_dbe_twait(fp->dbe, 72 lbolt + SEC_TO_TICK(rfs4_lease_time)); 73 if (rc == -1) { /* timed out */ 74 rfs4_dbe_unlock(fp->dbe); 75 rfs4_recall_deleg(fp, FALSE, NULL); 76 rfs4_dbe_lock(fp->dbe); 77 } 78 } 79 rfs4_dbe_unlock(fp->dbe); 80 } 81 82 return (vnext_open(arg, mode, cr)); 83 } 84 85 /* monitor for open on write delegated file */ 86 int 87 deleg_wropen( 88 femarg_t *arg, 89 int mode, 90 cred_t *cr) 91 { 92 clock_t rc; 93 rfs4_file_t *fp; 94 95 fp = (rfs4_file_t *)arg->fa_fnode->fn_available; 96 97 /* 98 * Since this monitor is for a write delegated file, we know that 99 * any open will cause a conflict. 100 */ 101 rfs4_recall_deleg(fp, FALSE, NULL); 102 rfs4_dbe_lock(fp->dbe); 103 while (fp->dinfo->dtype != OPEN_DELEGATE_NONE) { 104 rc = rfs4_dbe_twait(fp->dbe, 105 lbolt + SEC_TO_TICK(rfs4_lease_time)); 106 if (rc == -1) { /* timed out */ 107 rfs4_dbe_unlock(fp->dbe); 108 rfs4_recall_deleg(fp, FALSE, NULL); 109 rfs4_dbe_lock(fp->dbe); 110 } 111 } 112 rfs4_dbe_unlock(fp->dbe); 113 114 return (vnext_open(arg, mode, cr)); 115 } 116 117 /* 118 * this is only a write delegation op and should only be hit 119 * by the owner of the delegation. if not, then someone is 120 * doing a read without doing an open first. shouldn't happen. 121 */ 122 int 123 deleg_read( 124 femarg_t *arg, 125 uio_t *uiop, 126 int ioflag, 127 cred_t *cr, 128 struct caller_context *ct) 129 { 130 clock_t rc; 131 rfs4_file_t *fp; 132 133 /* use caller context to compare caller to delegation owner */ 134 if (ct == NULL || ct->cc_caller_id != nfs4_srv_caller_id) { 135 fp = (rfs4_file_t *)arg->fa_fnode->fn_available; 136 rfs4_recall_deleg(fp, FALSE, NULL); 137 rfs4_dbe_lock(fp->dbe); 138 while (fp->dinfo->dtype != OPEN_DELEGATE_NONE) { 139 rc = rfs4_dbe_twait(fp->dbe, 140 lbolt + SEC_TO_TICK(rfs4_lease_time)); 141 if (rc == -1) { /* timed out */ 142 rfs4_dbe_unlock(fp->dbe); 143 rfs4_recall_deleg(fp, FALSE, NULL); 144 rfs4_dbe_lock(fp->dbe); 145 } 146 } 147 rfs4_dbe_unlock(fp->dbe); 148 } 149 return (vnext_read(arg, uiop, ioflag, cr, ct)); 150 } 151 152 /* 153 * this should only be hit by the owner of the delegation. if not, then 154 * someone is doing a write without doing an open first. shouldn't happen. 155 */ 156 int 157 deleg_write( 158 femarg_t *arg, 159 uio_t *uiop, 160 int ioflag, 161 cred_t *cr, 162 struct caller_context *ct) 163 { 164 clock_t rc; 165 rfs4_file_t *fp; 166 167 /* use caller context to compare caller to delegation owner */ 168 if (ct == NULL || ct->cc_caller_id != nfs4_srv_caller_id) { 169 fp = (rfs4_file_t *)arg->fa_fnode->fn_available; 170 rfs4_recall_deleg(fp, FALSE, NULL); 171 rfs4_dbe_lock(fp->dbe); 172 while (fp->dinfo->dtype != OPEN_DELEGATE_NONE) { 173 rc = rfs4_dbe_twait(fp->dbe, 174 lbolt + SEC_TO_TICK(rfs4_lease_time)); 175 if (rc == -1) { /* timed out */ 176 rfs4_dbe_unlock(fp->dbe); 177 rfs4_recall_deleg(fp, FALSE, NULL); 178 rfs4_dbe_lock(fp->dbe); 179 } 180 } 181 rfs4_dbe_unlock(fp->dbe); 182 } 183 return (vnext_write(arg, uiop, ioflag, cr, ct)); 184 } 185 186 187 int 188 deleg_setattr( 189 femarg_t *arg, 190 vattr_t *vap, 191 int flags, 192 cred_t *cr, 193 caller_context_t *ct) 194 { 195 clock_t rc; 196 rfs4_file_t *fp; 197 198 /* 199 * use caller context to compare caller to delegation owner 200 * and if (changing mode, owner, group, or size) 201 */ 202 if ((vap->va_mask & (AT_MODE|AT_UID|AT_GID|AT_SIZE)) && 203 (ct == NULL || (ct->cc_caller_id != nfs4_srv_caller_id))) { 204 fp = (rfs4_file_t *)arg->fa_fnode->fn_available; 205 rfs4_recall_deleg(fp, FALSE, NULL); 206 rfs4_dbe_lock(fp->dbe); 207 while (fp->dinfo->dtype != OPEN_DELEGATE_NONE) { 208 rc = rfs4_dbe_twait(fp->dbe, 209 lbolt + SEC_TO_TICK(rfs4_lease_time)); 210 if (rc == -1) { /* timed out */ 211 rfs4_dbe_unlock(fp->dbe); 212 rfs4_recall_deleg(fp, FALSE, NULL); 213 rfs4_dbe_lock(fp->dbe); 214 } 215 } 216 rfs4_dbe_unlock(fp->dbe); 217 } 218 219 return (vnext_setattr(arg, vap, flags, cr, ct)); 220 } 221 222 223 224 int 225 deleg_rd_rwlock( 226 femarg_t *arg, 227 int write_lock, 228 caller_context_t *ct) 229 { 230 clock_t rc; 231 rfs4_file_t *fp; 232 233 /* 234 * if this is a write lock, then use caller context to compare 235 * caller to delegation owner 236 */ 237 if (write_lock && 238 (ct == NULL || ct->cc_caller_id != nfs4_srv_caller_id)) { 239 fp = (rfs4_file_t *)arg->fa_fnode->fn_available; 240 rfs4_recall_deleg(fp, FALSE, NULL); 241 rfs4_dbe_lock(fp->dbe); 242 while (fp->dinfo->dtype != OPEN_DELEGATE_NONE) { 243 rc = rfs4_dbe_twait(fp->dbe, 244 lbolt + SEC_TO_TICK(rfs4_lease_time)); 245 if (rc == -1) { /* timed out */ 246 rfs4_dbe_unlock(fp->dbe); 247 rfs4_recall_deleg(fp, FALSE, NULL); 248 rfs4_dbe_lock(fp->dbe); 249 } 250 } 251 rfs4_dbe_unlock(fp->dbe); 252 } 253 254 return (vnext_rwlock(arg, write_lock, ct)); 255 } 256 257 int 258 deleg_wr_rwlock( 259 femarg_t *arg, 260 int write_lock, 261 caller_context_t *ct) 262 { 263 clock_t rc; 264 rfs4_file_t *fp; 265 266 /* use caller context to compare caller to delegation owner */ 267 if (ct == NULL || ct->cc_caller_id != nfs4_srv_caller_id) { 268 fp = (rfs4_file_t *)arg->fa_fnode->fn_available; 269 rfs4_recall_deleg(fp, FALSE, NULL); 270 rfs4_dbe_lock(fp->dbe); 271 while (fp->dinfo->dtype != OPEN_DELEGATE_NONE) { 272 rc = rfs4_dbe_twait(fp->dbe, 273 lbolt + SEC_TO_TICK(rfs4_lease_time)); 274 if (rc == -1) { /* timed out */ 275 rfs4_dbe_unlock(fp->dbe); 276 rfs4_recall_deleg(fp, FALSE, NULL); 277 rfs4_dbe_lock(fp->dbe); 278 } 279 } 280 rfs4_dbe_unlock(fp->dbe); 281 } 282 283 return (vnext_rwlock(arg, write_lock, ct)); 284 } 285 286 int 287 deleg_space( 288 femarg_t *arg, 289 int cmd, 290 flock64_t *bfp, 291 int flag, 292 offset_t offset, 293 cred_t *cr, 294 caller_context_t *ct) 295 { 296 clock_t rc; 297 rfs4_file_t *fp; 298 299 /* use caller context to compare caller to delegation owner */ 300 if (ct == NULL || ct->cc_caller_id != nfs4_srv_caller_id) { 301 fp = (rfs4_file_t *)arg->fa_fnode->fn_available; 302 rfs4_recall_deleg(fp, FALSE, NULL); 303 rfs4_dbe_lock(fp->dbe); 304 while (fp->dinfo->dtype != OPEN_DELEGATE_NONE) { 305 rc = rfs4_dbe_twait(fp->dbe, 306 lbolt + SEC_TO_TICK(rfs4_lease_time)); 307 if (rc == -1) { /* timed out */ 308 rfs4_dbe_unlock(fp->dbe); 309 rfs4_recall_deleg(fp, FALSE, NULL); 310 rfs4_dbe_lock(fp->dbe); 311 } 312 } 313 rfs4_dbe_unlock(fp->dbe); 314 } 315 316 return (vnext_space(arg, cmd, bfp, flag, offset, cr, ct)); 317 } 318 319 int 320 deleg_setsecattr( 321 femarg_t *arg, 322 vsecattr_t *vsap, 323 int flag, 324 cred_t *cr) 325 { 326 clock_t rc; 327 rfs4_file_t *fp; 328 329 fp = (rfs4_file_t *)arg->fa_fnode->fn_available; 330 331 /* changing security attribute triggers recall */ 332 rfs4_recall_deleg(fp, FALSE, NULL); 333 rfs4_dbe_lock(fp->dbe); 334 while (fp->dinfo->dtype != OPEN_DELEGATE_NONE) { 335 rc = rfs4_dbe_twait(fp->dbe, 336 lbolt + SEC_TO_TICK(rfs4_lease_time)); 337 if (rc == -1) { /* timed out */ 338 rfs4_dbe_unlock(fp->dbe); 339 rfs4_recall_deleg(fp, FALSE, NULL); 340 rfs4_dbe_lock(fp->dbe); 341 } 342 } 343 rfs4_dbe_unlock(fp->dbe); 344 345 return (vnext_setsecattr(arg, vsap, flag, cr)); 346 } 347 348 /* ARGSUSED */ 349 int 350 deleg_vnevent( 351 femarg_t *arg, 352 vnevent_t vnevent, 353 vnode_t *dvp, 354 char *name) 355 { 356 clock_t rc; 357 rfs4_file_t *fp; 358 bool_t trunc = FALSE; 359 360 switch (vnevent) { 361 case VE_REMOVE: 362 case VE_RENAME_DEST: 363 trunc = TRUE; 364 /*FALLTHROUGH*/ 365 366 case VE_RENAME_SRC: 367 fp = (rfs4_file_t *)arg->fa_fnode->fn_available; 368 rfs4_recall_deleg(fp, trunc, NULL); 369 rfs4_dbe_lock(fp->dbe); 370 while (fp->dinfo->dtype != OPEN_DELEGATE_NONE) { 371 rc = rfs4_dbe_twait(fp->dbe, 372 lbolt + SEC_TO_TICK(rfs4_lease_time)); 373 if (rc == -1) { /* timed out */ 374 rfs4_dbe_unlock(fp->dbe); 375 rfs4_recall_deleg(fp, trunc, NULL); 376 rfs4_dbe_lock(fp->dbe); 377 } 378 } 379 rfs4_dbe_unlock(fp->dbe); 380 break; 381 382 default: 383 break; 384 } 385 return (vnext_vnevent(arg, vnevent, dvp, name)); 386 } 387