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 */ 201 if (ct == NULL || (ct->cc_caller_id != nfs4_srv_caller_id)) { 202 fp = (rfs4_file_t *)arg->fa_fnode->fn_available; 203 rfs4_recall_deleg(fp, FALSE, NULL); 204 rfs4_dbe_lock(fp->dbe); 205 while (fp->dinfo->dtype != OPEN_DELEGATE_NONE) { 206 rc = rfs4_dbe_twait(fp->dbe, 207 lbolt + SEC_TO_TICK(rfs4_lease_time)); 208 if (rc == -1) { /* timed out */ 209 rfs4_dbe_unlock(fp->dbe); 210 rfs4_recall_deleg(fp, FALSE, NULL); 211 rfs4_dbe_lock(fp->dbe); 212 } 213 } 214 rfs4_dbe_unlock(fp->dbe); 215 } 216 217 return (vnext_setattr(arg, vap, flags, cr, ct)); 218 } 219 220 221 222 int 223 deleg_rd_rwlock( 224 femarg_t *arg, 225 int write_lock, 226 caller_context_t *ct) 227 { 228 clock_t rc; 229 rfs4_file_t *fp; 230 231 /* 232 * if this is a write lock, then use caller context to compare 233 * caller to delegation owner 234 */ 235 if (write_lock && 236 (ct == NULL || ct->cc_caller_id != nfs4_srv_caller_id)) { 237 fp = (rfs4_file_t *)arg->fa_fnode->fn_available; 238 rfs4_recall_deleg(fp, FALSE, NULL); 239 rfs4_dbe_lock(fp->dbe); 240 while (fp->dinfo->dtype != OPEN_DELEGATE_NONE) { 241 rc = rfs4_dbe_twait(fp->dbe, 242 lbolt + SEC_TO_TICK(rfs4_lease_time)); 243 if (rc == -1) { /* timed out */ 244 rfs4_dbe_unlock(fp->dbe); 245 rfs4_recall_deleg(fp, FALSE, NULL); 246 rfs4_dbe_lock(fp->dbe); 247 } 248 } 249 rfs4_dbe_unlock(fp->dbe); 250 } 251 252 return (vnext_rwlock(arg, write_lock, ct)); 253 } 254 255 int 256 deleg_wr_rwlock( 257 femarg_t *arg, 258 int write_lock, 259 caller_context_t *ct) 260 { 261 clock_t rc; 262 rfs4_file_t *fp; 263 264 /* use caller context to compare caller to delegation owner */ 265 if (ct == NULL || ct->cc_caller_id != nfs4_srv_caller_id) { 266 fp = (rfs4_file_t *)arg->fa_fnode->fn_available; 267 rfs4_recall_deleg(fp, FALSE, NULL); 268 rfs4_dbe_lock(fp->dbe); 269 while (fp->dinfo->dtype != OPEN_DELEGATE_NONE) { 270 rc = rfs4_dbe_twait(fp->dbe, 271 lbolt + SEC_TO_TICK(rfs4_lease_time)); 272 if (rc == -1) { /* timed out */ 273 rfs4_dbe_unlock(fp->dbe); 274 rfs4_recall_deleg(fp, FALSE, NULL); 275 rfs4_dbe_lock(fp->dbe); 276 } 277 } 278 rfs4_dbe_unlock(fp->dbe); 279 } 280 281 return (vnext_rwlock(arg, write_lock, ct)); 282 } 283 284 int 285 deleg_space( 286 femarg_t *arg, 287 int cmd, 288 flock64_t *bfp, 289 int flag, 290 offset_t offset, 291 cred_t *cr, 292 caller_context_t *ct) 293 { 294 clock_t rc; 295 rfs4_file_t *fp; 296 297 /* use caller context to compare caller to delegation owner */ 298 if (ct == NULL || ct->cc_caller_id != nfs4_srv_caller_id) { 299 fp = (rfs4_file_t *)arg->fa_fnode->fn_available; 300 rfs4_recall_deleg(fp, FALSE, NULL); 301 rfs4_dbe_lock(fp->dbe); 302 while (fp->dinfo->dtype != OPEN_DELEGATE_NONE) { 303 rc = rfs4_dbe_twait(fp->dbe, 304 lbolt + SEC_TO_TICK(rfs4_lease_time)); 305 if (rc == -1) { /* timed out */ 306 rfs4_dbe_unlock(fp->dbe); 307 rfs4_recall_deleg(fp, FALSE, NULL); 308 rfs4_dbe_lock(fp->dbe); 309 } 310 } 311 rfs4_dbe_unlock(fp->dbe); 312 } 313 314 return (vnext_space(arg, cmd, bfp, flag, offset, cr, ct)); 315 } 316 317 int 318 deleg_setsecattr( 319 femarg_t *arg, 320 vsecattr_t *vsap, 321 int flag, 322 cred_t *cr) 323 { 324 clock_t rc; 325 rfs4_file_t *fp; 326 327 fp = (rfs4_file_t *)arg->fa_fnode->fn_available; 328 329 /* changing security attribute triggers recall */ 330 rfs4_recall_deleg(fp, FALSE, NULL); 331 rfs4_dbe_lock(fp->dbe); 332 while (fp->dinfo->dtype != OPEN_DELEGATE_NONE) { 333 rc = rfs4_dbe_twait(fp->dbe, 334 lbolt + SEC_TO_TICK(rfs4_lease_time)); 335 if (rc == -1) { /* timed out */ 336 rfs4_dbe_unlock(fp->dbe); 337 rfs4_recall_deleg(fp, FALSE, NULL); 338 rfs4_dbe_lock(fp->dbe); 339 } 340 } 341 rfs4_dbe_unlock(fp->dbe); 342 343 return (vnext_setsecattr(arg, vsap, flag, cr)); 344 } 345 346 /* ARGSUSED */ 347 int 348 deleg_vnevent( 349 femarg_t *arg, 350 vnevent_t vnevent, 351 vnode_t *dvp, 352 char *name) 353 { 354 clock_t rc; 355 rfs4_file_t *fp; 356 bool_t trunc = FALSE; 357 358 switch (vnevent) { 359 case VE_REMOVE: 360 case VE_RENAME_DEST: 361 trunc = TRUE; 362 /*FALLTHROUGH*/ 363 364 case VE_RENAME_SRC: 365 fp = (rfs4_file_t *)arg->fa_fnode->fn_available; 366 rfs4_recall_deleg(fp, trunc, NULL); 367 rfs4_dbe_lock(fp->dbe); 368 while (fp->dinfo->dtype != OPEN_DELEGATE_NONE) { 369 rc = rfs4_dbe_twait(fp->dbe, 370 lbolt + SEC_TO_TICK(rfs4_lease_time)); 371 if (rc == -1) { /* timed out */ 372 rfs4_dbe_unlock(fp->dbe); 373 rfs4_recall_deleg(fp, trunc, NULL); 374 rfs4_dbe_lock(fp->dbe); 375 } 376 } 377 rfs4_dbe_unlock(fp->dbe); 378 break; 379 380 default: 381 break; 382 } 383 return (vnext_vnevent(arg, vnevent, dvp, name)); 384 } 385