void smb_fem_oplock_uninstall(smb_node_t *node) { if (smb_oplock_ops == NULL) return; VERIFY0(fem_uninstall(node->vp, smb_oplock_ops, (void *)node)); }
void smb_fem_oplock_uninstall(smb_node_t *node) { (void) fem_uninstall(node->vp, smb_oplock_ops, (void *)node); }
void smb_fem_fcn_uninstall(smb_node_t *node) { (void) fem_uninstall(node->vp, smb_fcn_ops, (void *)node); }
/* * State routine for the server when a delegation is returned. */ void rfs4_return_deleg(rfs4_deleg_state_t *dsp, bool_t revoked) { rfs4_file_t *fp = dsp->rds_finfo; open_delegation_type4 dtypewas; rfs4_dbe_lock(fp->rf_dbe); /* nothing to do if no longer on list */ if (!list_link_active(&dsp->rds_node)) { rfs4_dbe_unlock(fp->rf_dbe); return; } /* Remove state from recall list */ list_remove(&fp->rf_delegstatelist, dsp); if (list_is_empty(&fp->rf_delegstatelist)) { dtypewas = fp->rf_dinfo.rd_dtype; fp->rf_dinfo.rd_dtype = OPEN_DELEGATE_NONE; rfs4_dbe_cv_broadcast(fp->rf_dbe); /* if file system was unshared, the vp will be NULL */ if (fp->rf_vp != NULL) { /* * Once a delegation is no longer held by any client, * the monitor is uninstalled. At this point, the * client must send OPEN otw, so we don't need the * reference on the vnode anymore. The open * downgrade removes the reference put on earlier. */ if (dtypewas == OPEN_DELEGATE_READ) { (void) fem_uninstall(fp->rf_vp, deleg_rdops, (void *)fp); vn_open_downgrade(fp->rf_vp, FREAD); } else if (dtypewas == OPEN_DELEGATE_WRITE) { (void) fem_uninstall(fp->rf_vp, deleg_wrops, (void *)fp); vn_open_downgrade(fp->rf_vp, FREAD|FWRITE); } } } switch (dsp->rds_dtype) { case OPEN_DELEGATE_READ: fp->rf_dinfo.rd_rdgrants--; break; case OPEN_DELEGATE_WRITE: fp->rf_dinfo.rd_wrgrants--; break; default: break; } /* used in the policy decision */ fp->rf_dinfo.rd_time_returned = gethrestime_sec(); /* * reset the time_recalled field so future delegations are not * accidentally revoked */ if ((fp->rf_dinfo.rd_rdgrants + fp->rf_dinfo.rd_wrgrants) == 0) fp->rf_dinfo.rd_time_recalled = 0; rfs4_dbe_unlock(fp->rf_dbe); rfs4_dbe_lock(dsp->rds_dbe); dsp->rds_dtype = OPEN_DELEGATE_NONE; if (revoked == TRUE) dsp->rds_time_revoked = gethrestime_sec(); rfs4_dbe_invalidate(dsp->rds_dbe); rfs4_dbe_unlock(dsp->rds_dbe); if (revoked == TRUE) { rfs4_dbe_lock(dsp->rds_client->rc_dbe); dsp->rds_client->rc_deleg_revoked++; /* observability */ rfs4_dbe_unlock(dsp->rds_client->rc_dbe); } }
/* * State support for delegation. * Set the state delegation type for this state; * This routine is called from open via rfs4_grant_delegation and the entry * locks on sp and sp->rs_finfo are assumed. */ static rfs4_deleg_state_t * rfs4_deleg_state(rfs4_state_t *sp, open_delegation_type4 dtype, int *recall) { rfs4_file_t *fp = sp->rs_finfo; bool_t create = TRUE; rfs4_deleg_state_t *dsp; vnode_t *vp; int open_prev = *recall; int ret; int fflags = 0; ASSERT(rfs4_dbe_islocked(sp->rs_dbe)); ASSERT(rfs4_dbe_islocked(fp->rf_dbe)); /* Shouldn't happen */ if (fp->rf_dinfo.rd_recall_count != 0 || (fp->rf_dinfo.rd_dtype == OPEN_DELEGATE_READ && dtype != OPEN_DELEGATE_READ)) { return (NULL); } /* Unlock to avoid deadlock */ rfs4_dbe_unlock(fp->rf_dbe); rfs4_dbe_unlock(sp->rs_dbe); dsp = rfs4_finddeleg(sp, &create); rfs4_dbe_lock(sp->rs_dbe); rfs4_dbe_lock(fp->rf_dbe); if (dsp == NULL) return (NULL); /* * It is possible that since we dropped the lock * in order to call finddeleg, the rfs4_file_t * was marked such that we should not grant a * delegation, if so bail out. */ if (fp->rf_dinfo.rd_hold_grant > 0) { rfs4_deleg_state_rele(dsp); return (NULL); } if (create == FALSE) { if (sp->rs_owner->ro_client == dsp->rds_client && dsp->rds_dtype == dtype) { return (dsp); } else { rfs4_deleg_state_rele(dsp); return (NULL); } } /* * Check that this file has not been delegated to another * client */ if (fp->rf_dinfo.rd_recall_count != 0 || fp->rf_dinfo.rd_dtype == OPEN_DELEGATE_WRITE || (fp->rf_dinfo.rd_dtype == OPEN_DELEGATE_READ && dtype != OPEN_DELEGATE_READ)) { rfs4_deleg_state_rele(dsp); return (NULL); } vp = fp->rf_vp; /* vnevent_support returns 0 if file system supports vnevents */ if (vnevent_support(vp, NULL)) { rfs4_deleg_state_rele(dsp); return (NULL); } /* Calculate the fflags for this OPEN. */ if (sp->rs_share_access & OPEN4_SHARE_ACCESS_READ) fflags |= FREAD; if (sp->rs_share_access & OPEN4_SHARE_ACCESS_WRITE) fflags |= FWRITE; *recall = 0; /* * Before granting a delegation we need to know if anyone else has * opened the file in a conflicting mode. However, first we need to * know how we opened the file to check the counts properly. */ if (dtype == OPEN_DELEGATE_READ) { if (((fflags & FWRITE) && vn_has_other_opens(vp, V_WRITE)) || (((fflags & FWRITE) == 0) && vn_is_opened(vp, V_WRITE)) || vn_is_mapped(vp, V_WRITE)) { if (open_prev) { *recall = 1; } else { rfs4_deleg_state_rele(dsp); return (NULL); } } ret = fem_install(vp, deleg_rdops, (void *)fp, OPUNIQ, rfs4_mon_hold, rfs4_mon_rele); if (((fflags & FWRITE) && vn_has_other_opens(vp, V_WRITE)) || (((fflags & FWRITE) == 0) && vn_is_opened(vp, V_WRITE)) || vn_is_mapped(vp, V_WRITE)) { if (open_prev) { *recall = 1; } else { (void) fem_uninstall(vp, deleg_rdops, (void *)fp); rfs4_deleg_state_rele(dsp); return (NULL); } } /* * Because a client can hold onto a delegation after the * file has been closed, we need to keep track of the * access to this file. Otherwise the CIFS server would * not know about the client accessing the file and could * inappropriately grant an OPLOCK. * fem_install() returns EBUSY when asked to install a * OPUNIQ monitor more than once. Therefore, check the * return code because we only want this done once. */ if (ret == 0) vn_open_upgrade(vp, FREAD); } else { /* WRITE */ if (((fflags & FWRITE) && vn_has_other_opens(vp, V_WRITE)) || (((fflags & FWRITE) == 0) && vn_is_opened(vp, V_WRITE)) || ((fflags & FREAD) && vn_has_other_opens(vp, V_READ)) || (((fflags & FREAD) == 0) && vn_is_opened(vp, V_READ)) || vn_is_mapped(vp, V_RDORWR)) { if (open_prev) { *recall = 1; } else { rfs4_deleg_state_rele(dsp); return (NULL); } } ret = fem_install(vp, deleg_wrops, (void *)fp, OPUNIQ, rfs4_mon_hold, rfs4_mon_rele); if (((fflags & FWRITE) && vn_has_other_opens(vp, V_WRITE)) || (((fflags & FWRITE) == 0) && vn_is_opened(vp, V_WRITE)) || ((fflags & FREAD) && vn_has_other_opens(vp, V_READ)) || (((fflags & FREAD) == 0) && vn_is_opened(vp, V_READ)) || vn_is_mapped(vp, V_RDORWR)) { if (open_prev) { *recall = 1; } else { (void) fem_uninstall(vp, deleg_wrops, (void *)fp); rfs4_deleg_state_rele(dsp); return (NULL); } } /* * Because a client can hold onto a delegation after the * file has been closed, we need to keep track of the * access to this file. Otherwise the CIFS server would * not know about the client accessing the file and could * inappropriately grant an OPLOCK. * fem_install() returns EBUSY when asked to install a * OPUNIQ monitor more than once. Therefore, check the * return code because we only want this done once. */ if (ret == 0) vn_open_upgrade(vp, FREAD|FWRITE); } /* Place on delegation list for file */ ASSERT(!list_link_active(&dsp->rds_node)); list_insert_tail(&fp->rf_delegstatelist, dsp); dsp->rds_dtype = fp->rf_dinfo.rd_dtype = dtype; /* Update delegation stats for this file */ fp->rf_dinfo.rd_time_lastgrant = gethrestime_sec(); /* reset since this is a new delegation */ fp->rf_dinfo.rd_conflicted_client = 0; fp->rf_dinfo.rd_ever_recalled = FALSE; if (dtype == OPEN_DELEGATE_READ) fp->rf_dinfo.rd_rdgrants++; else fp->rf_dinfo.rd_wrgrants++; return (dsp); }