#include <linux/vfs.h>
#include <linux/inet.h>
#include <linux/nfs_xdr.h>
-#include <linux/vserver/xid.h>
+#include <linux/vs_tag.h>
#include <asm/system.h>
#include <asm/uaccess.h>
static void nfs_zap_acl_cache(struct inode *);
-static kmem_cache_t * nfs_inode_cachep;
+static struct kmem_cache * nfs_inode_cachep;
+
+static inline unsigned long
+nfs_fattr_to_ino_t(struct nfs_fattr *fattr)
+{
+ return nfs_fileid_to_ino_t(fattr->fileid);
+}
int nfs_write_inode(struct inode *inode, int sync)
{
void nfs_clear_inode(struct inode *inode)
{
- struct nfs_inode *nfsi = NFS_I(inode);
- struct rpc_cred *cred;
-
/*
* The following should never happen...
*/
BUG_ON(nfs_have_writebacks(inode));
- BUG_ON (!list_empty(&nfsi->open_files));
+ BUG_ON(!list_empty(&NFS_I(inode)->open_files));
+ BUG_ON(atomic_read(&NFS_I(inode)->data_updates) != 0);
nfs_zap_acl_cache(inode);
- cred = nfsi->cache_access.cred;
- if (cred)
- put_rpccred(cred);
-
- nfs_fscache_release_fh_cookie(NFS_SERVER(inode), nfsi);
- BUG_ON(atomic_read(&nfsi->data_updates) != 0);
+ nfs_access_zap_cache(inode);
}
/**
spin_lock(&inode->i_lock);
nfs_zap_caches_locked(inode);
spin_unlock(&inode->i_lock);
+}
- nfs_fscache_zap_fh_cookie(NFS_SERVER(inode), NFS_I(inode));
+void nfs_zap_mapping(struct inode *inode, struct address_space *mapping)
+{
+ if (mapping->nrpages != 0) {
+ spin_lock(&inode->i_lock);
+ NFS_I(inode)->cache_validity |= NFS_INO_INVALID_DATA;
+ spin_unlock(&inode->i_lock);
+ }
}
static void nfs_zap_acl_cache(struct inode *inode)
};
struct inode *inode = ERR_PTR(-ENOENT);
unsigned long hash;
- int maycache = 1;
if ((fattr->valid & NFS_ATTR_FATTR) == 0)
goto out_no_inode;
goto out_no_inode;
}
- hash = fattr->fileid;
- if (sizeof(hash) < sizeof(u64))
- hash ^= fattr->fileid >> (sizeof(u64) - sizeof(ino_t)) * 8;
+ hash = nfs_fattr_to_ino_t(fattr);
inode = iget5_locked(sb, hash, nfs_find_actor, nfs_init_locked, &desc);
if (inode == NULL) {
if (inode->i_state & I_NEW) {
struct nfs_inode *nfsi = NFS_I(inode);
- /* We set i_ino for the few things that still rely on it, such
- * as printing messages; stat and filldir use the fileid
- * directly since i_ino may not be large enough */
- inode->i_ino = fattr->fileid;
+ /* We set i_ino for the few things that still rely on it,
+ * such as stat(2) */
+ inode->i_ino = hash;
/* We can't support update_atime(), since the server will reset it */
inode->i_flags |= S_NOATIME|S_NOCMTIME;
else
inode->i_op = &nfs_mountpoint_inode_operations;
inode->i_fop = NULL;
- maycache = 0;
}
} else if (S_ISLNK(inode->i_mode))
inode->i_op = &nfs_symlink_inode_operations;
nfsi->change_attr = fattr->change_attr;
inode->i_size = nfs_size_to_loff_t(fattr->size);
inode->i_nlink = fattr->nlink;
- inode->i_uid = INOXID_UID(XID_TAG(inode), fattr->uid, fattr->gid);
- inode->i_gid = INOXID_GID(XID_TAG(inode), fattr->uid, fattr->gid);
- inode->i_xid = INOXID_XID(XID_TAG(inode), fattr->uid, fattr->gid, 0);
+ inode->i_uid = INOTAG_UID(DX_TAG(inode), fattr->uid, fattr->gid);
+ inode->i_gid = INOTAG_GID(DX_TAG(inode), fattr->uid, fattr->gid);
+ inode->i_tag = INOTAG_TAG(DX_TAG(inode), fattr->uid, fattr->gid, 0);
/* maybe fattr->xid someday */
if (fattr->valid & (NFS_ATTR_FATTR_V3 | NFS_ATTR_FATTR_V4)) {
/*
nfsi->attrtimeo = NFS_MINATTRTIMEO(inode);
nfsi->attrtimeo_timestamp = jiffies;
memset(nfsi->cookieverf, 0, sizeof(nfsi->cookieverf));
- nfsi->cache_access.cred = NULL;
-
- nfs_fscache_get_fh_cookie(sb, nfsi, maycache);
+ nfsi->access_cache = RB_ROOT;
unlock_new_inode(inode);
} else
lock_kernel();
nfs_begin_data_update(inode);
/* Write all dirty data */
- filemap_write_and_wait(inode->i_mapping);
- nfs_wb_all(inode);
+ if (S_ISREG(inode->i_mode)) {
+ filemap_write_and_wait(inode->i_mapping);
+ nfs_wb_all(inode);
+ }
/*
* Return any delegations if we're going to change ACLs
*/
inode->i_uid = attr->ia_uid;
if ((attr->ia_valid & ATTR_GID) != 0)
inode->i_gid = attr->ia_gid;
- if ((attr->ia_valid & ATTR_XID) && IS_TAGXID(inode))
- inode->i_xid = attr->ia_xid;
+ if ((attr->ia_valid & ATTR_TAG) && IS_TAGGED(inode))
+ inode->i_tag = attr->ia_tag;
spin_lock(&inode->i_lock);
NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
spin_unlock(&inode->i_lock);
if ((attr->ia_valid & ATTR_SIZE) != 0) {
nfs_inc_stats(inode, NFSIOS_SETATTRTRUNC);
inode->i_size = attr->ia_size;
- nfs_fscache_set_size(NFS_SERVER(inode), NFS_I(inode), inode->i_size);
vmtruncate(inode, attr->ia_size);
}
}
int err;
/* Flush out writes to the server in order to update c/mtime */
- nfs_sync_inode_wait(inode, 0, 0, FLUSH_NOCOMMIT);
+ if (S_ISREG(inode->i_mode))
+ nfs_sync_mapping_range(inode->i_mapping, 0, 0, FLUSH_NOCOMMIT);
/*
* We may force a getattr if the user cares about atime.
err = __nfs_revalidate_inode(NFS_SERVER(inode), inode);
else
err = nfs_revalidate_inode(NFS_SERVER(inode), inode);
- if (!err) {
+ if (!err)
generic_fillattr(inode, stat);
- stat->ino = NFS_FILEID(inode);
- }
return err;
}
{
struct nfs_open_context *ctx;
- ctx = (struct nfs_open_context *)kmalloc(sizeof(*ctx), GFP_KERNEL);
+ ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
if (ctx != NULL) {
atomic_set(&ctx->count, 1);
ctx->dentry = dget(dentry);
*/
static void nfs_file_set_open_context(struct file *filp, struct nfs_open_context *ctx)
{
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct nfs_inode *nfsi = NFS_I(inode);
filp->private_data = get_nfs_open_context(ctx);
static void nfs_file_clear_open_context(struct file *filp)
{
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct nfs_open_context *ctx = (struct nfs_open_context *)filp->private_data;
if (ctx) {
cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0);
if (IS_ERR(cred))
return PTR_ERR(cred);
- ctx = alloc_nfs_open_context(filp->f_vfsmnt, filp->f_dentry, 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);
- if ((filp->f_flags & O_ACCMODE) != O_RDONLY)
- nfs_fscache_disable_fh_cookie(inode);
return 0;
}
nfs_inc_stats(inode, NFSIOS_INODEREVALIDATE);
lock_kernel();
- if (!inode || is_bad_inode(inode))
+ if (is_bad_inode(inode))
goto out_nowait;
if (NFS_STALE(inode))
goto out_nowait;
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));
+ /* This ensures we revalidate child dentries */
+ nfsi->cache_change_attribute = jiffies;
+ }
+ 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 - Revalidate the pagecache
+ * nfs_revalidate_mapping_nolock - Revalidate the pagecache
* @inode - pointer to host inode
* @mapping - pointer to mapping
*/
-int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping)
+int nfs_revalidate_mapping_nolock(struct inode *inode, struct address_space *mapping)
{
struct nfs_inode *nfsi = NFS_I(inode);
int ret = 0;
- if (NFS_STALE(inode))
- ret = -ESTALE;
if ((nfsi->cache_validity & NFS_INO_REVAL_PAGECACHE)
- || nfs_attribute_timeout(inode))
+ || 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;
+}
- if (nfsi->cache_validity & NFS_INO_INVALID_DATA) {
- nfs_inc_stats(inode, NFSIOS_DATAINVALIDATE);
- if (S_ISREG(inode->i_mode))
- nfs_sync_mapping(mapping);
- invalidate_inode_pages2(mapping);
-
- 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));
- /* This ensures we revalidate child dentries */
- nfsi->cache_change_attribute = jiffies;
- }
- spin_unlock(&inode->i_lock);
-
- nfs_fscache_renew_fh_cookie(NFS_SERVER(inode), nfsi);
+/**
+ * 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;
- dfprintk(PAGECACHE, "NFS: (%s/%Ld) data cache invalidated\n",
- inode->i_sb->s_id,
- (long long)NFS_FILEID(inode));
+ 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;
}
{
struct nfs_inode *nfsi = NFS_I(inode);
- if (!nfs_have_delegation(inode, FMODE_READ)) {
- /* Directories and symlinks: invalidate page cache */
- if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) {
- spin_lock(&inode->i_lock);
- nfsi->cache_validity |= NFS_INO_INVALID_DATA;
- spin_unlock(&inode->i_lock);
- }
+ /* Directories: invalidate page cache */
+ if (S_ISDIR(inode->i_mode)) {
+ spin_lock(&inode->i_lock);
+ nfsi->cache_validity |= NFS_INO_INVALID_DATA;
+ spin_unlock(&inode->i_lock);
}
nfsi->cache_change_attribute = jiffies;
atomic_dec(&nfsi->data_updates);
int data_unstable;
uid_t uid;
gid_t gid;
- xid_t xid;
+ tag_t tag;
/* Has the inode gone and changed behind our back? */
if (cur_size != new_isize && nfsi->npages == 0)
nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE;
- uid = INOXID_UID(XID_TAG(inode), fattr->uid, fattr->gid);
- gid = INOXID_GID(XID_TAG(inode), fattr->uid, fattr->gid);
- xid = INOXID_XID(XID_TAG(inode), fattr->uid, fattr->gid, 0);
+ uid = INOTAG_UID(DX_TAG(inode), fattr->uid, fattr->gid);
+ gid = INOTAG_GID(DX_TAG(inode), fattr->uid, fattr->gid);
+ tag = INOTAG_TAG(DX_TAG(inode), fattr->uid, fattr->gid, 0);
/* Have any file permissions changed? */
if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO)
|| inode->i_uid != uid
|| inode->i_gid != gid
- || inode->i_xid != xid)
+ || inode->i_tag != tag)
nfsi->cache_validity |= NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ACCESS | NFS_INO_INVALID_ACL;
/* Has the link count changed? */
*
* 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 data_stable;
uid_t uid;
gid_t gid;
- xid_t xid;
+ tag_t tag;
dfprintk(VFS, "NFS: %s(%s/%ld ct=%d info=0x%x)\n",
__FUNCTION__, inode->i_sb->s_id, inode->i_ino,
if (data_stable) {
inode->i_size = new_isize;
invalid |= NFS_INO_INVALID_DATA;
- nfs_fscache_set_size(NFS_SERVER(inode), nfsi, inode->i_size);
}
invalid |= NFS_INO_INVALID_ATTR;
} else if (new_isize > cur_isize) {
inode->i_size = new_isize;
invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;
- nfs_fscache_set_size(NFS_SERVER(inode), nfsi, inode->i_size);
}
nfsi->cache_change_attribute = jiffies;
dprintk("NFS: isize change on server for file %s/%ld\n",
}
memcpy(&inode->i_atime, &fattr->atime, sizeof(inode->i_atime));
- uid = INOXID_UID(XID_TAG(inode), fattr->uid, fattr->gid);
- gid = INOXID_GID(XID_TAG(inode), fattr->uid, fattr->gid);
- xid = INOXID_XID(XID_TAG(inode), fattr->uid, fattr->gid, 0);
+ uid = INOTAG_UID(DX_TAG(inode), fattr->uid, fattr->gid);
+ gid = INOTAG_GID(DX_TAG(inode), fattr->uid, fattr->gid);
+ tag = INOTAG_TAG(DX_TAG(inode), fattr->uid, fattr->gid, 0);
if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO) ||
inode->i_uid != uid ||
inode->i_gid != gid ||
- inode->i_xid != xid)
+ inode->i_tag != tag)
invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
inode->i_mode = fattr->mode;
inode->i_nlink = fattr->nlink;
inode->i_uid = uid;
inode->i_gid = gid;
- inode->i_xid = xid;
+ inode->i_tag = tag;
if (fattr->valid & (NFS_ATTR_FATTR_V3 | NFS_ATTR_FATTR_V4)) {
/*
struct inode *nfs_alloc_inode(struct super_block *sb)
{
struct nfs_inode *nfsi;
- nfsi = (struct nfs_inode *)kmem_cache_alloc(nfs_inode_cachep, SLAB_KERNEL);
+ nfsi = (struct nfs_inode *)kmem_cache_alloc(nfs_inode_cachep, GFP_KERNEL);
if (!nfsi)
return NULL;
nfsi->flags = 0UL;
#endif
}
-static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
+static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flags)
{
struct nfs_inode *nfsi = (struct nfs_inode *) foo;
INIT_LIST_HEAD(&nfsi->dirty);
INIT_LIST_HEAD(&nfsi->commit);
INIT_LIST_HEAD(&nfsi->open_files);
+ INIT_LIST_HEAD(&nfsi->access_cache_entry_lru);
+ INIT_LIST_HEAD(&nfsi->access_cache_inode_lru);
INIT_RADIX_TREE(&nfsi->nfs_page_tree, GFP_ATOMIC);
atomic_set(&nfsi->data_updates, 0);
nfsi->ndirty = 0;
static void nfs_destroy_inodecache(void)
{
- if (kmem_cache_destroy(nfs_inode_cachep))
- printk(KERN_INFO "nfs_inode_cache: not all structures were freed\n");
+ kmem_cache_destroy(nfs_inode_cachep);
}
/*
{
int err;
- err = nfs_fscache_register();
- if (err < 0)
- goto out6;
-
err = nfs_fs_proc_init();
if (err)
goto out5;
out4:
nfs_fs_proc_exit();
out5:
- nfs_fscache_unregister();
-out6:
return err;
}
nfs_destroy_readpagecache();
nfs_destroy_inodecache();
nfs_destroy_nfspagecache();
- nfs_fscache_unregister();
#ifdef CONFIG_PROC_FS
rpc_proc_unregister("nfs");
#endif