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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/systm.h> 30 #include <rpc/auth.h> 31 #include <rpc/clnt.h> 32 #include <nfs/nfs4_kprot.h> 33 #include <nfs/nfs4.h> 34 #include <sys/types.h> 35 #include <sys/mutex.h> 36 #include <sys/condvar.h> 37 #include <sys/vfs.h> 38 #include <sys/vnode.h> 39 #include <sys/time.h> 40 #include <sys/fem.h> 41 #include <sys/cmn_err.h> 42 43 44 extern u_longlong_t nfs4_srv_caller_id; 45 46 /* 47 * This file contains the code for the monitors which are placed on the vnodes 48 * of files that are granted delegations by the nfsV4 server. These monitors 49 * will detect local access that conflict with the delegations and recall the 50 * delegation from the client before letting the offending operation continue. 51 */ 52 53 /* monitor for open on read delegated file */ 54 int 55 deleg_rdopen( 56 femarg_t *arg, 57 int mode, 58 cred_t *cr) 59 { 60 clock_t rc; 61 rfs4_file_t *fp; 62 63 /* 64 * Since this monitor is for a read delegated file, we know that 65 * only an open for write will cause a conflict. 66 */ 67 if (mode & (FWRITE|FTRUNC)) { 68 fp = (rfs4_file_t *)arg->fa_fnode->fn_available; 69 rfs4_recall_deleg(fp, FALSE, NULL); 70 rfs4_dbe_lock(fp->dbe); 71 while (fp->dinfo->dtype != OPEN_DELEGATE_NONE) { 72 rc = rfs4_dbe_twait(fp->dbe, 73 lbolt + SEC_TO_TICK(rfs4_lease_time)); 74 if (rc == -1) { /* timed out */ 75 rfs4_dbe_unlock(fp->dbe); 76 rfs4_recall_deleg(fp, FALSE, NULL); 77 rfs4_dbe_lock(fp->dbe); 78 } 79 } 80 rfs4_dbe_unlock(fp->dbe); 81 } 82 83 return (vnext_open(arg, mode, cr)); 84 } 85 86 /* monitor for open on write delegated file */ 87 int 88 deleg_wropen( 89 femarg_t *arg, 90 int mode, 91 cred_t *cr) 92 { 93 clock_t rc; 94 rfs4_file_t *fp; 95 96 fp = (rfs4_file_t *)arg->fa_fnode->fn_available; 97 98 /* 99 * Since this monitor is for a write delegated file, we know that 100 * any open will cause a conflict. 101 */ 102 rfs4_recall_deleg(fp, FALSE, NULL); 103 rfs4_dbe_lock(fp->dbe); 104 while (fp->dinfo->dtype != OPEN_DELEGATE_NONE) { 105 rc = rfs4_dbe_twait(fp->dbe, 106 lbolt + SEC_TO_TICK(rfs4_lease_time)); 107 if (rc == -1) { /* timed out */ 108 rfs4_dbe_unlock(fp->dbe); 109 rfs4_recall_deleg(fp, FALSE, NULL); 110 rfs4_dbe_lock(fp->dbe); 111 } 112 } 113 rfs4_dbe_unlock(fp->dbe); 114 115 return (vnext_open(arg, mode, cr)); 116 } 117 118 /* 119 * this is only a write delegation op and should only be hit 120 * by the owner of the delegation. if not, then someone is 121 * doing a read without doing an open first. shouldn't happen. 122 */ 123 int 124 deleg_read( 125 femarg_t *arg, 126 uio_t *uiop, 127 int ioflag, 128 cred_t *cr, 129 struct caller_context *ct) 130 { 131 clock_t rc; 132 rfs4_file_t *fp; 133 134 /* use caller context to compare caller to delegation owner */ 135 if (ct == NULL || ct->cc_caller_id != nfs4_srv_caller_id) { 136 fp = (rfs4_file_t *)arg->fa_fnode->fn_available; 137 rfs4_recall_deleg(fp, FALSE, NULL); 138 rfs4_dbe_lock(fp->dbe); 139 while (fp->dinfo->dtype != OPEN_DELEGATE_NONE) { 140 rc = rfs4_dbe_twait(fp->dbe, 141 lbolt + SEC_TO_TICK(rfs4_lease_time)); 142 if (rc == -1) { /* timed out */ 143 rfs4_dbe_unlock(fp->dbe); 144 rfs4_recall_deleg(fp, FALSE, NULL); 145 rfs4_dbe_lock(fp->dbe); 146 } 147 } 148 rfs4_dbe_unlock(fp->dbe); 149 } 150 return (vnext_read(arg, uiop, ioflag, cr, ct)); 151 } 152 153 /* 154 * this should only be hit by the owner of the delegation. if not, then 155 * someone is doing a write without doing an open first. shouldn't happen. 156 */ 157 int 158 deleg_write( 159 femarg_t *arg, 160 uio_t *uiop, 161 int ioflag, 162 cred_t *cr, 163 struct caller_context *ct) 164 { 165 clock_t rc; 166 rfs4_file_t *fp; 167 168 /* use caller context to compare caller to delegation owner */ 169 if (ct == NULL || ct->cc_caller_id != nfs4_srv_caller_id) { 170 fp = (rfs4_file_t *)arg->fa_fnode->fn_available; 171 rfs4_recall_deleg(fp, FALSE, NULL); 172 rfs4_dbe_lock(fp->dbe); 173 while (fp->dinfo->dtype != OPEN_DELEGATE_NONE) { 174 rc = rfs4_dbe_twait(fp->dbe, 175 lbolt + SEC_TO_TICK(rfs4_lease_time)); 176 if (rc == -1) { /* timed out */ 177 rfs4_dbe_unlock(fp->dbe); 178 rfs4_recall_deleg(fp, FALSE, NULL); 179 rfs4_dbe_lock(fp->dbe); 180 } 181 } 182 rfs4_dbe_unlock(fp->dbe); 183 } 184 return (vnext_write(arg, uiop, ioflag, cr, ct)); 185 } 186 187 188 int 189 deleg_setattr( 190 femarg_t *arg, 191 vattr_t *vap, 192 int flags, 193 cred_t *cr, 194 caller_context_t *ct) 195 { 196 clock_t rc; 197 rfs4_file_t *fp; 198 199 /* 200 * use caller context to compare caller to delegation owner 201 * and if (changing mode, owner, group, or size) 202 */ 203 if ((vap->va_mask & (AT_MODE|AT_UID|AT_GID|AT_SIZE)) && 204 (ct == NULL || (ct->cc_caller_id != nfs4_srv_caller_id))) { 205 fp = (rfs4_file_t *)arg->fa_fnode->fn_available; 206 rfs4_recall_deleg(fp, FALSE, NULL); 207 rfs4_dbe_lock(fp->dbe); 208 while (fp->dinfo->dtype != OPEN_DELEGATE_NONE) { 209 rc = rfs4_dbe_twait(fp->dbe, 210 lbolt + SEC_TO_TICK(rfs4_lease_time)); 211 if (rc == -1) { /* timed out */ 212 rfs4_dbe_unlock(fp->dbe); 213 rfs4_recall_deleg(fp, FALSE, NULL); 214 rfs4_dbe_lock(fp->dbe); 215 } 216 } 217 rfs4_dbe_unlock(fp->dbe); 218 } 219 220 return (vnext_setattr(arg, vap, flags, cr, ct)); 221 } 222 223 224 225 int 226 deleg_rd_rwlock( 227 femarg_t *arg, 228 int write_lock, 229 caller_context_t *ct) 230 { 231 clock_t rc; 232 rfs4_file_t *fp; 233 234 /* 235 * if this is a write lock, then use caller context to compare 236 * caller to delegation owner 237 */ 238 if (write_lock && 239 (ct == NULL || ct->cc_caller_id != nfs4_srv_caller_id)) { 240 fp = (rfs4_file_t *)arg->fa_fnode->fn_available; 241 rfs4_recall_deleg(fp, FALSE, NULL); 242 rfs4_dbe_lock(fp->dbe); 243 while (fp->dinfo->dtype != OPEN_DELEGATE_NONE) { 244 rc = rfs4_dbe_twait(fp->dbe, 245 lbolt + SEC_TO_TICK(rfs4_lease_time)); 246 if (rc == -1) { /* timed out */ 247 rfs4_dbe_unlock(fp->dbe); 248 rfs4_recall_deleg(fp, FALSE, NULL); 249 rfs4_dbe_lock(fp->dbe); 250 } 251 } 252 rfs4_dbe_unlock(fp->dbe); 253 } 254 255 return (vnext_rwlock(arg, write_lock, ct)); 256 } 257 258 int 259 deleg_wr_rwlock( 260 femarg_t *arg, 261 int write_lock, 262 caller_context_t *ct) 263 { 264 clock_t rc; 265 rfs4_file_t *fp; 266 267 /* use caller context to compare caller to delegation owner */ 268 if (ct == NULL || ct->cc_caller_id != nfs4_srv_caller_id) { 269 fp = (rfs4_file_t *)arg->fa_fnode->fn_available; 270 rfs4_recall_deleg(fp, FALSE, NULL); 271 rfs4_dbe_lock(fp->dbe); 272 while (fp->dinfo->dtype != OPEN_DELEGATE_NONE) { 273 rc = rfs4_dbe_twait(fp->dbe, 274 lbolt + SEC_TO_TICK(rfs4_lease_time)); 275 if (rc == -1) { /* timed out */ 276 rfs4_dbe_unlock(fp->dbe); 277 rfs4_recall_deleg(fp, FALSE, NULL); 278 rfs4_dbe_lock(fp->dbe); 279 } 280 } 281 rfs4_dbe_unlock(fp->dbe); 282 } 283 284 return (vnext_rwlock(arg, write_lock, ct)); 285 } 286 287 int 288 deleg_space( 289 femarg_t *arg, 290 int cmd, 291 flock64_t *bfp, 292 int flag, 293 offset_t offset, 294 cred_t *cr, 295 caller_context_t *ct) 296 { 297 clock_t rc; 298 rfs4_file_t *fp; 299 300 /* use caller context to compare caller to delegation owner */ 301 if (ct == NULL || ct->cc_caller_id != nfs4_srv_caller_id) { 302 fp = (rfs4_file_t *)arg->fa_fnode->fn_available; 303 rfs4_recall_deleg(fp, FALSE, NULL); 304 rfs4_dbe_lock(fp->dbe); 305 while (fp->dinfo->dtype != OPEN_DELEGATE_NONE) { 306 rc = rfs4_dbe_twait(fp->dbe, 307 lbolt + SEC_TO_TICK(rfs4_lease_time)); 308 if (rc == -1) { /* timed out */ 309 rfs4_dbe_unlock(fp->dbe); 310 rfs4_recall_deleg(fp, FALSE, NULL); 311 rfs4_dbe_lock(fp->dbe); 312 } 313 } 314 rfs4_dbe_unlock(fp->dbe); 315 } 316 317 return (vnext_space(arg, cmd, bfp, flag, offset, cr, ct)); 318 } 319 320 int 321 deleg_setsecattr( 322 femarg_t *arg, 323 vsecattr_t *vsap, 324 int flag, 325 cred_t *cr) 326 { 327 clock_t rc; 328 rfs4_file_t *fp; 329 330 fp = (rfs4_file_t *)arg->fa_fnode->fn_available; 331 332 /* changing security attribute triggers recall */ 333 rfs4_recall_deleg(fp, FALSE, NULL); 334 rfs4_dbe_lock(fp->dbe); 335 while (fp->dinfo->dtype != OPEN_DELEGATE_NONE) { 336 rc = rfs4_dbe_twait(fp->dbe, 337 lbolt + SEC_TO_TICK(rfs4_lease_time)); 338 if (rc == -1) { /* timed out */ 339 rfs4_dbe_unlock(fp->dbe); 340 rfs4_recall_deleg(fp, FALSE, NULL); 341 rfs4_dbe_lock(fp->dbe); 342 } 343 } 344 rfs4_dbe_unlock(fp->dbe); 345 346 return (vnext_setsecattr(arg, vsap, flag, cr)); 347 } 348 349 int 350 deleg_vnevent( 351 femarg_t *arg, 352 vnevent_t vnevent) 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)); 384 } 385