#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>
static int nfs_statfs(struct super_block *, struct kstatfs *);
static int nfs_show_options(struct seq_file *, struct vfsmount *);
-static struct rpc_program nfs_program;
-
static struct super_operations nfs_sops = {
.alloc_inode = nfs_alloc_inode,
.destroy_inode = nfs_destroy_inode,
/*
* RPC cruft for NFS
*/
-static struct rpc_stat nfs_rpcstat = {
+struct rpc_stat nfs_rpcstat = {
.program = &nfs_program
};
static struct rpc_version * nfs_version[] = {
#endif
};
-static struct rpc_program nfs_program = {
+struct rpc_program nfs_program = {
.name = "nfs",
.number = NFS_PROGRAM,
.nrvers = sizeof(nfs_version) / sizeof(nfs_version[0]),
.fattr = &fattr,
};
int no_root_error = 0;
- unsigned long max_rpc_payload;
/* 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));
if (fsinfo.wtmax >= 512 && server->wsize > fsinfo.wtmax)
server->wsize = nfs_block_size(fsinfo.wtmax, NULL);
- max_rpc_payload = nfs_block_size(rpc_max_payload(server->client), NULL);
- if (server->rsize > max_rpc_payload)
- server->rsize = max_rpc_payload;
- if (server->wsize > max_rpc_payload)
- server->wsize = max_rpc_payload;
-
server->rpages = (server->rsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
if (server->rpages > NFS_READ_MAXIOV) {
server->rpages = NFS_READ_MAXIOV;
}
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;
- server->client->cl_intr = (server->flags & NFS_MOUNT_INTR) ? 1 : 0;
- server->client->cl_softrtry = (server->flags & NFS_MOUNT_SOFT) ? 1 : 0;
-
/* We're airborne Set socket buffersize */
rpc_setbufsize(server->client, server->wsize + 100, server->rsize + 100);
return 0;
goto out_fail;
}
- clnt->cl_intr = 1;
- clnt->cl_softrtry = 1;
+ 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;
if (server->flags & NFS_MOUNT_VER3) {
if (server->namelen == 0 || server->namelen > NFS3_MAXNAMLEN)
server->namelen = NFS3_MAXNAMLEN;
- sb->s_time_gran = 1;
} else {
if (server->namelen == 0 || server->namelen > NFS2_MAXNAMLEN)
server->namelen = NFS2_MAXNAMLEN;
if (error < 0)
goto out_err;
- /*
- * Current versions of glibc do not correctly handle the
- * case where f_frsize != f_bsize. Eventually we want to
- * report the value of wtmult in this field.
- */
- buf->f_frsize = sb->s_blocksize;
-
- /*
- * On most *nix systems, f_blocks, f_bfree, and f_bavail
- * are reported in units of f_frsize. Linux hasn't had
- * an f_frsize field in its statfs struct until recently,
- * thus historically Linux's sys_statfs reports these
- * fields in units of f_bsize.
- */
+ buf->f_frsize = server->wtmult;
buf->f_bsize = sb->s_blocksize;
blockbits = sb->s_blocksize_bits;
blockres = (1 << blockbits) - 1;
buf->f_blocks = (res.tbytes + blockres) >> blockbits;
buf->f_bfree = (res.fbytes + blockres) >> blockbits;
buf->f_bavail = (res.abytes + blockres) >> blockbits;
-
buf->f_files = res.tfiles;
buf->f_ffree = res.afiles;
{ NFS_MOUNT_NOCTO, ",nocto", "" },
{ 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;
memset(NFS_COOKIEVERF(inode), 0, sizeof(NFS_COOKIEVERF(inode)));
if (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode))
- nfsi->flags |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS;
+ nfsi->flags |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;
else
- nfsi->flags |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS;
+ nfsi->flags |= NFS_INO_INVALID_ATTR;
}
/*
return 0;
if (nfs_compare_fh(NFS_FH(inode), fh))
return 0;
- if (is_bad_inode(inode) || NFS_STALE(inode))
+ if (is_bad_inode(inode))
return 0;
return 1;
}
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;
-
+/* FIXME
+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);
}
}
- if ((attr->ia_valid & (ATTR_MODE|ATTR_UID|ATTR_GID)) != 0)
- NFS_FLAGS(inode) |= NFS_INO_INVALID_ACCESS;
+ if ((attr->ia_valid & (ATTR_MODE|ATTR_UID|ATTR_GID)) != 0) {
+ struct rpc_cred **cred = &NFS_I(inode)->cache_access.cred;
+ if (*cred) {
+ put_rpccred(*cred);
+ *cred = NULL;
+ }
+ }
nfs_end_data_update(inode);
unlock_kernel();
return error;
* Wait for the inode to get unlocked.
* (Used for NFS_INO_LOCKED and NFS_INO_REVALIDATING).
*/
-static int
+int
nfs_wait_on_inode(struct inode *inode, int flag)
{
struct rpc_clnt *clnt = NFS_CLIENT(inode);
void put_nfs_open_context(struct nfs_open_context *ctx)
{
if (atomic_dec_and_test(&ctx->count)) {
- if (!list_empty(&ctx->list)) {
- struct inode *inode = ctx->dentry->d_inode;
- spin_lock(&inode->i_lock);
- list_del(&ctx->list);
- spin_unlock(&inode->i_lock);
- }
if (ctx->state != NULL)
nfs4_close_state(ctx->state, ctx->mode);
if (ctx->cred != NULL)
if (ctx) {
filp->private_data = NULL;
spin_lock(&inode->i_lock);
- list_move_tail(&ctx->list, &NFS_I(inode)->open_files);
+ list_del(&ctx->list);
spin_unlock(&inode->i_lock);
put_nfs_open_context(ctx);
}
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);
+ 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)
lock_kernel();
if (!inode || is_bad_inode(inode))
goto out_nowait;
- if (NFS_STALE(inode))
+ if (NFS_STALE(inode) && inode != inode->i_sb->s_root->d_inode)
goto out_nowait;
while (NFS_REVALIDATING(inode)) {
status = nfs_wait_on_inode(inode, NFS_INO_REVALIDATING);
if (status < 0)
goto out_nowait;
- if (NFS_ATTRTIMEO(inode) == 0)
+ if (NFS_SERVER(inode)->flags & NFS_MOUNT_NOAC)
continue;
if (NFS_FLAGS(inode) & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ATIME))
continue;
/* Protect against RPC races by saving the change attribute */
verifier = nfs_save_change_attribute(inode);
status = NFS_PROTO(inode)->getattr(server, NFS_FH(inode), &fattr);
- if (status != 0) {
+ if (status) {
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))
- NFS_FLAGS(inode) |= NFS_INO_STALE;
+ NFS_FLAGS(inode) |= NFS_INO_STALE;
+ if (inode != inode->i_sb->s_root->d_inode)
+ remove_inode_hash(inode);
}
goto out;
}
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);
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))
} 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)
- nfsi->flags |= NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ACCESS;
+ || inode->i_uid != uid
+ || inode->i_gid != gid
+ || inode->i_xid != xid)
+ nfsi->flags |= NFS_INO_INVALID_ATTR;
/* Has the link count changed? */
if (inode->i_nlink != fattr->nlink)
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,
#endif
nfsi->change_attr = fattr->change_attr;
if (!data_unstable)
- invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS;
+ 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));
+ 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)
- invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS;
+ 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);
+ *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;
+ inode->i_uid = uid;
+ inode->i_gid = gid;
+ inode->i_xid = xid;
if (fattr->valid & (NFS_ATTR_FATTR_V3 | NFS_ATTR_FATTR_V4)) {
/*
*/
nfs_invalidate_inode(inode);
out_err:
- NFS_FLAGS(inode) |= NFS_INO_STALE;
- return -ESTALE;
+ return -EIO;
}
/*
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))
rpciod_down(); /* release rpciod */
+ destroy_nfsv4_state(server);
+
if (server->hostname != NULL)
kfree(server->hostname);
kfree(server);
if (data->wsize != 0)
server->wsize = nfs_block_size(data->wsize, NULL);
server->flags = data->flags & NFS_MOUNT_FLAGMASK;
- server->caps = NFS_CAP_ATOMIC_OPEN;
+
+ /* NFSv4 doesn't use NLM locking */
+ server->flags |= NFS_MOUNT_NONLM;
server->acregmin = data->acregmin*HZ;
server->acregmax = data->acregmax*HZ;
err = PTR_ERR(clnt);
goto out_fail;
}
- clnt->cl_intr = 1;
- clnt->cl_softrtry = 1;
clnt->cl_chatty = 1;
clp->cl_rpcclient = clnt;
clp->cl_cred = rpcauth_lookupcred(clnt->cl_auth, 0);
- if (IS_ERR(clp->cl_cred)) {
- up_write(&clp->cl_sem);
- err = PTR_ERR(clp->cl_cred);
- clp->cl_cred = NULL;
- goto out_fail;
- }
memcpy(clp->cl_ipaddr, server->ip_addr, sizeof(clp->cl_ipaddr));
nfs_idmap_new(clp);
}
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) {
}
}
- sb->s_time_gran = 1;
-
sb->s_op = &nfs4_sops;
err = nfs_sb_init(sb, authflavour);
if (err == 0)
static void nfs4_kill_super(struct super_block *sb)
{
- struct nfs_server *server = NFS_SB(sb);
-
nfs_return_all_delegations(sb);
- kill_anon_super(sb);
-
- nfs4_renewd_prepare_shutdown(server);
-
- if (server->client != NULL && !IS_ERR(server->client))
- rpc_shutdown_client(server->client);
- rpciod_down(); /* release rpciod */
-
- destroy_nfsv4_state(server);
-
- if (server->hostname != NULL)
- kfree(server->hostname);
- kfree(server);
+ nfs_kill_super(sb);
}
static struct file_system_type nfs4_fs_type = {
extern int nfs_init_nfspagecache(void);
extern void nfs_destroy_nfspagecache(void);
extern int nfs_init_readpagecache(void);
-extern void nfs_destroy_readpagecache(void);
+extern int nfs_destroy_readpagecache(void);
extern int nfs_init_writepagecache(void);
-extern void nfs_destroy_writepagecache(void);
-#ifdef CONFIG_NFS_DIRECTIO
-extern int nfs_init_directcache(void);
-extern void nfs_destroy_directcache(void);
-#endif
+extern int nfs_destroy_writepagecache(void);
static kmem_cache_t * nfs_inode_cachep;
}
}
-static int nfs_init_inodecache(void)
+int nfs_init_inodecache(void)
{
nfs_inode_cachep = kmem_cache_create("nfs_inode_cache",
sizeof(struct nfs_inode),
return 0;
}
-static void nfs_destroy_inodecache(void)
+void nfs_destroy_inodecache(void)
{
if (kmem_cache_destroy(nfs_inode_cachep))
printk(KERN_INFO "nfs_inode_cache: not all structures were freed\n");
if (err)
goto out1;
-#ifdef CONFIG_NFS_DIRECTIO
- err = nfs_init_directcache();
- if (err)
- goto out0;
-#endif
-
#ifdef CONFIG_PROC_FS
rpc_proc_register(&nfs_rpcstat);
#endif
goto out;
return 0;
out:
-#ifdef CONFIG_PROC_FS
rpc_proc_unregister("nfs");
-#endif
nfs_destroy_writepagecache();
-#ifdef CONFIG_NFS_DIRECTIO
-out0:
- nfs_destroy_directcache();
-#endif
out1:
nfs_destroy_readpagecache();
out2:
static void __exit exit_nfs_fs(void)
{
-#ifdef CONFIG_NFS_DIRECTIO
- nfs_destroy_directcache();
-#endif
nfs_destroy_writepagecache();
nfs_destroy_readpagecache();
nfs_destroy_inodecache();