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