int smb_vop_other_opens(vnode_t *vp, int mode) { return (((mode & FWRITE) && vn_has_other_opens(vp, V_WRITE)) || (((mode & FWRITE) == 0) && vn_is_opened(vp, V_WRITE)) || ((mode & FREAD) && vn_has_other_opens(vp, V_READ)) || (((mode & FREAD) == 0) && vn_is_opened(vp, V_READ)) || vn_is_mapped(vp, V_RDORWR)); }
/* * 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); }