#include <linux/mount.h>
#include <linux/nfs_idmap.h>
#include <linux/vfs.h>
+#include <linux/vserver/xid.h>
#include <asm/system.h>
#include <asm/uaccess.h>
+#include "delegation.h"
+
#define NFSDBG_FACILITY NFSDBG_VFS
#define NFS_PARANOIA 1
static struct inode *nfs_alloc_inode(struct super_block *sb);
static void nfs_destroy_inode(struct inode *);
-static void nfs_write_inode(struct inode *,int);
+static int nfs_write_inode(struct inode *,int);
static void nfs_delete_inode(struct inode *);
-static void nfs_put_super(struct super_block *);
static void nfs_clear_inode(struct inode *);
static void nfs_umount_begin(struct super_block *);
static int nfs_statfs(struct super_block *, struct kstatfs *);
.destroy_inode = nfs_destroy_inode,
.write_inode = nfs_write_inode,
.delete_inode = nfs_delete_inode,
- .put_super = nfs_put_super,
.statfs = nfs_statfs,
.clear_inode = nfs_clear_inode,
.umount_begin = nfs_umount_begin,
return nfs_fileid_to_ino_t(fattr->fileid);
}
-static void
+static int
nfs_write_inode(struct inode *inode, int sync)
{
int flags = sync ? FLUSH_WAIT : 0;
+ int ret;
- nfs_commit_inode(inode, 0, 0, flags);
+ ret = nfs_commit_inode(inode, 0, 0, flags);
+ if (ret < 0)
+ return ret;
+ return 0;
}
static void
{
dprintk("NFS: delete_inode(%s/%ld)\n", inode->i_sb->s_id, inode->i_ino);
+ nfs_wb_all(inode);
/*
- * The following can never actually happen...
+ * The following should never happen...
*/
if (nfs_have_writebacks(inode)) {
printk(KERN_ERR "nfs_delete_inode: inode %ld has pending RPC requests\n", inode->i_ino);
nfs_clear_inode(struct inode *inode)
{
struct nfs_inode *nfsi = NFS_I(inode);
- struct rpc_cred *cred = nfsi->mm_cred;
+ struct rpc_cred *cred;
- if (cred)
- put_rpccred(cred);
+ nfs_wb_all(inode);
+ BUG_ON (!list_empty(&nfsi->open_files));
cred = nfsi->cache_access.cred;
if (cred)
put_rpccred(cred);
BUG_ON(atomic_read(&nfsi->data_updates) != 0);
}
-void
-nfs_put_super(struct super_block *sb)
-{
- struct nfs_server *server = NFS_SB(sb);
-
- nfs4_renewd_prepare_shutdown(server);
-
- if (server->client != NULL)
- rpc_shutdown_client(server->client);
- if (server->client_sys != NULL)
- rpc_shutdown_client(server->client_sys);
-
- if (!(server->flags & NFS_MOUNT_NONLM))
- lockd_down(); /* release rpc.lockd */
- rpciod_down(); /* release rpciod */
-
- destroy_nfsv4_state(server);
-
- kfree(server->hostname);
-}
-
void
nfs_umount_begin(struct super_block *sb)
{
error = server->rpc_ops->getroot(server, rootfh, fsinfo);
if (error < 0) {
- printk(KERN_NOTICE "nfs_get_root: getattr error = %d\n", -error);
+ dprintk("nfs_get_root: getattr error = %d\n", -error);
return ERR_PTR(error);
}
struct nfs_pathconf pathinfo = {
.fattr = &fattr,
};
+ int no_root_error = 0;
/* We probably want something more informative here */
snprintf(sb->s_id, sizeof(sb->s_id), "%x:%x", MAJOR(sb->s_dev), MINOR(sb->s_dev));
root_inode = nfs_get_root(sb, &server->fh, &fsinfo);
/* Did getting the root inode fail? */
- if (IS_ERR(root_inode))
+ if (IS_ERR(root_inode)) {
+ no_root_error = PTR_ERR(root_inode);
goto out_no_root;
+ }
sb->s_root = d_alloc_root(root_inode);
- if (!sb->s_root)
+ if (!sb->s_root) {
+ no_root_error = -ENOMEM;
goto out_no_root;
-
+ }
sb->s_root->d_op = server->rpc_ops->dentry_ops;
/* Get some general file system info */
server->rsize = nfs_block_size(fsinfo.rtpref, NULL);
if (server->wsize == 0)
server->wsize = nfs_block_size(fsinfo.wtpref, NULL);
- if (sb->s_blocksize == 0) {
- if (fsinfo.wtmult == 0) {
- sb->s_blocksize = 512;
- sb->s_blocksize_bits = 9;
- } else
- sb->s_blocksize = nfs_block_bits(fsinfo.wtmult,
- &sb->s_blocksize_bits);
- }
if (fsinfo.rtmax >= 512 && server->rsize > fsinfo.rtmax)
server->rsize = nfs_block_size(fsinfo.rtmax, NULL);
server->wsize = server->wpages << PAGE_CACHE_SHIFT;
}
+ if (sb->s_blocksize == 0)
+ sb->s_blocksize = nfs_block_bits(server->wsize,
+ &sb->s_blocksize_bits);
+ server->wtmult = nfs_block_bits(fsinfo.wtmult, NULL);
+
server->dtsize = nfs_block_size(fsinfo.dtpref, NULL);
if (server->dtsize > PAGE_CACHE_SIZE)
server->dtsize = PAGE_CACHE_SIZE;
}
server->backing_dev_info.ra_pages = server->rpages * NFS_MAX_READAHEAD;
+ if (server->flags & NFS_MOUNT_TAGXID)
+ sb->s_flags |= MS_TAGXID;
+
sb->s_maxbytes = fsinfo.maxfilesize;
if (sb->s_maxbytes > MAX_LFS_FILESIZE)
sb->s_maxbytes = MAX_LFS_FILESIZE;
return 0;
/* Yargs. It didn't work out. */
out_no_root:
- printk("nfs_read_super: get root inode failed\n");
+ dprintk("nfs_sb_init: get root inode failed: errno %d\n", -no_root_error);
if (!IS_ERR(root_inode))
iput(root_inode);
- return -EINVAL;
+ return no_root_error;
}
/*
clnt->cl_intr = (server->flags & NFS_MOUNT_INTR) ? 1 : 0;
clnt->cl_softrtry = (server->flags & NFS_MOUNT_SOFT) ? 1 : 0;
clnt->cl_droppriv = (server->flags & NFS_MOUNT_BROKEN_SUID) ? 1 : 0;
+ clnt->cl_tagxid = (server->flags & NFS_MOUNT_TAGXID) ? 1 : 0;
clnt->cl_chatty = 1;
return clnt;
nfs_fill_super(struct super_block *sb, struct nfs_mount_data *data, int silent)
{
struct nfs_server *server;
- int err = -EIO;
rpc_authflavor_t authflavor;
server = NFS_SB(sb);
server->acdirmin = data->acdirmin*HZ;
server->acdirmax = data->acdirmax*HZ;
+ /* Start lockd here, before we might error out */
+ if (!(server->flags & NFS_MOUNT_NONLM))
+ lockd_up();
+
server->namelen = data->namlen;
server->hostname = kmalloc(strlen(data->hostname) + 1, GFP_KERNEL);
if (!server->hostname)
- goto out_fail;
+ return -ENOMEM;
strcpy(server->hostname, data->hostname);
/* Check NFS protocol revision and initialize RPC op vector
server->caps |= NFS_CAP_READDIRPLUS;
if (data->version < 4) {
printk(KERN_NOTICE "NFS: NFSv3 not supported by mount program.\n");
- goto out_fail;
+ return -EIO;
}
#else
printk(KERN_NOTICE "NFS: NFSv3 not supported.\n");
- goto out_fail;
+ return -EIO;
#endif
} else {
server->rpc_ops = &nfs_v2_clientops;
/* Create RPC client handles */
server->client = nfs_create_client(server, data);
- if (server->client == NULL)
- goto out_fail;
+ if (IS_ERR(server->client))
+ return PTR_ERR(server->client);
/* RFC 2623, sec 2.3.2 */
if (authflavor != RPC_AUTH_UNIX) {
server->client_sys = rpc_clone_client(server->client);
- if (server->client_sys == NULL)
- goto out_shutdown;
+ if (IS_ERR(server->client_sys))
+ return PTR_ERR(server->client_sys);
if (!rpcauth_create(RPC_AUTH_UNIX, server->client_sys))
- goto out_shutdown;
+ return -ENOMEM;
} else {
atomic_inc(&server->client->cl_count);
server->client_sys = server->client;
}
- /* Fire up rpciod if not yet running */
- if (rpciod_up() != 0) {
- printk(KERN_WARNING "NFS: couldn't start rpciod!\n");
- goto out_shutdown;
- }
-
- sb->s_op = &nfs_sops;
- err = nfs_sb_init(sb, authflavor);
- if (err != 0)
- goto out_noinit;
-
if (server->flags & NFS_MOUNT_VER3) {
if (server->namelen == 0 || server->namelen > NFS3_MAXNAMLEN)
server->namelen = NFS3_MAXNAMLEN;
server->namelen = NFS2_MAXNAMLEN;
}
- /* Check whether to start the lockd process */
- if (!(server->flags & NFS_MOUNT_NONLM))
- lockd_up();
- return 0;
-out_noinit:
- rpciod_down();
-out_shutdown:
- if (server->client)
- rpc_shutdown_client(server->client);
- if (server->client_sys)
- rpc_shutdown_client(server->client_sys);
-out_fail:
- if (server->hostname)
- kfree(server->hostname);
- return err;
+ sb->s_op = &nfs_sops;
+ return nfs_sb_init(sb, authflavor);
}
static int
if (error < 0)
goto out_err;
+ buf->f_frsize = server->wtmult;
buf->f_bsize = sb->s_blocksize;
blockbits = sb->s_blocksize_bits;
blockres = (1 << blockbits) - 1;
{ NFS_MOUNT_NOAC, ",noac", "" },
{ NFS_MOUNT_NONLM, ",nolock", ",lock" },
{ NFS_MOUNT_BROKEN_SUID, ",broken_suid", "" },
+ { NFS_MOUNT_TAGXID, ",tagxid", "" },
{ 0, NULL, NULL }
};
struct proc_nfs_info *nfs_infop;
if (NFS_FILEID(inode) != fattr->fileid)
return 0;
- if (memcmp(NFS_FH(inode), fh, sizeof(struct nfs_fh)) != 0)
+ if (nfs_compare_fh(NFS_FH(inode), fh))
return 0;
if (is_bad_inode(inode))
return 0;
nfs_init_locked(struct inode *inode, void *opaque)
{
struct nfs_find_desc *desc = (struct nfs_find_desc *)opaque;
- struct nfs_fh *fh = desc->fh;
struct nfs_fattr *fattr = desc->fattr;
NFS_FILEID(inode) = fattr->fileid;
- memcpy(NFS_FH(inode), fh, sizeof(struct nfs_fh));
+ nfs_copy_fh(NFS_FH(inode), desc->fh);
return 0;
}
nfsi->change_attr = fattr->change_attr;
inode->i_size = nfs_size_to_loff_t(fattr->size);
inode->i_nlink = fattr->nlink;
- inode->i_uid = fattr->uid;
- inode->i_gid = fattr->gid;
+ 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);
+ /* maybe fattr->xid someday */
if (fattr->valid & (NFS_ATTR_FATTR_V3 | NFS_ATTR_FATTR_V4)) {
/*
* report the blocks in 512byte units
out:
return inode;
-
+/*
+fail_dlim:
+ make_bad_inode(inode);
+ iput(inode);
+ inode = NULL;
+*/
out_no_inode:
printk("nfs_fhget: iget failed\n");
goto out;
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) != 0)
+ inode->i_xid = attr->ia_xid;
if ((attr->ia_valid & ATTR_SIZE) != 0) {
inode->i_size = attr->ia_size;
vmtruncate(inode, attr->ia_size);
return err;
}
+struct nfs_open_context *alloc_nfs_open_context(struct dentry *dentry, struct rpc_cred *cred)
+{
+ struct nfs_open_context *ctx;
+
+ ctx = (struct nfs_open_context *)kmalloc(sizeof(*ctx), GFP_KERNEL);
+ if (ctx != NULL) {
+ atomic_set(&ctx->count, 1);
+ ctx->dentry = dget(dentry);
+ ctx->cred = get_rpccred(cred);
+ ctx->state = NULL;
+ ctx->lockowner = current->files;
+ ctx->error = 0;
+ init_waitqueue_head(&ctx->waitq);
+ }
+ return ctx;
+}
+
+struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx)
+{
+ if (ctx != NULL)
+ atomic_inc(&ctx->count);
+ return ctx;
+}
+
+void put_nfs_open_context(struct nfs_open_context *ctx)
+{
+ if (atomic_dec_and_test(&ctx->count)) {
+ if (ctx->state != NULL)
+ nfs4_close_state(ctx->state, ctx->mode);
+ if (ctx->cred != NULL)
+ put_rpccred(ctx->cred);
+ dput(ctx->dentry);
+ kfree(ctx);
+ }
+}
+
/*
* Ensure that mmap has a recent RPC credential for use when writing out
* shared pages
*/
-void
-nfs_set_mmcred(struct inode *inode, struct rpc_cred *cred)
+void nfs_file_set_open_context(struct file *filp, struct nfs_open_context *ctx)
+{
+ struct inode *inode = filp->f_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);
+}
+
+struct nfs_open_context *nfs_find_open_context(struct inode *inode, int mode)
{
- struct rpc_cred **p = &NFS_I(inode)->mm_cred,
- *oldcred = *p;
+ struct nfs_inode *nfsi = NFS_I(inode);
+ struct nfs_open_context *pos, *ctx = NULL;
- *p = get_rpccred(cred);
- if (oldcred)
- put_rpccred(oldcred);
+ spin_lock(&inode->i_lock);
+ list_for_each_entry(pos, &nfsi->open_files, list) {
+ if ((pos->mode & mode) == mode) {
+ ctx = get_nfs_open_context(pos);
+ break;
+ }
+ }
+ spin_unlock(&inode->i_lock);
+ return ctx;
+}
+
+void nfs_file_clear_open_context(struct file *filp)
+{
+ struct inode *inode = filp->f_dentry->d_inode;
+ struct nfs_open_context *ctx = (struct nfs_open_context *)filp->private_data;
+
+ if (ctx) {
+ filp->private_data = NULL;
+ spin_lock(&inode->i_lock);
+ list_del(&ctx->list);
+ spin_unlock(&inode->i_lock);
+ put_nfs_open_context(ctx);
+ }
}
/*
- * These are probably going to contain hooks for
- * allocating and releasing RPC credentials for
- * the file. I'll have to think about Tronds patch
- * a bit more..
+ * These allocate and release file read/write context information.
*/
int nfs_open(struct inode *inode, struct file *filp)
{
- struct rpc_auth *auth;
+ struct nfs_open_context *ctx;
struct rpc_cred *cred;
- auth = NFS_CLIENT(inode)->cl_auth;
- cred = rpcauth_lookupcred(auth, 0);
- filp->private_data = cred;
- if ((filp->f_mode & FMODE_WRITE) != 0) {
- nfs_set_mmcred(inode, cred);
+ if ((cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0)) == NULL)
+ return -ENOMEM;
+ ctx = alloc_nfs_open_context(filp->f_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_mode & FMODE_WRITE) != 0)
nfs_begin_data_update(inode);
- }
return 0;
}
int nfs_release(struct inode *inode, struct file *filp)
{
- struct rpc_cred *cred;
-
- lock_kernel();
if ((filp->f_mode & FMODE_WRITE) != 0)
nfs_end_data_update(inode);
- cred = nfs_file_cred(filp);
- if (cred)
- put_rpccred(cred);
- unlock_kernel();
+ nfs_file_clear_open_context(filp);
return 0;
}
/* Protect against RPC races by saving the change attribute */
verifier = nfs_save_change_attribute(inode);
- status = NFS_PROTO(inode)->getattr(inode, &fattr);
+ status = NFS_PROTO(inode)->getattr(server, NFS_FH(inode), &fattr);
if (status) {
dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Ld) getattr failed, error=%d\n",
inode->i_sb->s_id,
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
{
struct nfs_inode *nfsi = NFS_I(inode);
- /* 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;
+ 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);
}
struct nfs_inode *nfsi = NFS_I(inode);
loff_t cur_size, new_isize;
int data_unstable;
+ uid_t uid;
+ gid_t gid;
+ xid_t xid = 0;
+
+ /* 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);
} else if (S_ISREG(inode->i_mode) && new_isize > cur_size)
nfsi->flags |= NFS_INO_INVALID_ATTR;
+ 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);
+
/* 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)
+ || inode->i_uid != uid
+ || inode->i_gid != gid
+ || inode->i_xid != xid)
nfsi->flags |= NFS_INO_INVALID_ATTR;
/* Has the link count changed? */
unsigned int invalid = 0;
loff_t cur_isize;
int data_unstable;
+ uid_t uid;
+ gid_t gid;
+ xid_t xid = 0;
dfprintk(VFS, "NFS: %s(%s/%ld ct=%d info=0x%x)\n",
__FUNCTION__, inode->i_sb->s_id, inode->i_ino,
memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime));
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);
+
if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO) ||
- inode->i_uid != fattr->uid ||
- inode->i_gid != fattr->gid) {
+ inode->i_uid != uid ||
+ inode->i_gid != gid ||
+ inode->i_xid != xid) {
struct rpc_cred **cred = &NFS_I(inode)->cache_access.cred;
if (*cred) {
put_rpccred(*cred);
inode->i_mode = fattr->mode;
inode->i_nlink = fattr->nlink;
- inode->i_uid = fattr->uid;
- inode->i_gid = fattr->gid;
+ inode->i_uid = uid;
+ inode->i_gid = gid;
+ inode->i_xid = xid;
if (fattr->valid & (NFS_ATTR_FATTR_V3 | NFS_ATTR_FATTR_V4)) {
/*
if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode)
|| S_ISLNK(inode->i_mode)))
invalid &= ~NFS_INO_INVALID_DATA;
- nfsi->flags |= invalid;
+ if (!nfs_have_delegation(inode, FMODE_READ))
+ nfsi->flags |= invalid;
return 0;
out_changed:
return 0;
if (old->addr.sin_port != server->addr.sin_port)
return 0;
- return !memcmp(&old->fh, &server->fh, sizeof(struct nfs_fh));
+ return !nfs_compare_fh(&old->fh, &server->fh);
}
static struct super_block *nfs_get_sb(struct file_system_type *fs_type,
/* Zero out the NFS state stuff */
init_nfsv4_state(server);
- root = &server->fh;
- memcpy(root, &data->root, sizeof(*root));
- if (root->size < sizeof(root->data))
- memset(root->data+root->size, 0, sizeof(root->data)-root->size);
-
if (data->version != NFS_MOUNT_VERSION) {
printk("nfs warning: mount version %s than kernel\n",
data->version < NFS_MOUNT_VERSION ? "older" : "newer");
data->bsize = 0;
if (data->version < 4) {
data->flags &= ~NFS_MOUNT_VER3;
- memset(root, 0, sizeof(*root));
- root->size = NFS2_FHSIZE;
- memcpy(root->data, data->old_root.data, NFS2_FHSIZE);
+ 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) {
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);
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 */
+
+ rpciod_down(); /* release rpciod */
+
+ destroy_nfsv4_state(server);
+
+ if (server->hostname != NULL)
+ kfree(server->hostname);
kfree(server);
}
static void nfs4_clear_inode(struct inode *);
+
static struct super_operations nfs4_sops = {
.alloc_inode = nfs_alloc_inode,
.destroy_inode = nfs_destroy_inode,
.write_inode = nfs_write_inode,
.delete_inode = nfs_delete_inode,
- .put_super = nfs_put_super,
.statfs = nfs_statfs,
.clear_inode = nfs4_clear_inode,
.umount_begin = nfs_umount_begin,
{
struct nfs_inode *nfsi = NFS_I(inode);
+ /* If we are holding a delegation, return it! */
+ if (nfsi->delegation != NULL)
+ nfs_inode_return_delegation(inode);
+ /* First call standard NFS clear_inode() code */
+ nfs_clear_inode(inode);
+ /* Now clear out any remaining state */
while (!list_empty(&nfsi->open_states)) {
struct nfs4_state *state;
BUG_ON(atomic_read(&state->count) != 1);
nfs4_close_state(state, state->state);
}
- /* Now call standard NFS clear_inode() code */
- nfs_clear_inode(inode);
}
clp = nfs4_get_client(&server->addr.sin_addr);
if (!clp) {
printk(KERN_WARNING "NFS: failed to create NFS4 client.\n");
- goto out_fail;
+ return -EIO;
}
/* Now create transport and client */
memcpy(clp->cl_ipaddr, server->ip_addr, sizeof(clp->cl_ipaddr));
nfs_idmap_new(clp);
}
- if (list_empty(&clp->cl_superblocks))
- clear_bit(NFS4CLNT_OK, &clp->cl_state);
+ if (list_empty(&clp->cl_superblocks)) {
+ err = nfs4_init_client(clp);
+ if (err != 0) {
+ up_write(&clp->cl_sem);
+ goto out_fail;
+ }
+ }
list_add_tail(&server->nfs4_siblings, &clp->cl_superblocks);
clnt = rpc_clone_client(clp->cl_rpcclient);
if (!IS_ERR(clnt))
if (IS_ERR(clnt)) {
printk(KERN_WARNING "NFS: cannot create RPC client.\n");
- err = PTR_ERR(clnt);
- goto out_remove_list;
- }
- err = -ENOMEM;
- if (server->nfs4_state->cl_idmap == NULL) {
- printk(KERN_WARNING "NFS: failed to create idmapper.\n");
- goto out_shutdown;
+ return PTR_ERR(clnt);
}
clnt->cl_intr = (server->flags & NFS4_MOUNT_INTR) ? 1 : 0;
clnt->cl_softrtry = (server->flags & NFS4_MOUNT_SOFT) ? 1 : 0;
server->client = clnt;
+ if (server->nfs4_state->cl_idmap == NULL) {
+ printk(KERN_WARNING "NFS: failed to create idmapper.\n");
+ return -ENOMEM;
+ }
+
if (clnt->cl_auth->au_flavor != authflavour) {
if (rpcauth_create(authflavour, clnt) == NULL) {
printk(KERN_WARNING "NFS: couldn't create credcache!\n");
- goto out_shutdown;
+ return -ENOMEM;
}
}
- /* Fire up rpciod if not yet running */
- if (rpciod_up() != 0) {
- printk(KERN_WARNING "NFS: couldn't start rpciod!\n");
- goto out_shutdown;
- }
-
sb->s_op = &nfs4_sops;
err = nfs_sb_init(sb, authflavour);
if (err == 0)
return 0;
- rpciod_down();
-out_shutdown:
- rpc_shutdown_client(server->client);
-out_remove_list:
- down_write(&server->nfs4_state->cl_sem);
- list_del_init(&server->nfs4_siblings);
- up_write(&server->nfs4_state->cl_sem);
- destroy_nfsv4_state(server);
out_fail:
if (clp)
nfs4_put_client(clp);
s->s_flags = flags;
+ /* Fire up rpciod if not yet running */
+ if (rpciod_up() != 0) {
+ printk(KERN_WARNING "NFS: couldn't start rpciod!\n");
+ s = ERR_PTR(-EIO);
+ goto out_free;
+ }
+
error = nfs4_fill_super(s, data, flags & MS_VERBOSE ? 1 : 0);
if (error) {
up_write(&s->s_umount);
return s;
}
+static void nfs4_kill_super(struct super_block *sb)
+{
+ nfs_return_all_delegations(sb);
+ nfs_kill_super(sb);
+}
+
static struct file_system_type nfs4_fs_type = {
.owner = THIS_MODULE,
.name = "nfs4",
.get_sb = nfs4_get_sb,
- .kill_sb = nfs_kill_super,
+ .kill_sb = nfs4_kill_super,
.fs_flags = FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
};
-#define nfs4_zero_state(nfsi) \
+#define nfs4_init_once(nfsi) \
do { \
INIT_LIST_HEAD(&(nfsi)->open_states); \
+ nfsi->delegation = NULL; \
+ nfsi->delegation_state = 0; \
+ init_rwsem(&nfsi->rwsem); \
} while(0)
#define register_nfs4fs() register_filesystem(&nfs4_fs_type)
#define unregister_nfs4fs() unregister_filesystem(&nfs4_fs_type)
#else
-#define nfs4_zero_state(nfsi) \
+#define nfs4_init_once(nfsi) \
do { } while (0)
#define register_nfs4fs() (0)
#define unregister_nfs4fs()
if (!nfsi)
return NULL;
nfsi->flags = 0;
- nfsi->mm_cred = NULL;
- nfs4_zero_state(nfsi);
return &nfsi->vfs_inode;
}
if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
SLAB_CTOR_CONSTRUCTOR) {
inode_init_once(&nfsi->vfs_inode);
+ spin_lock_init(&nfsi->req_lock);
INIT_LIST_HEAD(&nfsi->dirty);
INIT_LIST_HEAD(&nfsi->commit);
+ INIT_LIST_HEAD(&nfsi->open_files);
INIT_RADIX_TREE(&nfsi->nfs_page_tree, GFP_ATOMIC);
atomic_set(&nfsi->data_updates, 0);
nfsi->ndirty = 0;
nfsi->ncommit = 0;
nfsi->npages = 0;
init_waitqueue_head(&nfsi->nfs_i_wait);
+ nfs4_init_once(nfsi);
}
}
{
nfs_inode_cachep = kmem_cache_create("nfs_inode_cache",
sizeof(struct nfs_inode),
- 0, SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT,
+ 0, SLAB_RECLAIM_ACCOUNT,
init_once, NULL);
if (nfs_inode_cachep == NULL)
return -ENOMEM;