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