📄 inode.c
字号:
if (status == -ESTALE) { NFS_FLAGS(inode) |= NFS_INO_STALE; if (inode != inode->i_sb->s_root->d_inode) remove_inode_hash(inode); } goto out; } status = nfs_update_inode(inode, &fattr, verifier); if (status) { 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; } flags = nfsi->flags; /* * We may need to keep the attributes marked as invalid if * we raced with nfs_end_attr_update(). */ if (verifier == nfsi->cache_change_attribute) nfsi->flags &= ~(NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ATIME); /* Do the page cache invalidation */ if (flags & NFS_INO_INVALID_DATA) { if (S_ISREG(inode->i_mode)) { if (filemap_fdatawrite(inode->i_mapping) == 0) filemap_fdatawait(inode->i_mapping); nfs_wb_all(inode); } nfsi->flags &= ~NFS_INO_INVALID_DATA; invalidate_inode_pages2(inode->i_mapping); memset(NFS_COOKIEVERF(inode), 0, sizeof(NFS_COOKIEVERF(inode))); dfprintk(PAGECACHE, "NFS: (%s/%Ld) data cache invalidated\n", inode->i_sb->s_id, (long long)NFS_FILEID(inode)); /* This ensures we revalidate dentries */ nfsi->cache_change_attribute++; } dfprintk(PAGECACHE, "NFS: (%s/%Ld) revalidation complete\n", inode->i_sb->s_id, (long long)NFS_FILEID(inode)); NFS_FLAGS(inode) &= ~NFS_INO_STALE;out: NFS_FLAGS(inode) &= ~NFS_INO_REVALIDATING; wake_up(&nfsi->nfs_i_wait); 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_after(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_FLAGS(inode) & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA)) && !nfs_attribute_timeout(inode)) return NFS_STALE(inode) ? -ESTALE : 0; return __nfs_revalidate_inode(server, inode);}/** * nfs_begin_data_update * @inode - pointer to inode * Declare that a set of operations will update file data on the server */void nfs_begin_data_update(struct inode *inode){ atomic_inc(&NFS_I(inode)->data_updates);}/** * nfs_end_data_update * @inode - pointer to inode * Declare end of the operations that will update file data * This will mark the inode as immediately needing revalidation * of its attribute cache. */void nfs_end_data_update(struct inode *inode){ struct nfs_inode *nfsi = NFS_I(inode); if (!nfs_have_delegation(inode, FMODE_READ)) { /* Mark the attribute cache for revalidation */ nfsi->flags |= NFS_INO_INVALID_ATTR; /* Directories and symlinks: invalidate page cache too */ if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) nfsi->flags |= NFS_INO_INVALID_DATA; } nfsi->cache_change_attribute ++; atomic_dec(&nfsi->data_updates);}/** * nfs_end_data_update_defer * @inode - pointer to inode * Declare end of the operations that will update file data * This will defer marking the inode as needing revalidation * unless there are no other pending updates. */void nfs_end_data_update_defer(struct inode *inode){ struct nfs_inode *nfsi = NFS_I(inode); if (atomic_dec_and_test(&nfsi->data_updates)) { /* Mark the attribute cache for revalidation */ nfsi->flags |= NFS_INO_INVALID_ATTR; /* Directories and symlinks: invalidate page cache too */ if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) nfsi->flags |= NFS_INO_INVALID_DATA; nfsi->cache_change_attribute ++; }}/** * nfs_refresh_inode - 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. */int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr){ struct nfs_inode *nfsi = NFS_I(inode); loff_t cur_size, new_isize; int data_unstable; /* Do we hold a delegation? */ if (nfs_have_delegation(inode, FMODE_READ)) return 0; /* Are we in the process of updating data on the server? */ data_unstable = nfs_caches_unstable(inode); if (fattr->valid & NFS_ATTR_FATTR_V4) { if ((fattr->valid & NFS_ATTR_PRE_CHANGE) != 0 && nfsi->change_attr == fattr->pre_change_attr) nfsi->change_attr = fattr->change_attr; if (!data_unstable && nfsi->change_attr != fattr->change_attr) nfsi->flags |= NFS_INO_INVALID_ATTR; } if ((fattr->valid & NFS_ATTR_FATTR) == 0) return 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; cur_size = i_size_read(inode); new_isize = nfs_size_to_loff_t(fattr->size); /* 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)); } /* Verify a few of the more important attributes */ if (!data_unstable) { if (!timespec_equal(&inode->i_mtime, &fattr->mtime) || cur_size != new_isize) nfsi->flags |= NFS_INO_INVALID_ATTR; } else if (S_ISREG(inode->i_mode) && new_isize > cur_size) nfsi->flags |= NFS_INO_INVALID_ATTR; /* Have any file permissions changed? */ if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO) || inode->i_uid != fattr->uid || inode->i_gid != fattr->gid) nfsi->flags |= NFS_INO_INVALID_ATTR; /* Has the link count changed? */ if (inode->i_nlink != fattr->nlink) nfsi->flags |= NFS_INO_INVALID_ATTR; if (!timespec_equal(&inode->i_atime, &fattr->atime)) nfsi->flags |= NFS_INO_INVALID_ATIME; nfsi->read_cache_jiffies = fattr->timestamp; return 0;}/* * 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. */static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, unsigned long verifier){ struct nfs_inode *nfsi = NFS_I(inode); __u64 new_size; loff_t new_isize; unsigned int invalid = 0; loff_t cur_isize; int data_unstable; dfprintk(VFS, "NFS: %s(%s/%ld ct=%d info=0x%x)\n", __FUNCTION__, inode->i_sb->s_id, inode->i_ino, atomic_read(&inode->i_count), fattr->valid); if ((fattr->valid & NFS_ATTR_FATTR) == 0) return 0; if (nfsi->fileid != fattr->fileid) { printk(KERN_ERR "%s: inode number mismatch\n" "expected (%s/0x%Lx), got (%s/0x%Lx)\n", __FUNCTION__, inode->i_sb->s_id, (long long)nfsi->fileid, inode->i_sb->s_id, (long long)fattr->fileid); goto out_err; } /* * Make sure the inode's type hasn't changed. */ if ((inode->i_mode & S_IFMT) != (fattr->mode & S_IFMT)) goto out_changed; /* * Update the read time so we don't revalidate too often. */ nfsi->read_cache_jiffies = fattr->timestamp; /* Are we racing with known updates of the metadata on the server? */ data_unstable = ! nfs_verify_change_attribute(inode, verifier); /* Check if the file size agrees */ new_size = fattr->size; new_isize = nfs_size_to_loff_t(fattr->size); cur_isize = i_size_read(inode); if (cur_isize != new_size) {#ifdef NFS_DEBUG_VERBOSE printk(KERN_DEBUG "NFS: isize change on %s/%ld\n", inode->i_sb->s_id, inode->i_ino);#endif /* * If we have pending writebacks, things can get * messy. */ if (S_ISREG(inode->i_mode) && data_unstable) { if (new_isize > cur_isize) { inode->i_size = new_isize; invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA; } } else { inode->i_size = new_isize; invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA; } } /* * Note: we don't check inode->i_mtime since pipes etc. * can change this value in VFS without requiring a * cache revalidation. */ if (!timespec_equal(&inode->i_mtime, &fattr->mtime)) { memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime));#ifdef NFS_DEBUG_VERBOSE printk(KERN_DEBUG "NFS: mtime change on %s/%ld\n", inode->i_sb->s_id, inode->i_ino);#endif if (!data_unstable) invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA; } if ((fattr->valid & NFS_ATTR_FATTR_V4) && nfsi->change_attr != fattr->change_attr) {#ifdef NFS_DEBUG_VERBOSE printk(KERN_DEBUG "NFS: change_attr change on %s/%ld\n", inode->i_sb->s_id, inode->i_ino);#endif nfsi->change_attr = fattr->change_attr; if (!data_unstable) invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA; } memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime)); memcpy(&inode->i_atime, &fattr->atime, sizeof(inode->i_atime)); if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO) || inode->i_uid != fattr->uid || inode->i_gid != fattr->gid) { struct rpc_cred **cred = &NFS_I(inode)->cache_access.cred; if (*cred) { put_rpccred(*cred); *cred = NULL; } invalid |= NFS_INO_INVALID_ATTR; } inode->i_mode = fattr->mode; inode->i_nlink = fattr->nlink; inode->i_uid = fattr->uid; inode->i_gid = fattr->gid; if (fattr->valid & (NFS_ATTR_FATTR_V3 | NFS_ATTR_FATTR_V4)) { /* * report the blocks in 512byte units */ inode->i_blocks = nfs_calc_block_size(fattr->du.nfs3.used); inode->i_blksize = inode->i_sb->s_blocksize; } else { inode->i_blocks = fattr->du.nfs2.blocks; inode->i_blksize = fattr->du.nfs2.blocksize; } /* Update attrtimeo value if we're out of the unstable period */ if (invalid & NFS_INO_INVALID_ATTR) { nfsi->attrtimeo = NFS_MINATTRTIMEO(inode); nfsi->attrtimeo_timestamp = jiffies; } else if (time_after(jiffies, nfsi->attrtimeo_timestamp+nfsi->attrtimeo)) { if ((nfsi->attrtimeo <<= 1) > NFS_MAXATTRTIMEO(inode)) nfsi->attrtimeo = NFS_MAXATTRTIMEO(inode); nfsi->attrtimeo_timestamp = jiffies; } /* Don't invalidate the data if we were to blame */ if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))) invalid &= ~NFS_INO_INVALID_DATA; if (!nfs_have_delegation(inode, FMODE_READ)) nfsi->flags |= invalid; return 0; out_changed: /* * Big trouble! The inode has become a different object. */#ifdef NFS_PARANOIA printk(KERN_DEBUG "%s: inode %ld mode changed, %07o to %07o\n", __FUNCTION__, inode->i_ino, inode->i_mode, fattr->mode);#endif /* * No need to worry about unhashing the dentry, as the * lookup validation will know that the inode is bad. * (But we fall through to invalidate the caches.) */ nfs_invalidate_inode(inode); out_err: return -EIO;}/* * File system information */static int nfs_set_super(struct super_block *s, void *data){ s->s_fs_info = data; return set_anon_super(s, data);} static int nfs_compare_super(struct super_block *sb, void *data){ struct nfs_server *server = data; struct nfs_server *old = NFS_SB(sb); if (old->addr.sin_addr.s_addr != server->addr.sin_addr.s_addr) return 0; if (old->addr.sin_port != server->addr.sin_port) return 0; return !nfs_compare_fh(&old->fh, &server->fh);}static struct super_block *nfs_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name, void *raw_data){ int error; struct nfs_server *server; struct super_block *s; struct nfs_fh *root; struct nfs_mount_data *data = raw_data; if (!data) { printk("nfs_read_super: missing data argument\n"); return ERR_PTR(-EINVAL); } server = kmalloc(sizeof(struct nfs_server), GFP_KERNEL); if (!server) return ERR_PTR(-ENOMEM); memset(server, 0, sizeof(struct nfs_server)); /* Zero out the NFS state stuff */ init_nfsv4_state(server); if (data->version != NFS_MOUNT_VERSION) { printk("nfs warning: mount version %s than kernel\n", data->version < NFS_MOUNT_VERSION ? "older" : "newer"); if (data->version < 2) data->namlen = 0; if (data->version < 3) data->bsize = 0; if (data->version < 4) { data->flags &= ~NFS_MOUNT_VER3; data->root.size = NFS2_FHSIZE; memcpy(data->root.data, data->old_root.data, NFS2_FHSIZE); } if (data->version < 5) data->flags &= ~NFS_MOUNT_SECFLAVOUR; } root = &server->fh; if (data->flags & NFS_MOUNT_VER3) root->size = data->root.size; else root->size = NFS2_FHSIZE; if (root->size > sizeof(root->data)) { printk("nfs_get_sb: invalid root filehandle\n"); kfree(server); return ERR_PTR(-EINVAL); } memcpy(root->data, data->root.data, root->size); /* We now require that the mount process passes the remote address */ memcpy(&server->addr, &data->addr, sizeof(server->addr)); if (server->addr.sin_addr.s_addr == INADDR_ANY) { printk("NFS: mount program didn't pass remote address!\n"); kfree(server); return ERR_PTR(-EINVAL); } s = sget(fs_type, nfs_compare_super, nfs_set_super, server); if (IS_ERR(s) || s->s_root) { kfree(server); return s; } s->s_flags = flags; /* Fire up rpciod if not yet running */ if (rpciod_up() != 0) { printk(KERN_WARNING "NFS: couldn't start rpciod!\n"); kfree(server); return ERR_PTR(-EIO); } error = nfs_fill_super(s, data, flags & MS_VERBOSE ? 1 : 0); if (error) { up_write(&s->s_umount); deactivate_super(s); return ERR_PTR(error); } s->s_flags |= MS_ACTIVE; return s;}static void nfs_kill_super(struct super_block *s){ struct nfs_server *server = NFS_SB(s); kill_anon_super(s); nfs4_renewd_prepare_shutdown(server); if (server->client != NULL && !IS_ERR(server->client)) rpc_shutdown_client(server->client); if (server->client_sys != NULL && !IS_ERR(server->client_sys)) rpc_shutdown_client(server->client_sys); if (!(server->flags & NFS_MOUNT_NONLM)) lockd_down(); /* release rpc.lockd */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -