📄 inode.c
字号:
/* * Wait for the inode to get unlocked. */static int nfs_wait_on_inode(struct inode *inode){ struct rpc_clnt *clnt = NFS_CLIENT(inode); struct nfs_inode *nfsi = NFS_I(inode); sigset_t oldmask; int error; rpc_clnt_sigmask(clnt, &oldmask); error = wait_on_bit_lock(&nfsi->flags, NFS_INO_REVALIDATING, nfs_wait_schedule, TASK_INTERRUPTIBLE); rpc_clnt_sigunmask(clnt, &oldmask); return error;}static void nfs_wake_up_inode(struct inode *inode){ struct nfs_inode *nfsi = NFS_I(inode); clear_bit(NFS_INO_REVALIDATING, &nfsi->flags); smp_mb__after_clear_bit(); wake_up_bit(&nfsi->flags, NFS_INO_REVALIDATING);}int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat){ struct inode *inode = dentry->d_inode; int need_atime = NFS_I(inode)->cache_validity & NFS_INO_INVALID_ATIME; int err; /* Flush out writes to the server in order to update c/mtime */ if (S_ISREG(inode->i_mode)) nfs_wb_nocommit(inode); /* * 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 MS_NOATIME or MS_NODIRATIME so there is * no point in checking those. */ if ((mnt->mnt_flags & MNT_NOATIME) || ((mnt->mnt_flags & MNT_NODIRATIME) && S_ISDIR(inode->i_mode))) need_atime = 0; if (need_atime) err = __nfs_revalidate_inode(NFS_SERVER(inode), inode); else err = nfs_revalidate_inode(NFS_SERVER(inode), inode); if (!err) { generic_fillattr(inode, stat); stat->ino = nfs_compat_user_ino64(NFS_FILEID(inode)); } return err;}static struct nfs_open_context *alloc_nfs_open_context(struct vfsmount *mnt, struct dentry *dentry, struct rpc_cred *cred){ struct nfs_open_context *ctx; ctx = kmalloc(sizeof(*ctx), GFP_KERNEL); if (ctx != NULL) { ctx->path.dentry = dget(dentry); ctx->path.mnt = mntget(mnt); ctx->cred = get_rpccred(cred); ctx->state = NULL; ctx->lockowner = current->files; ctx->error = 0; ctx->dir_cookie = 0; atomic_set(&ctx->count, 1); } return ctx;}struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx){ if (ctx != NULL) atomic_inc(&ctx->count); return ctx;}static void __put_nfs_open_context(struct nfs_open_context *ctx, int wait){ struct inode *inode = ctx->path.dentry->d_inode; if (!atomic_dec_and_lock(&ctx->count, &inode->i_lock)) return; list_del(&ctx->list); spin_unlock(&inode->i_lock); if (ctx->state != NULL) { if (wait) nfs4_close_sync(&ctx->path, ctx->state, ctx->mode); else nfs4_close_state(&ctx->path, ctx->state, ctx->mode); } if (ctx->cred != NULL) put_rpccred(ctx->cred); dput(ctx->path.dentry); mntput(ctx->path.mnt); kfree(ctx);}void put_nfs_open_context(struct nfs_open_context *ctx){ __put_nfs_open_context(ctx, 0);}static void put_nfs_open_context_sync(struct nfs_open_context *ctx){ __put_nfs_open_context(ctx, 1);}/* * Ensure that mmap has a recent RPC credential for use when writing out * shared pages */static void nfs_file_set_open_context(struct file *filp, struct nfs_open_context *ctx){ struct inode *inode = filp->f_path.dentry->d_inode; struct nfs_inode *nfsi = NFS_I(inode); filp->private_data = get_nfs_open_context(ctx); spin_lock(&inode->i_lock); list_add(&ctx->list, &nfsi->open_files); spin_unlock(&inode->i_lock);}/* * Given an inode, search for an open context with the desired characteristics */struct nfs_open_context *nfs_find_open_context(struct inode *inode, struct rpc_cred *cred, int mode){ struct nfs_inode *nfsi = NFS_I(inode); struct nfs_open_context *pos, *ctx = NULL; spin_lock(&inode->i_lock); list_for_each_entry(pos, &nfsi->open_files, list) { if (cred != NULL && pos->cred != cred) continue; if ((pos->mode & mode) == mode) { ctx = get_nfs_open_context(pos); break; } } spin_unlock(&inode->i_lock); return ctx;}static void nfs_file_clear_open_context(struct file *filp){ struct inode *inode = filp->f_path.dentry->d_inode; struct nfs_open_context *ctx = nfs_file_open_context(filp); if (ctx) { filp->private_data = NULL; spin_lock(&inode->i_lock); list_move_tail(&ctx->list, &NFS_I(inode)->open_files); spin_unlock(&inode->i_lock); put_nfs_open_context_sync(ctx); }}/* * These allocate and release file read/write context information. */int nfs_open(struct inode *inode, struct file *filp){ struct nfs_open_context *ctx; struct rpc_cred *cred; cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0); if (IS_ERR(cred)) return PTR_ERR(cred); ctx = alloc_nfs_open_context(filp->f_path.mnt, filp->f_path.dentry, cred); put_rpccred(cred); if (ctx == NULL) return -ENOMEM; ctx->mode = filp->f_mode; nfs_file_set_open_context(filp, ctx); put_nfs_open_context(ctx); return 0;}int nfs_release(struct inode *inode, struct file *filp){ nfs_file_clear_open_context(filp); return 0;}/* * 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; struct nfs_inode *nfsi = NFS_I(inode); dfprintk(PAGECACHE, "NFS: revalidating (%s/%Ld)\n", inode->i_sb->s_id, (long long)NFS_FILEID(inode)); nfs_inc_stats(inode, NFSIOS_INODEREVALIDATE); lock_kernel(); if (is_bad_inode(inode)) goto out_nowait; if (NFS_STALE(inode)) goto out_nowait; status = nfs_wait_on_inode(inode); if (status < 0) goto out; status = -ESTALE; if (NFS_STALE(inode)) goto out; status = NFS_PROTO(inode)->getattr(server, NFS_FH(inode), &fattr); if (status != 0) { dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Ld) getattr failed, error=%d\n", inode->i_sb->s_id, (long long)NFS_FILEID(inode), status); if (status == -ESTALE) { nfs_zap_caches(inode); if (!S_ISDIR(inode->i_mode)) set_bit(NFS_INO_STALE, &NFS_FLAGS(inode)); } goto out; } spin_lock(&inode->i_lock); status = nfs_update_inode(inode, &fattr); if (status) { spin_unlock(&inode->i_lock); dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Ld) refresh failed, error=%d\n", inode->i_sb->s_id, (long long)NFS_FILEID(inode), status); goto out; } spin_unlock(&inode->i_lock); if (nfsi->cache_validity & NFS_INO_INVALID_ACL) nfs_zap_acl_cache(inode); dfprintk(PAGECACHE, "NFS: (%s/%Ld) revalidation complete\n", inode->i_sb->s_id, (long long)NFS_FILEID(inode)); out: nfs_wake_up_inode(inode); out_nowait: unlock_kernel(); return status;}int nfs_attribute_timeout(struct inode *inode){ struct nfs_inode *nfsi = NFS_I(inode); if (nfs_have_delegation(inode, FMODE_READ)) return 0; return !time_in_range(jiffies, nfsi->read_cache_jiffies, nfsi->read_cache_jiffies + nfsi->attrtimeo);}/** * nfs_revalidate_inode - Revalidate the inode attributes * @server - pointer to nfs_server struct * @inode - pointer to inode struct * * Updates inode attribute information by retrieving the data from the server. */int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode){ if (!(NFS_I(inode)->cache_validity & NFS_INO_INVALID_ATTR) && !nfs_attribute_timeout(inode)) return NFS_STALE(inode) ? -ESTALE : 0; return __nfs_revalidate_inode(server, inode);}static int nfs_invalidate_mapping_nolock(struct inode *inode, struct address_space *mapping){ struct nfs_inode *nfsi = NFS_I(inode); if (mapping->nrpages != 0) { int ret = invalidate_inode_pages2(mapping); if (ret < 0) return ret; } spin_lock(&inode->i_lock); nfsi->cache_validity &= ~NFS_INO_INVALID_DATA; if (S_ISDIR(inode->i_mode)) memset(nfsi->cookieverf, 0, sizeof(nfsi->cookieverf)); spin_unlock(&inode->i_lock); nfs_inc_stats(inode, NFSIOS_DATAINVALIDATE); dfprintk(PAGECACHE, "NFS: (%s/%Ld) data cache invalidated\n", inode->i_sb->s_id, (long long)NFS_FILEID(inode)); return 0;}static int nfs_invalidate_mapping(struct inode *inode, struct address_space *mapping){ int ret = 0; mutex_lock(&inode->i_mutex); if (NFS_I(inode)->cache_validity & NFS_INO_INVALID_DATA) { ret = nfs_sync_mapping(mapping); if (ret == 0) ret = nfs_invalidate_mapping_nolock(inode, mapping); } mutex_unlock(&inode->i_mutex); return ret;}/** * nfs_revalidate_mapping_nolock - Revalidate the pagecache * @inode - pointer to host inode * @mapping - pointer to mapping */int nfs_revalidate_mapping_nolock(struct inode *inode, struct address_space *mapping){ struct nfs_inode *nfsi = NFS_I(inode); int ret = 0; if ((nfsi->cache_validity & NFS_INO_REVAL_PAGECACHE) || nfs_attribute_timeout(inode) || NFS_STALE(inode)) { ret = __nfs_revalidate_inode(NFS_SERVER(inode), inode); if (ret < 0) goto out; } if (nfsi->cache_validity & NFS_INO_INVALID_DATA) ret = nfs_invalidate_mapping_nolock(inode, mapping);out: return ret;}/** * nfs_revalidate_mapping - Revalidate the pagecache * @inode - pointer to host inode * @mapping - pointer to mapping * * This version of the function will take the inode->i_mutex and attempt to * flush out all dirty data if it needs to invalidate the page cache. */int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping){ struct nfs_inode *nfsi = NFS_I(inode); int ret = 0; if ((nfsi->cache_validity & NFS_INO_REVAL_PAGECACHE) || nfs_attribute_timeout(inode) || NFS_STALE(inode)) { ret = __nfs_revalidate_inode(NFS_SERVER(inode), inode); if (ret < 0) goto out; } if (nfsi->cache_validity & NFS_INO_INVALID_DATA) ret = nfs_invalidate_mapping(inode, mapping);out: return ret;}static void nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr *fattr){ struct nfs_inode *nfsi = NFS_I(inode); if ((fattr->valid & NFS_ATTR_WCC_V4) != 0 && nfsi->change_attr == fattr->pre_change_attr) { nfsi->change_attr = fattr->change_attr; if (S_ISDIR(inode->i_mode)) nfsi->cache_validity |= NFS_INO_INVALID_DATA; } /* If we have atomic WCC data, we may update some attributes */ if ((fattr->valid & NFS_ATTR_WCC) != 0) { if (timespec_equal(&inode->i_ctime, &fattr->pre_ctime)) memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime)); if (timespec_equal(&inode->i_mtime, &fattr->pre_mtime)) { memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime)); if (S_ISDIR(inode->i_mode)) nfsi->cache_validity |= NFS_INO_INVALID_DATA; } if (inode->i_size == fattr->pre_size && nfsi->npages == 0) inode->i_size = fattr->size; }}/** * 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. */static int nfs_check_inode_attributes(struct inode *inode, struct nfs_fattr *fattr){ struct nfs_inode *nfsi = NFS_I(inode); loff_t cur_size, new_isize; unsigned long invalid = 0; /* Has the inode gone and changed behind our back? */ if (nfsi->fileid != fattr->fileid || (inode->i_mode & S_IFMT) != (fattr->mode & S_IFMT)) { return -EIO; } /* Do atomic weak cache consistency updates */ nfs_wcc_update_inode(inode, fattr); if ((fattr->valid & NFS_ATTR_FATTR_V4) != 0 && nfsi->change_attr != fattr->change_attr) invalid |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE; /* Verify a few of the more important attributes */ if (!timespec_equal(&inode->i_mtime, &fattr->mtime)) invalid |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE; cur_size = i_size_read(inode); new_isize = nfs_size_to_loff_t(fattr->size); if (cur_size != new_isize && nfsi->npages == 0) invalid |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -