1227
1228 /*
1229 * The following two accessor functions are for the NFSv4 server. Since there
1230 * is no VOP_OPEN_UP/DOWNGRADE we need a way for the NFS server to keep the
1231 * vnode open counts correct when a client "upgrades" an open or does an
1232 * open_downgrade. In NFS, an upgrade or downgrade can not only change the
1233 * open mode (add or subtract read or write), but also change the share/deny
1234 * modes. However, share reservations are not integrated with OPEN, yet, so
1235 * we need to handle each separately. These functions are cleaner than having
1236 * the NFS server manipulate the counts directly, however, nobody else should
1237 * use these functions.
1238 */
1239 void
1240 vn_open_upgrade(
1241 vnode_t *vp,
1242 int filemode)
1243 {
1244 ASSERT(vp->v_type == VREG);
1245
1246 if (filemode & FREAD)
1247 atomic_add_32(&(vp->v_rdcnt), 1);
1248 if (filemode & FWRITE)
1249 atomic_add_32(&(vp->v_wrcnt), 1);
1250
1251 }
1252
1253 void
1254 vn_open_downgrade(
1255 vnode_t *vp,
1256 int filemode)
1257 {
1258 ASSERT(vp->v_type == VREG);
1259
1260 if (filemode & FREAD) {
1261 ASSERT(vp->v_rdcnt > 0);
1262 atomic_add_32(&(vp->v_rdcnt), -1);
1263 }
1264 if (filemode & FWRITE) {
1265 ASSERT(vp->v_wrcnt > 0);
1266 atomic_add_32(&(vp->v_wrcnt), -1);
1267 }
1268
1269 }
1270
1271 int
1272 vn_create(
1273 char *pnamep,
1274 enum uio_seg seg,
1275 struct vattr *vap,
1276 enum vcexcl excl,
1277 int mode,
1278 struct vnode **vpp,
1279 enum create why,
1280 int flag,
1281 mode_t umask)
1282 {
1283 return (vn_createat(pnamep, seg, vap, excl, mode, vpp, why, flag,
1284 umask, NULL));
1285 }
1286
2901 loc = (fs_generic_func_p *)
2902 ((char *)(vop) + otdp->offset);
2903 break;
2904 }
2905 }
2906
2907 return ((loc != NULL) && (*loc == funcp));
2908 }
2909
2910 /*
2911 * fs_new_caller_id() needs to return a unique ID on a given local system.
2912 * The IDs do not need to survive across reboots. These are primarily
2913 * used so that (FEM) monitors can detect particular callers (such as
2914 * the NFS server) to a given vnode/vfs operation.
2915 */
2916 u_longlong_t
2917 fs_new_caller_id()
2918 {
2919 static uint64_t next_caller_id = 0LL; /* First call returns 1 */
2920
2921 return ((u_longlong_t)atomic_add_64_nv(&next_caller_id, 1));
2922 }
2923
2924 /*
2925 * Given a starting vnode and a path, updates the path in the target vnode in
2926 * a safe manner. If the vnode already has path information embedded, then the
2927 * cached path is left untouched.
2928 */
2929
2930 size_t max_vnode_path = 4 * MAXPATHLEN;
2931
2932 void
2933 vn_setpath(vnode_t *rootvp, struct vnode *startvp, struct vnode *vp,
2934 const char *path, size_t plen)
2935 {
2936 char *rpath;
2937 vnode_t *base;
2938 size_t rpathlen, rpathalloc;
2939 int doslash = 1;
2940
2941 if (*path == '/') {
3129 caller_context_t *ct)
3130 {
3131 int ret;
3132 vnode_t *vp = *vpp;
3133
3134 VN_HOLD(vp);
3135 /*
3136 * Adding to the vnode counts before calling open
3137 * avoids the need for a mutex. It circumvents a race
3138 * condition where a query made on the vnode counts results in a
3139 * false negative. The inquirer goes away believing the file is
3140 * not open when there is an open on the file already under way.
3141 *
3142 * The counts are meant to prevent NFS from granting a delegation
3143 * when it would be dangerous to do so.
3144 *
3145 * The vnode counts are only kept on regular files
3146 */
3147 if ((*vpp)->v_type == VREG) {
3148 if (mode & FREAD)
3149 atomic_add_32(&((*vpp)->v_rdcnt), 1);
3150 if (mode & FWRITE)
3151 atomic_add_32(&((*vpp)->v_wrcnt), 1);
3152 }
3153
3154 VOPXID_MAP_CR(vp, cr);
3155
3156 ret = (*(*(vpp))->v_op->vop_open)(vpp, mode, cr, ct);
3157
3158 if (ret) {
3159 /*
3160 * Use the saved vp just in case the vnode ptr got trashed
3161 * by the error.
3162 */
3163 VOPSTATS_UPDATE(vp, open);
3164 if ((vp->v_type == VREG) && (mode & FREAD))
3165 atomic_add_32(&(vp->v_rdcnt), -1);
3166 if ((vp->v_type == VREG) && (mode & FWRITE))
3167 atomic_add_32(&(vp->v_wrcnt), -1);
3168 } else {
3169 /*
3170 * Some filesystems will return a different vnode,
3171 * but the same path was still used to open it.
3172 * So if we do change the vnode and need to
3173 * copy over the path, do so here, rather than special
3174 * casing each filesystem. Adjust the vnode counts to
3175 * reflect the vnode switch.
3176 */
3177 VOPSTATS_UPDATE(*vpp, open);
3178 if (*vpp != vp && *vpp != NULL) {
3179 vn_copypath(vp, *vpp);
3180 if (((*vpp)->v_type == VREG) && (mode & FREAD))
3181 atomic_add_32(&((*vpp)->v_rdcnt), 1);
3182 if ((vp->v_type == VREG) && (mode & FREAD))
3183 atomic_add_32(&(vp->v_rdcnt), -1);
3184 if (((*vpp)->v_type == VREG) && (mode & FWRITE))
3185 atomic_add_32(&((*vpp)->v_wrcnt), 1);
3186 if ((vp->v_type == VREG) && (mode & FWRITE))
3187 atomic_add_32(&(vp->v_wrcnt), -1);
3188 }
3189 }
3190 VN_RELE(vp);
3191 return (ret);
3192 }
3193
3194 int
3195 fop_close(
3196 vnode_t *vp,
3197 int flag,
3198 int count,
3199 offset_t offset,
3200 cred_t *cr,
3201 caller_context_t *ct)
3202 {
3203 int err;
3204
3205 VOPXID_MAP_CR(vp, cr);
3206
3207 err = (*(vp)->v_op->vop_close)(vp, flag, count, offset, cr, ct);
3208 VOPSTATS_UPDATE(vp, close);
3209 /*
3210 * Check passed in count to handle possible dups. Vnode counts are only
3211 * kept on regular files
3212 */
3213 if ((vp->v_type == VREG) && (count == 1)) {
3214 if (flag & FREAD) {
3215 ASSERT(vp->v_rdcnt > 0);
3216 atomic_add_32(&(vp->v_rdcnt), -1);
3217 }
3218 if (flag & FWRITE) {
3219 ASSERT(vp->v_wrcnt > 0);
3220 atomic_add_32(&(vp->v_wrcnt), -1);
3221 }
3222 }
3223 return (err);
3224 }
3225
3226 int
3227 fop_read(
3228 vnode_t *vp,
3229 uio_t *uiop,
3230 int ioflag,
3231 cred_t *cr,
3232 caller_context_t *ct)
3233 {
3234 int err;
3235 ssize_t resid_start = uiop->uio_resid;
3236
3237 VOPXID_MAP_CR(vp, cr);
3238
3239 err = (*(vp)->v_op->vop_read)(vp, uiop, ioflag, cr, ct);
3240 VOPSTATS_UPDATE_IO(vp, read,
|
1227
1228 /*
1229 * The following two accessor functions are for the NFSv4 server. Since there
1230 * is no VOP_OPEN_UP/DOWNGRADE we need a way for the NFS server to keep the
1231 * vnode open counts correct when a client "upgrades" an open or does an
1232 * open_downgrade. In NFS, an upgrade or downgrade can not only change the
1233 * open mode (add or subtract read or write), but also change the share/deny
1234 * modes. However, share reservations are not integrated with OPEN, yet, so
1235 * we need to handle each separately. These functions are cleaner than having
1236 * the NFS server manipulate the counts directly, however, nobody else should
1237 * use these functions.
1238 */
1239 void
1240 vn_open_upgrade(
1241 vnode_t *vp,
1242 int filemode)
1243 {
1244 ASSERT(vp->v_type == VREG);
1245
1246 if (filemode & FREAD)
1247 atomic_inc_32(&vp->v_rdcnt);
1248 if (filemode & FWRITE)
1249 atomic_inc_32(&vp->v_wrcnt);
1250
1251 }
1252
1253 void
1254 vn_open_downgrade(
1255 vnode_t *vp,
1256 int filemode)
1257 {
1258 ASSERT(vp->v_type == VREG);
1259
1260 if (filemode & FREAD) {
1261 ASSERT(vp->v_rdcnt > 0);
1262 atomic_dec_32(&vp->v_rdcnt);
1263 }
1264 if (filemode & FWRITE) {
1265 ASSERT(vp->v_wrcnt > 0);
1266 atomic_dec_32(&vp->v_wrcnt);
1267 }
1268
1269 }
1270
1271 int
1272 vn_create(
1273 char *pnamep,
1274 enum uio_seg seg,
1275 struct vattr *vap,
1276 enum vcexcl excl,
1277 int mode,
1278 struct vnode **vpp,
1279 enum create why,
1280 int flag,
1281 mode_t umask)
1282 {
1283 return (vn_createat(pnamep, seg, vap, excl, mode, vpp, why, flag,
1284 umask, NULL));
1285 }
1286
2901 loc = (fs_generic_func_p *)
2902 ((char *)(vop) + otdp->offset);
2903 break;
2904 }
2905 }
2906
2907 return ((loc != NULL) && (*loc == funcp));
2908 }
2909
2910 /*
2911 * fs_new_caller_id() needs to return a unique ID on a given local system.
2912 * The IDs do not need to survive across reboots. These are primarily
2913 * used so that (FEM) monitors can detect particular callers (such as
2914 * the NFS server) to a given vnode/vfs operation.
2915 */
2916 u_longlong_t
2917 fs_new_caller_id()
2918 {
2919 static uint64_t next_caller_id = 0LL; /* First call returns 1 */
2920
2921 return ((u_longlong_t)atomic_inc_64_nv(&next_caller_id));
2922 }
2923
2924 /*
2925 * Given a starting vnode and a path, updates the path in the target vnode in
2926 * a safe manner. If the vnode already has path information embedded, then the
2927 * cached path is left untouched.
2928 */
2929
2930 size_t max_vnode_path = 4 * MAXPATHLEN;
2931
2932 void
2933 vn_setpath(vnode_t *rootvp, struct vnode *startvp, struct vnode *vp,
2934 const char *path, size_t plen)
2935 {
2936 char *rpath;
2937 vnode_t *base;
2938 size_t rpathlen, rpathalloc;
2939 int doslash = 1;
2940
2941 if (*path == '/') {
3129 caller_context_t *ct)
3130 {
3131 int ret;
3132 vnode_t *vp = *vpp;
3133
3134 VN_HOLD(vp);
3135 /*
3136 * Adding to the vnode counts before calling open
3137 * avoids the need for a mutex. It circumvents a race
3138 * condition where a query made on the vnode counts results in a
3139 * false negative. The inquirer goes away believing the file is
3140 * not open when there is an open on the file already under way.
3141 *
3142 * The counts are meant to prevent NFS from granting a delegation
3143 * when it would be dangerous to do so.
3144 *
3145 * The vnode counts are only kept on regular files
3146 */
3147 if ((*vpp)->v_type == VREG) {
3148 if (mode & FREAD)
3149 atomic_inc_32(&(*vpp)->v_rdcnt);
3150 if (mode & FWRITE)
3151 atomic_inc_32(&(*vpp)->v_wrcnt);
3152 }
3153
3154 VOPXID_MAP_CR(vp, cr);
3155
3156 ret = (*(*(vpp))->v_op->vop_open)(vpp, mode, cr, ct);
3157
3158 if (ret) {
3159 /*
3160 * Use the saved vp just in case the vnode ptr got trashed
3161 * by the error.
3162 */
3163 VOPSTATS_UPDATE(vp, open);
3164 if ((vp->v_type == VREG) && (mode & FREAD))
3165 atomic_dec_32(&vp->v_rdcnt);
3166 if ((vp->v_type == VREG) && (mode & FWRITE))
3167 atomic_dec_32(&vp->v_wrcnt);
3168 } else {
3169 /*
3170 * Some filesystems will return a different vnode,
3171 * but the same path was still used to open it.
3172 * So if we do change the vnode and need to
3173 * copy over the path, do so here, rather than special
3174 * casing each filesystem. Adjust the vnode counts to
3175 * reflect the vnode switch.
3176 */
3177 VOPSTATS_UPDATE(*vpp, open);
3178 if (*vpp != vp && *vpp != NULL) {
3179 vn_copypath(vp, *vpp);
3180 if (((*vpp)->v_type == VREG) && (mode & FREAD))
3181 atomic_inc_32(&(*vpp)->v_rdcnt);
3182 if ((vp->v_type == VREG) && (mode & FREAD))
3183 atomic_dec_32(&vp->v_rdcnt);
3184 if (((*vpp)->v_type == VREG) && (mode & FWRITE))
3185 atomic_inc_32(&(*vpp)->v_wrcnt);
3186 if ((vp->v_type == VREG) && (mode & FWRITE))
3187 atomic_dec_32(&vp->v_wrcnt);
3188 }
3189 }
3190 VN_RELE(vp);
3191 return (ret);
3192 }
3193
3194 int
3195 fop_close(
3196 vnode_t *vp,
3197 int flag,
3198 int count,
3199 offset_t offset,
3200 cred_t *cr,
3201 caller_context_t *ct)
3202 {
3203 int err;
3204
3205 VOPXID_MAP_CR(vp, cr);
3206
3207 err = (*(vp)->v_op->vop_close)(vp, flag, count, offset, cr, ct);
3208 VOPSTATS_UPDATE(vp, close);
3209 /*
3210 * Check passed in count to handle possible dups. Vnode counts are only
3211 * kept on regular files
3212 */
3213 if ((vp->v_type == VREG) && (count == 1)) {
3214 if (flag & FREAD) {
3215 ASSERT(vp->v_rdcnt > 0);
3216 atomic_dec_32(&vp->v_rdcnt);
3217 }
3218 if (flag & FWRITE) {
3219 ASSERT(vp->v_wrcnt > 0);
3220 atomic_dec_32(&vp->v_wrcnt);
3221 }
3222 }
3223 return (err);
3224 }
3225
3226 int
3227 fop_read(
3228 vnode_t *vp,
3229 uio_t *uiop,
3230 int ioflag,
3231 cred_t *cr,
3232 caller_context_t *ct)
3233 {
3234 int err;
3235 ssize_t resid_start = uiop->uio_resid;
3236
3237 VOPXID_MAP_CR(vp, cr);
3238
3239 err = (*(vp)->v_op->vop_read)(vp, uiop, ioflag, cr, ct);
3240 VOPSTATS_UPDATE_IO(vp, read,
|