int nfs_wait_bit_killable(struct wait_bit_key *key, int mode)
{ if (unlikely(nfs_current_task_exiting())) return -EINTR;
schedule(); if (signal_pending_state(mode, current)) return -ERESTARTSYS; return 0;
}
EXPORT_SYMBOL_GPL(nfs_wait_bit_killable);
/** * nfs_compat_user_ino64 - returns the user-visible inode number * @fileid: 64-bit fileid * * This function returns a 32-bit inode number if the boot parameter * nfs.enable_ino64 is zero.
*/
u64 nfs_compat_user_ino64(u64 fileid)
{ #ifdef CONFIG_COMPAT
compat_ulong_t ino; #else unsignedlong ino; #endif
void nfs_clear_inode(struct inode *inode)
{ /* * The following should never happen...
*/
WARN_ON_ONCE(nfs_have_writebacks(inode));
WARN_ON_ONCE(!list_empty(&NFS_I(inode)->open_files));
nfs_zap_acl_cache(inode);
nfs_access_zap_cache(inode);
nfs_fscache_clear_inode(inode);
}
EXPORT_SYMBOL_GPL(nfs_clear_inode);
int nfs_sync_inode(struct inode *inode)
{
inode_dio_wait(inode); return nfs_wb_all(inode);
}
EXPORT_SYMBOL_GPL(nfs_sync_inode);
/** * nfs_sync_mapping - helper to flush all mmapped dirty data to disk * @mapping: pointer to struct address_space
*/ int nfs_sync_mapping(struct address_space *mapping)
{ int ret = 0;
if (mapping->nrpages != 0) {
unmap_mapping_range(mapping, 0, 0, 0);
ret = nfs_wb_all(mapping->host);
} return ret;
}
/* * Invalidate, but do not unhash, the inode. * NB: must be called with inode->i_lock held!
*/ staticvoid nfs_set_inode_stale_locked(struct inode *inode)
{
set_bit(NFS_INO_STALE, &NFS_I(inode)->flags);
nfs_zap_caches_locked(inode);
trace_nfs_set_inode_stale(inode);
}
/* * In NFSv3 we can have 64bit inode numbers. In order to support * this, and re-exported directories (also seen in NFSv2) * we are forced to allow 2 different inodes to have the same * i_ino.
*/ staticint
nfs_find_actor(struct inode *inode, void *opaque)
{ struct nfs_find_desc *desc = opaque; struct nfs_fh *fh = desc->fh; struct nfs_fattr *fattr = desc->fattr;
if (NFS_FILEID(inode) != fattr->fileid) return 0; if (inode_wrong_type(inode, fattr->mode)) return 0; if (nfs_compare_fh(NFS_FH(inode), fh)) return 0; if (is_bad_inode(inode) || NFS_STALE(inode)) return 0; return 1;
}
/** * nfs_vmtruncate - unmap mappings "freed" by truncate() syscall * @inode: inode of the file used * @offset: file offset to start truncating * * This is a copy of the common vmtruncate, but with the locking * corrected to take into account the fact that NFS requires * inode->i_size to be updated under the inode->i_lock. * Note: must be called with inode->i_lock held!
*/ staticint nfs_vmtruncate(struct inode * inode, loff_t offset)
{ int err;
err = inode_newsize_ok(inode, offset); if (err) goto out;
/** * nfs_setattr_update_inode - Update inode metadata after a setattr call. * @inode: pointer to struct inode * @attr: pointer to struct iattr * @fattr: pointer to struct nfs_fattr * * Note: we do this in the *proc.c in order to ensure that * it works for things like exclusive creates too.
*/ void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr, struct nfs_fattr *fattr)
{ /* Barrier: bump the attribute generation count. */
nfs_fattr_set_barrier(fattr);
if (fattr->valid & NFS_ATTR_FATTR_CTIME)
inode_set_ctime_to_ts(inode, fattr->ctime); else
nfs_set_cache_invalid(inode, NFS_INO_INVALID_CHANGE
| NFS_INO_INVALID_CTIME);
} if (fattr->valid)
nfs_update_inode(inode, fattr);
spin_unlock(&inode->i_lock);
}
EXPORT_SYMBOL_GPL(nfs_setattr_update_inode);
/* * Don't request help from readdirplus if the file is being written to, * or if attribute caching is turned off
*/ staticbool nfs_getattr_readdirplus_enable(conststruct inode *inode)
{ return nfs_server_capable(inode, NFS_CAP_READDIRPLUS) &&
!nfs_have_writebacks(inode) && NFS_MAXATTRTIMEO(inode) > 5 * HZ;
}
if (!(fattr_valid & NFS_ATTR_FATTR_BTIME))
request_mask &= ~STATX_BTIME;
if ((query_flags & AT_STATX_DONT_SYNC) && !force_sync) { if (readdirplus_enabled)
nfs_readdirplus_parent_cache_hit(path->dentry); goto out_no_revalidate;
}
/* Flush out writes to the server in order to update c/mtime/version. */ if ((request_mask & (STATX_CTIME | STATX_MTIME | STATX_CHANGE_COOKIE)) &&
S_ISREG(inode->i_mode)) { if (nfs_have_delegated_mtime(inode))
filemap_fdatawrite(inode->i_mapping); else
filemap_write_and_wait(inode->i_mapping);
}
/* * We may force a getattr if the user cares about atime. * * Note that we only have to check the vfsmount flags here: * - NFS always sets S_NOATIME by so checking it would give a * bogus result * - NFS never sets SB_NOATIME or SB_NODIRATIME so there is * no point in checking those.
*/ if ((path->mnt->mnt_flags & MNT_NOATIME) ||
((path->mnt->mnt_flags & MNT_NODIRATIME) && S_ISDIR(inode->i_mode)))
request_mask &= ~STATX_ATIME;
/* Is the user requesting attributes that might need revalidation? */ if (!(request_mask & (STATX_MODE|STATX_NLINK|STATX_ATIME|STATX_CTIME|
STATX_MTIME|STATX_UID|STATX_GID|
STATX_SIZE|STATX_BLOCKS|STATX_BTIME|
STATX_CHANGE_COOKIE))) goto out_no_revalidate;
/* Check whether the cached attributes are stale */
do_update |= force_sync || nfs_attribute_cache_expired(inode);
cache_validity = READ_ONCE(NFS_I(inode)->cache_validity);
do_update |= cache_validity & NFS_INO_INVALID_CHANGE; if (request_mask & STATX_ATIME)
do_update |= cache_validity & NFS_INO_INVALID_ATIME; if (request_mask & STATX_CTIME)
do_update |= cache_validity & NFS_INO_INVALID_CTIME; if (request_mask & STATX_MTIME)
do_update |= cache_validity & NFS_INO_INVALID_MTIME; if (request_mask & STATX_SIZE)
do_update |= cache_validity & NFS_INO_INVALID_SIZE; if (request_mask & STATX_NLINK)
do_update |= cache_validity & NFS_INO_INVALID_NLINK; if (request_mask & STATX_MODE)
do_update |= cache_validity & NFS_INO_INVALID_MODE; if (request_mask & (STATX_UID | STATX_GID))
do_update |= cache_validity & NFS_INO_INVALID_OTHER; if (request_mask & STATX_BLOCKS)
do_update |= cache_validity & NFS_INO_INVALID_BLOCKS; if (request_mask & STATX_BTIME)
do_update |= cache_validity & NFS_INO_INVALID_BTIME;
if (do_update) { if (readdirplus_enabled)
nfs_readdirplus_parent_cache_miss(path->dentry);
err = __nfs_revalidate_inode(server, inode); if (err) goto out;
} elseif (readdirplus_enabled)
nfs_readdirplus_parent_cache_hit(path->dentry);
out_no_revalidate: /* Only return attributes that were revalidated. */
stat->result_mask = nfs_get_valid_attrmask(inode) | request_mask;
/** * nfs_close_context - Common close_context() routine NFSv2/v3 * @ctx: pointer to context * @is_sync: is this a synchronous close * * Ensure that the attributes are up to date if we're mounted * with close-to-open semantics and we have cached data that will * need to be revalidated on open.
*/ void nfs_close_context(struct nfs_open_context *ctx, int is_sync)
{ struct nfs_inode *nfsi; struct inode *inode;
if (!(ctx->mode & FMODE_WRITE)) return; if (!is_sync) return;
inode = d_inode(ctx->dentry); if (nfs_have_read_or_write_delegation(inode)) return;
nfsi = NFS_I(inode); if (inode->i_mapping->nrpages == 0) return; if (nfsi->cache_validity & NFS_INO_INVALID_DATA) return; if (!list_empty(&nfsi->open_files)) return; if (NFS_SERVER(inode)->flags & NFS_MOUNT_NOCTO) return;
nfs_revalidate_inode(inode,
NFS_INO_INVALID_CHANGE | NFS_INO_INVALID_SIZE);
}
EXPORT_SYMBOL_GPL(nfs_close_context);
/* * Ensure that mmap has a recent RPC credential for use when writing out * shared pages
*/ void nfs_inode_attach_open_context(struct nfs_open_context *ctx)
{ struct inode *inode = d_inode(ctx->dentry); struct nfs_inode *nfsi = NFS_I(inode);
/* * This function is called whenever some part of NFS notices that * the cached attributes have to be refreshed.
*/ int
__nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
{ int status = -ESTALE; struct nfs_fattr *fattr = NULL; struct nfs_inode *nfsi = NFS_I(inode);
if (is_bad_inode(inode)) goto out; if (NFS_STALE(inode)) goto out;
/* pNFS: Attributes aren't updated until we layoutcommit */ if (S_ISREG(inode->i_mode)) {
status = pnfs_sync_inode(inode, false); if (status) goto out;
}
status = -ENOMEM;
fattr = nfs_alloc_fattr_with_label(NFS_SERVER(inode)); if (fattr == NULL) goto out;
nfs_inc_stats(inode, NFSIOS_INODEREVALIDATE);
status = NFS_PROTO(inode)->getattr(server, NFS_FH(inode), fattr, inode); if (status != 0) {
dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Lu) getattr failed, error=%d\n",
inode->i_sb->s_id,
(unsignedlonglong)NFS_FILEID(inode), status); switch (status) { case -ETIMEDOUT: /* A soft timeout occurred. Use cached information? */ if (server->flags & NFS_MOUNT_SOFTREVAL)
status = 0; break; case -ESTALE: if (!S_ISDIR(inode->i_mode))
nfs_set_inode_stale(inode); else
nfs_zap_caches(inode);
} goto out;
}
status = nfs_refresh_inode(inode, fattr); if (status) {
dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Lu) refresh failed, error=%d\n",
inode->i_sb->s_id,
(unsignedlonglong)NFS_FILEID(inode), status); goto out;
}
if (nfsi->cache_validity & NFS_INO_INVALID_ACL)
nfs_zap_acl_cache(inode);
int nfs_attribute_cache_expired(struct inode *inode)
{ if (nfs_have_delegated_attributes(inode)) return 0; return nfs_attribute_timeout(inode);
}
/** * nfs_revalidate_inode - Revalidate the inode attributes * @inode: pointer to inode struct * @flags: cache flags to check * * Updates inode attribute information by retrieving the data from the server.
*/ int nfs_revalidate_inode(struct inode *inode, unsignedlong flags)
{ if (!nfs_check_cache_invalid(inode, flags)) return NFS_STALE(inode) ? -ESTALE : 0; return __nfs_revalidate_inode(NFS_SERVER(inode), inode);
}
EXPORT_SYMBOL_GPL(nfs_revalidate_inode);
staticint nfs_invalidate_mapping(struct inode *inode, struct address_space *mapping)
{ int ret;
nfs_fscache_invalidate(inode, 0); if (mapping->nrpages != 0) { if (S_ISREG(inode->i_mode)) {
ret = nfs_sync_mapping(mapping); if (ret < 0) return ret;
}
ret = invalidate_inode_pages2(mapping); if (ret < 0) return ret;
}
nfs_inc_stats(inode, NFSIOS_DATAINVALIDATE);
/** * nfs_clear_invalid_mapping - Conditionally clear a mapping * @mapping: pointer to mapping * * If the NFS_INO_INVALID_DATA inode flag is set, clear the mapping.
*/ int nfs_clear_invalid_mapping(struct address_space *mapping)
{ struct inode *inode = mapping->host; struct nfs_inode *nfsi = NFS_I(inode); unsignedlong *bitlock = &nfsi->flags; int ret = 0;
/* * We must clear NFS_INO_INVALID_DATA first to ensure that * invalidations that come in while we're shooting down the mappings * are respected. But, that leaves a race window where one revalidator * can clear the flag, and then another checks it before the mapping * gets invalidated. Fix that by serializing access to this part of * the function. * * At the same time, we need to allow other tasks to see whether we * might be in the middle of invalidating the pages, so we only set * the bit lock here if it looks like we're going to be doing that.
*/ for (;;) {
ret = wait_on_bit_action(bitlock, NFS_INO_INVALIDATING,
nfs_wait_bit_killable,
TASK_KILLABLE|TASK_FREEZABLE_UNSAFE); if (ret) goto out;
smp_rmb(); /* pairs with smp_wmb() below */ if (test_bit(NFS_INO_INVALIDATING, bitlock)) continue; /* pairs with nfs_set_cache_invalid()'s smp_store_release() */ if (!(smp_load_acquire(&nfsi->cache_validity) & NFS_INO_INVALID_DATA)) goto out; /* Slow-path that double-checks with spinlock held */
spin_lock(&inode->i_lock); if (test_bit(NFS_INO_INVALIDATING, bitlock)) {
spin_unlock(&inode->i_lock); continue;
} if (nfsi->cache_validity & NFS_INO_INVALID_DATA) break;
spin_unlock(&inode->i_lock); goto out;
}
int nfs_revalidate_mapping_rcu(struct inode *inode)
{ struct nfs_inode *nfsi = NFS_I(inode); unsignedlong *bitlock = &nfsi->flags; int ret = 0;
if (IS_SWAPFILE(inode)) goto out; if (nfs_mapping_need_revalidate_inode(inode)) {
ret = -ECHILD; goto out;
}
spin_lock(&inode->i_lock); if (test_bit(NFS_INO_INVALIDATING, bitlock) ||
(nfsi->cache_validity & NFS_INO_INVALID_DATA))
ret = -ECHILD;
spin_unlock(&inode->i_lock);
out: return ret;
}
/** * nfs_revalidate_mapping - Revalidate the pagecache * @inode: pointer to host inode * @mapping: pointer to mapping
*/ int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping)
{ /* swapfiles are not supposed to be shared. */ if (IS_SWAPFILE(inode)) return 0;
if (nfs_mapping_need_revalidate_inode(inode)) { int ret = __nfs_revalidate_inode(NFS_SERVER(inode), inode); if (ret < 0) return ret;
}
/** * nfs_check_inode_attributes - verify consistency of the inode attribute cache * @inode: pointer to inode * @fattr: updated attributes * * Verifies the attribute cache. If we have just changed the attributes, * so that fattr carries weak cache consistency data, then it may * also update the ctime/mtime/change_attribute.
*/ staticint nfs_check_inode_attributes(struct inode *inode, struct nfs_fattr *fattr)
{ struct nfs_inode *nfsi = NFS_I(inode);
loff_t cur_size, new_isize; unsignedlong invalid = 0; struct timespec64 ts;
if (nfs_have_delegated_attributes(inode)) return 0;
if (!(fattr->valid & NFS_ATTR_FATTR_FILEID)) { /* Only a mounted-on-fileid? Just exit */ if (fattr->valid & NFS_ATTR_FATTR_MOUNTED_ON_FILEID) return 0; /* Has the inode gone and changed behind our back? */
} elseif (nfsi->fileid != fattr->fileid) { /* Is this perhaps the mounted-on fileid? */ if ((fattr->valid & NFS_ATTR_FATTR_MOUNTED_ON_FILEID) &&
nfsi->fileid == fattr->mounted_on_fileid) return 0; return -ESTALE;
} if ((fattr->valid & NFS_ATTR_FATTR_TYPE) && inode_wrong_type(inode, fattr->mode)) return -ESTALE;
if (!nfs_file_has_buffered_writers(nfsi)) { /* Verify a few of the more important attributes */ if ((fattr->valid & NFS_ATTR_FATTR_CHANGE) != 0 && !inode_eq_iversion_raw(inode, fattr->change_attr))
invalid |= NFS_INO_INVALID_CHANGE;
/** * nfs_fattr_set_barrier * @fattr: attributes * * Used to set a barrier after an attribute was updated. This * barrier ensures that older attributes from RPC calls that may * have raced with our update cannot clobber these new values. * Note that you are still responsible for ensuring that other * operations which change the attribute on the server do not * collide.
*/ void nfs_fattr_set_barrier(struct nfs_fattr *fattr)
{
fattr->gencount = nfs_inc_attr_generation_counter();
}
#ifdef NFS_DEBUG /* * _nfs_display_fhandle_hash - calculate the crc32 hash for the filehandle * in the same way that wireshark does * * @fh: file handle * * For debugging only.
*/
u32 _nfs_display_fhandle_hash(conststruct nfs_fh *fh)
{ /* wireshark uses 32-bit AUTODIN crc and does a bitwise
* not on the result */ return nfs_fhandle_hash(fh);
}
EXPORT_SYMBOL_GPL(_nfs_display_fhandle_hash);
/* * _nfs_display_fhandle - display an NFS file handle on the console * * @fh: file handle to display * @caption: display caption * * For debugging only.
*/ void _nfs_display_fhandle(conststruct nfs_fh *fh, constchar *caption)
{ unsignedshort i;
if (fh == NULL || fh->size == 0) {
printk(KERN_DEFAULT "%s at %p is empty\n", caption, fh); return;
}
printk(KERN_DEFAULT "%s at %p is %u bytes, crc: 0x%08x:\n",
caption, fh, fh->size, _nfs_display_fhandle_hash(fh)); for (i = 0; i < fh->size; i += 16) {
__be32 *pos = (__be32 *)&fh->data[i];
/** * nfs_inode_attrs_cmp_generic - compare attributes * @fattr: attributes * @inode: pointer to inode * * Attempt to divine whether or not an RPC call reply carrying stale * attributes got scheduled after another call carrying updated ones. * Note also the check for wraparound of 'attr_gencount' * * The function returns '1' if it thinks the attributes in @fattr are * more recent than the ones cached in @inode. Otherwise it returns * the value '0'.
*/ staticint nfs_inode_attrs_cmp_generic(conststruct nfs_fattr *fattr, conststruct inode *inode)
{ unsignedlong attr_gencount = NFS_I(inode)->attr_gencount;
/** * nfs_inode_attrs_cmp_monotonic - compare attributes * @fattr: attributes * @inode: pointer to inode * * Attempt to divine whether or not an RPC call reply carrying stale * attributes got scheduled after another call carrying updated ones. * * We assume that the server observes monotonic semantics for * the change attribute, so a larger value means that the attributes in * @fattr are more recent, in which case the function returns the * value '1'. * A return value of '0' indicates no measurable change * A return value of '-1' means that the attributes in @inode are * more recent.
*/ staticint nfs_inode_attrs_cmp_monotonic(conststruct nfs_fattr *fattr, conststruct inode *inode)
{
s64 diff = fattr->change_attr - inode_peek_iversion_raw(inode); if (diff > 0) return 1; return diff == 0 ? 0 : -1;
}
/** * nfs_inode_attrs_cmp_strict_monotonic - compare attributes * @fattr: attributes * @inode: pointer to inode * * Attempt to divine whether or not an RPC call reply carrying stale * attributes got scheduled after another call carrying updated ones. * * We assume that the server observes strictly monotonic semantics for * the change attribute, so a larger value means that the attributes in * @fattr are more recent, in which case the function returns the * value '1'. * A return value of '-1' means that the attributes in @inode are * more recent or unchanged.
*/ staticint nfs_inode_attrs_cmp_strict_monotonic(conststruct nfs_fattr *fattr, conststruct inode *inode)
{ return nfs_inode_attrs_cmp_monotonic(fattr, inode) > 0 ? 1 : -1;
}
/** * nfs_inode_attrs_cmp - compare attributes * @fattr: attributes * @inode: pointer to inode * * This function returns '1' if it thinks the attributes in @fattr are * more recent than the ones cached in @inode. It returns '-1' if * the attributes in @inode are more recent than the ones in @fattr, * and it returns 0 if not sure.
*/ staticint nfs_inode_attrs_cmp(conststruct nfs_fattr *fattr, conststruct inode *inode)
{ if (nfs_inode_attrs_cmp_generic(fattr, inode) > 0) return 1; switch (NFS_SERVER(inode)->change_attr_type) { case NFS4_CHANGE_TYPE_IS_UNDEFINED: break; case NFS4_CHANGE_TYPE_IS_TIME_METADATA: if (!(fattr->valid & NFS_ATTR_FATTR_CHANGE)) break; return nfs_inode_attrs_cmp_monotonic(fattr, inode); default: if (!(fattr->valid & NFS_ATTR_FATTR_CHANGE)) break; return nfs_inode_attrs_cmp_strict_monotonic(fattr, inode);
} return 0;
}
/** * nfs_inode_finish_partial_attr_update - complete a previous inode update * @fattr: attributes * @inode: pointer to inode * * Returns '1' if the last attribute update left the inode cached * attributes in a partially unrevalidated state, and @fattr * matches the change attribute of that partial update. * Otherwise returns '0'.
*/ staticint nfs_inode_finish_partial_attr_update(conststruct nfs_fattr *fattr, conststruct inode *inode)
{ constunsignedlong check_valid =
NFS_INO_INVALID_ATIME | NFS_INO_INVALID_CTIME |
NFS_INO_INVALID_MTIME | NFS_INO_INVALID_SIZE |
NFS_INO_INVALID_BLOCKS | NFS_INO_INVALID_OTHER |
NFS_INO_INVALID_NLINK | NFS_INO_INVALID_BTIME; unsignedlong cache_validity = NFS_I(inode)->cache_validity; enum nfs4_change_attr_type ctype = NFS_SERVER(inode)->change_attr_type;
staticvoid nfs_ooo_merge(struct nfs_inode *nfsi,
u64 start, u64 end)
{ int i, cnt;
if (nfsi->cache_validity & NFS_INO_DATA_INVAL_DEFER) /* No point merging anything */ return;
if (!nfsi->ooo) {
nfsi->ooo = kmalloc(sizeof(*nfsi->ooo), GFP_ATOMIC); if (!nfsi->ooo) {
nfsi->cache_validity |= NFS_INO_DATA_INVAL_DEFER; return;
}
nfsi->ooo->cnt = 0;
}
/* add this range, merging if possible */
cnt = nfsi->ooo->cnt; for (i = 0; i < cnt; i++) { if (end == nfsi->ooo->gap[i].start)
end = nfsi->ooo->gap[i].end; elseif (start == nfsi->ooo->gap[i].end)
start = nfsi->ooo->gap[i].start; else continue; /* Remove 'i' from table and loop to insert the new range */
cnt -= 1;
nfsi->ooo->gap[i] = nfsi->ooo->gap[cnt];
i = -1;
} if (start != end) { if (cnt >= ARRAY_SIZE(nfsi->ooo->gap)) {
nfsi->cache_validity |= NFS_INO_DATA_INVAL_DEFER;
kfree(nfsi->ooo);
nfsi->ooo = NULL; return;
}
nfsi->ooo->gap[cnt].start = start;
nfsi->ooo->gap[cnt].end = end;
cnt += 1;
}
nfsi->ooo->cnt = cnt;
}
staticvoid nfs_ooo_record(struct nfs_inode *nfsi, struct nfs_fattr *fattr)
{ /* This reply was out-of-order, so record in the * pre/post change id, possibly cancelling * gaps created when iversion was jumpped forward.
*/ if ((fattr->valid & NFS_ATTR_FATTR_CHANGE) &&
(fattr->valid & NFS_ATTR_FATTR_PRECHANGE))
nfs_ooo_merge(nfsi,
fattr->change_attr,
fattr->pre_change_attr);
}
staticint nfs_refresh_inode_locked(struct inode *inode, struct nfs_fattr *fattr)
{ int attr_cmp = nfs_inode_attrs_cmp(fattr, inode); int ret = 0;
trace_nfs_refresh_inode_enter(inode);
if (attr_cmp > 0 || nfs_inode_finish_partial_attr_update(fattr, inode))
ret = nfs_update_inode(inode, fattr); else {
nfs_ooo_record(NFS_I(inode), fattr);
if (attr_cmp == 0)
ret = nfs_check_inode_attributes(inode, fattr);
}
/** * nfs_refresh_inode - try to update the inode attribute cache * @inode: pointer to inode * @fattr: updated attributes * * Check that an RPC call that returned attributes has not overlapped with * other recent updates of the inode metadata, then decide whether it is * safe to do a full update of the inode attributes, or whether just to * call nfs_check_inode_attributes.
*/ int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
{ int status;
if ((fattr->valid & NFS_ATTR_FATTR) == 0) return 0;
spin_lock(&inode->i_lock);
status = nfs_refresh_inode_locked(inode, fattr);
spin_unlock(&inode->i_lock);
/** * nfs_post_op_update_inode - try to update the inode attribute cache * @inode: pointer to inode * @fattr: updated attributes * * After an operation that has changed the inode metadata, mark the * attribute cache as being invalid, then try to update it. * * NB: if the server didn't return any post op attributes, this * function will force the retrieval of attributes before the next * NFS request. Thus it should be used only for operations that * are expected to change one or more attributes, to avoid * unnecessary NFS requests and trips through nfs_update_inode().
*/ int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr)
{ int status;
/** * nfs_post_op_update_inode_force_wcc_locked - update the inode attribute cache * @inode: pointer to inode * @fattr: updated attributes * * After an operation that has changed the inode metadata, mark the * attribute cache as being invalid, then try to update it. Fake up * weak cache consistency data, if none exist. * * This function is mainly designed to be used by the ->write_done() functions.
*/ int nfs_post_op_update_inode_force_wcc_locked(struct inode *inode, struct nfs_fattr *fattr)
{ int attr_cmp = nfs_inode_attrs_cmp(fattr, inode); int status;
/* Don't do a WCC update if these attributes are already stale */ if (attr_cmp < 0) return 0; if ((fattr->valid & NFS_ATTR_FATTR) == 0 || !attr_cmp) { /* Record the pre/post change info before clearing PRECHANGE */
nfs_ooo_record(NFS_I(inode), fattr);
fattr->valid &= ~(NFS_ATTR_FATTR_PRECHANGE
| NFS_ATTR_FATTR_PRESIZE
| NFS_ATTR_FATTR_PREMTIME
| NFS_ATTR_FATTR_PRECTIME); goto out_noforce;
} if ((fattr->valid & NFS_ATTR_FATTR_CHANGE) != 0 &&
(fattr->valid & NFS_ATTR_FATTR_PRECHANGE) == 0) {
fattr->pre_change_attr = inode_peek_iversion_raw(inode);
fattr->valid |= NFS_ATTR_FATTR_PRECHANGE;
} if ((fattr->valid & NFS_ATTR_FATTR_CTIME) != 0 &&
(fattr->valid & NFS_ATTR_FATTR_PRECTIME) == 0) {
fattr->pre_ctime = inode_get_ctime(inode);
fattr->valid |= NFS_ATTR_FATTR_PRECTIME;
} if ((fattr->valid & NFS_ATTR_FATTR_MTIME) != 0 &&
(fattr->valid & NFS_ATTR_FATTR_PREMTIME) == 0) {
fattr->pre_mtime = inode_get_mtime(inode);
fattr->valid |= NFS_ATTR_FATTR_PREMTIME;
} if ((fattr->valid & NFS_ATTR_FATTR_SIZE) != 0 &&
(fattr->valid & NFS_ATTR_FATTR_PRESIZE) == 0) {
fattr->pre_size = i_size_read(inode);
fattr->valid |= NFS_ATTR_FATTR_PRESIZE;
}
out_noforce:
status = nfs_post_op_update_inode_locked(inode, fattr,
NFS_INO_INVALID_CHANGE
| NFS_INO_INVALID_CTIME
| NFS_INO_INVALID_MTIME
| NFS_INO_INVALID_BLOCKS); return status;
}
/** * nfs_post_op_update_inode_force_wcc - try to update the inode attribute cache * @inode: pointer to inode * @fattr: updated attributes * * After an operation that has changed the inode metadata, mark the * attribute cache as being invalid, then try to update it. Fake up * weak cache consistency data, if none exist. * * This function is mainly designed to be used by the ->write_done() functions.
*/ int nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fattr *fattr)
{ int status;
/* * Many nfs protocol calls return the new file attributes after * an operation. Here we update the inode to reflect the state * of the server's inode. * * This is a bit tricky because we have to make sure all dirty pages * have been sent off to the server before calling invalidate_inode_pages. * To make sure no other process adds more write requests while we try * our best to flush them, we make them sleep during the attribute refresh. * * A very similar scenario holds for the dir cache.
*/ staticint nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
{ struct nfs_server *server = NFS_SERVER(inode); struct nfs_inode *nfsi = NFS_I(inode);
loff_t cur_isize, new_isize;
u64 fattr_supported = server->fattr_valid; unsignedlong invalid = 0; unsignedlong now = jiffies; unsignedlong save_cache_validity; bool have_writers = nfs_file_has_buffered_writers(nfsi); bool cache_revalidated = true; bool attr_changed = false; bool have_delegation;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.