Changeset View
Changeset View
Standalone View
Standalone View
sys/fs/fuse/fuse_internal.c
Show First 20 Lines • Show All 249 Lines • ▼ Show 20 Lines | |||||
* 'vp'. Optionally, if argument 'vap' is not NULL, store a copy of the | * 'vp'. Optionally, if argument 'vap' is not NULL, store a copy of the | ||||
* converted attributes there as well. | * converted attributes there as well. | ||||
* | * | ||||
* If the nominal attribute cache TTL is zero, do not cache on the 'vp' (but do | * If the nominal attribute cache TTL is zero, do not cache on the 'vp' (but do | ||||
* return the result to the caller). | * return the result to the caller). | ||||
*/ | */ | ||||
void | void | ||||
fuse_internal_cache_attrs(struct vnode *vp, struct fuse_attr *attr, | fuse_internal_cache_attrs(struct vnode *vp, struct fuse_attr *attr, | ||||
uint64_t attr_valid, uint32_t attr_valid_nsec, struct vattr *vap) | uint64_t attr_valid, uint32_t attr_valid_nsec, struct vattr *vap, | ||||
bool from_server) | |||||
{ | { | ||||
struct mount *mp; | struct mount *mp; | ||||
struct fuse_vnode_data *fvdat; | struct fuse_vnode_data *fvdat; | ||||
struct fuse_data *data; | struct fuse_data *data; | ||||
struct vattr *vp_cache_at; | struct vattr *vp_cache_at; | ||||
mp = vnode_mount(vp); | mp = vnode_mount(vp); | ||||
fvdat = VTOFUD(vp); | fvdat = VTOFUD(vp); | ||||
data = fuse_get_mpdata(mp); | data = fuse_get_mpdata(mp); | ||||
ASSERT_VOP_ELOCKED(vp, "fuse_internal_cache_attrs"); | ASSERT_VOP_ELOCKED(vp, "fuse_internal_cache_attrs"); | ||||
fuse_validity_2_bintime(attr_valid, attr_valid_nsec, | fuse_validity_2_bintime(attr_valid, attr_valid_nsec, | ||||
&fvdat->attr_cache_timeout); | &fvdat->attr_cache_timeout); | ||||
if (vnode_isreg(vp) && | |||||
fvdat->cached_attrs.va_size != VNOVAL && | |||||
attr->size != fvdat->cached_attrs.va_size) | |||||
{ | |||||
if ( data->cache_mode == FUSE_CACHE_WB && | |||||
fvdat->flag & FN_SIZECHANGE) | |||||
{ | |||||
const char *msg; | |||||
/* | |||||
* The server changed the file's size even though we're | |||||
* using writeback cacheing and and we have outstanding | |||||
* dirty writes! That's a server bug. | |||||
*/ | |||||
if (fuse_libabi_geq(data, 7, 23)) { | |||||
msg = "writeback cache incoherent!." | |||||
"To prevent data corruption, disable " | |||||
"the writeback cache according to your " | |||||
"FUSE server's documentation."; | |||||
} else { | |||||
msg = "writeback cache incoherent!." | |||||
"To prevent data corruption, disable " | |||||
"the writeback cache by setting " | |||||
"vfs.fusefs.data_cache_mode to 0 or 1."; | |||||
} | |||||
fuse_warn(data, FSESS_WARN_WB_CACHE_INCOHERENT, msg); | |||||
} | |||||
if (fuse_vnode_attr_cache_valid(vp) && | |||||
data->cache_mode != FUSE_CACHE_UC) | |||||
{ | |||||
/* | |||||
* The server changed the file's size even though we | |||||
* have it cached and our cache has not yet expired. | |||||
* That's a bug. | |||||
*/ | |||||
fuse_warn(data, FSESS_WARN_CACHE_INCOHERENT, | |||||
"cache incoherent! " | |||||
"To prevent " | |||||
"data corruption, disable the data cache " | |||||
"by mounting with -o direct_io, or as " | |||||
"directed otherwise by your FUSE server's " | |||||
"documentation."); | |||||
} | |||||
} | |||||
/* Fix our buffers if the filesize changed without us knowing */ | /* Fix our buffers if the filesize changed without us knowing */ | ||||
if (vnode_isreg(vp) && attr->size != fvdat->cached_attrs.va_size) { | if (vnode_isreg(vp) && attr->size != fvdat->cached_attrs.va_size) { | ||||
(void)fuse_vnode_setsize(vp, attr->size); | (void)fuse_vnode_setsize(vp, attr->size, from_server); | ||||
fvdat->cached_attrs.va_size = attr->size; | fvdat->cached_attrs.va_size = attr->size; | ||||
} | } | ||||
if (attr_valid > 0 || attr_valid_nsec > 0) | if (attr_valid > 0 || attr_valid_nsec > 0) | ||||
vp_cache_at = &(fvdat->cached_attrs); | vp_cache_at = &(fvdat->cached_attrs); | ||||
else if (vap != NULL) | else if (vap != NULL) | ||||
vp_cache_at = vap; | vp_cache_at = vap; | ||||
else | else | ||||
▲ Show 20 Lines • Show All 516 Lines • ▼ Show 20 Lines | fuse_internal_newentry_core(struct vnode *dvp, | ||||
/* | /* | ||||
* Purge the parent's attribute cache because the daemon should've | * Purge the parent's attribute cache because the daemon should've | ||||
* updated its mtime and ctime | * updated its mtime and ctime | ||||
*/ | */ | ||||
fuse_vnode_clear_attr_cache(dvp); | fuse_vnode_clear_attr_cache(dvp); | ||||
fuse_internal_cache_attrs(*vpp, &feo->attr, feo->attr_valid, | fuse_internal_cache_attrs(*vpp, &feo->attr, feo->attr_valid, | ||||
feo->attr_valid_nsec, NULL); | feo->attr_valid_nsec, NULL, true); | ||||
return err; | return err; | ||||
} | } | ||||
int | int | ||||
fuse_internal_newentry(struct vnode *dvp, | fuse_internal_newentry(struct vnode *dvp, | ||||
struct vnode **vpp, | struct vnode **vpp, | ||||
struct componentname *cnp, | struct componentname *cnp, | ||||
▲ Show 20 Lines • Show All 89 Lines • ▼ Show 20 Lines | fuse_internal_do_getattr(struct vnode *vp, struct vattr *vap, | ||||
if (fvdat->flag & FN_CTIMECHANGE) { | if (fvdat->flag & FN_CTIMECHANGE) { | ||||
fao->attr.ctime = old_ctime.tv_sec; | fao->attr.ctime = old_ctime.tv_sec; | ||||
fao->attr.ctimensec = old_ctime.tv_nsec; | fao->attr.ctimensec = old_ctime.tv_nsec; | ||||
} | } | ||||
if (fvdat->flag & FN_MTIMECHANGE) { | if (fvdat->flag & FN_MTIMECHANGE) { | ||||
fao->attr.mtime = old_mtime.tv_sec; | fao->attr.mtime = old_mtime.tv_sec; | ||||
fao->attr.mtimensec = old_mtime.tv_nsec; | fao->attr.mtimensec = old_mtime.tv_nsec; | ||||
} | } | ||||
if (vnode_isreg(vp) && | |||||
fvdat->cached_attrs.va_size != VNOVAL && | |||||
fao->attr.size != fvdat->cached_attrs.va_size) { | |||||
/* | |||||
* The server changed the file's size even though we had it | |||||
* cached! That's a server bug. | |||||
*/ | |||||
struct mount *mp = vnode_mount(vp); | |||||
struct fuse_data *data = fuse_get_mpdata(mp); | |||||
fuse_warn(data, FSESS_WARN_CACHE_INCOHERENT, | |||||
"cache incoherent! " | |||||
"To prevent data corruption, disable the data cache " | |||||
"by mounting with -o direct_io, or as directed " | |||||
"otherwise by your FUSE server's documentation."); | |||||
int iosize = fuse_iosize(vp); | |||||
v_inval_buf_range(vp, 0, INT64_MAX, iosize); | |||||
} | |||||
fuse_internal_cache_attrs(vp, &fao->attr, fao->attr_valid, | fuse_internal_cache_attrs(vp, &fao->attr, fao->attr_valid, | ||||
fao->attr_valid_nsec, vap); | fao->attr_valid_nsec, vap, true); | ||||
if (vtyp != vnode_vtype(vp)) { | if (vtyp != vnode_vtype(vp)) { | ||||
fuse_internal_vnode_disappear(vp); | fuse_internal_vnode_disappear(vp); | ||||
err = ENOENT; | err = ENOENT; | ||||
} | } | ||||
out: | out: | ||||
fdisp_destroy(&fdi); | fdisp_destroy(&fdi); | ||||
return err; | return err; | ||||
▲ Show 20 Lines • Show All 283 Lines • ▼ Show 20 Lines | if (vnode_vtype(vp) == VNON && vtyp != VNON) { | ||||
fuse_internal_vnode_disappear(vp); | fuse_internal_vnode_disappear(vp); | ||||
err = EAGAIN; | err = EAGAIN; | ||||
} | } | ||||
} | } | ||||
if (err == 0) { | if (err == 0) { | ||||
struct fuse_attr_out *fao = (struct fuse_attr_out*)fdi.answ; | struct fuse_attr_out *fao = (struct fuse_attr_out*)fdi.answ; | ||||
fuse_vnode_undirty_cached_timestamps(vp); | fuse_vnode_undirty_cached_timestamps(vp); | ||||
fuse_internal_cache_attrs(vp, &fao->attr, fao->attr_valid, | fuse_internal_cache_attrs(vp, &fao->attr, fao->attr_valid, | ||||
fao->attr_valid_nsec, NULL); | fao->attr_valid_nsec, NULL, false); | ||||
} | } | ||||
out: | out: | ||||
fdisp_destroy(&fdi); | fdisp_destroy(&fdi); | ||||
return err; | return err; | ||||
} | } | ||||
/* | /* | ||||
▲ Show 20 Lines • Show All 67 Lines • Show Last 20 Lines |