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
*/
-struct rpc_stat nfs_rpcstat = {
+static struct rpc_stat nfs_rpcstat = {
.program = &nfs_program
};
static struct rpc_version * nfs_version[] = {
#endif
};
-struct rpc_program nfs_program = {
+static 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;
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;
+ server->client->cl_tagxid = (server->flags & NFS_MOUNT_TAGXID) ? 1 : 0;
+
/* We're airborne Set socket buffersize */
rpc_setbufsize(server->client, server->wsize + 100, server->rsize + 100);
return 0;
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;
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;
- buf->f_frsize = server->wtmult;
+ /*
+ * 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_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;
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;
+ nfsi->flags |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS;
else
- nfsi->flags |= NFS_INO_INVALID_ATTR;
+ nfsi->flags |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS;
}
/*
return 0;
if (nfs_compare_fh(NFS_FH(inode), fh))
return 0;
- if (is_bad_inode(inode))
+ if (is_bad_inode(inode) || NFS_STALE(inode))
return 0;
return 1;
}
vmtruncate(inode, attr->ia_size);
}
}
- 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;
- }
- }
+ if ((attr->ia_valid & (ATTR_MODE|ATTR_UID|ATTR_GID)) != 0)
+ NFS_FLAGS(inode) |= NFS_INO_INVALID_ACCESS;
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).
*/
-int
+static 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_del(&ctx->list);
+ list_move_tail(&ctx->list, &NFS_I(inode)->open_files);
spin_unlock(&inode->i_lock);
put_nfs_open_context(ctx);
}
struct nfs_open_context *ctx;
struct rpc_cred *cred;
- if ((cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0)) == NULL)
- return -ENOMEM;
+ cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0);
+ if (IS_ERR(cred))
+ return PTR_ERR(cred);
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) && inode != inode->i_sb->s_root->d_inode)
+ if (NFS_STALE(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_SERVER(inode)->flags & NFS_MOUNT_NOAC)
+ if (NFS_ATTRTIMEO(inode) == 0)
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) {
+ 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_FLAGS(inode) |= NFS_INO_STALE;
- if (inode != inode->i_sb->s_root->d_inode)
- remove_inode_hash(inode);
+ nfs_zap_caches(inode);
+ if (!S_ISDIR(inode->i_mode))
+ NFS_FLAGS(inode) |= NFS_INO_STALE;
}
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);
|| inode->i_uid != uid
|| inode->i_gid != gid
|| inode->i_xid != xid)
- nfsi->flags |= NFS_INO_INVALID_ATTR;
+ nfsi->flags |= NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ACCESS;
/* Has the link count changed? */
if (inode->i_nlink != fattr->nlink)
#endif
nfsi->change_attr = fattr->change_attr;
if (!data_unstable)
- invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;
+ invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS;
}
memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime));
if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO) ||
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_xid != xid)
+ invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS;
inode->i_mode = fattr->mode;
inode->i_nlink = fattr->nlink;
*/
nfs_invalidate_inode(inode);
out_err:
- return -EIO;
+ NFS_FLAGS(inode) |= NFS_INO_STALE;
+ return -ESTALE;
}
/*
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;
-
- /* NFSv4 doesn't use NLM locking */
- server->flags |= NFS_MOUNT_NONLM;
+ server->caps = NFS_CAP_ATOMIC_OPEN;
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);
- nfs_kill_super(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);
}
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 int nfs_destroy_readpagecache(void);
+extern void nfs_destroy_readpagecache(void);
extern int nfs_init_writepagecache(void);
-extern int nfs_destroy_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
static kmem_cache_t * nfs_inode_cachep;
}
}
-int nfs_init_inodecache(void)
+static int nfs_init_inodecache(void)
{
nfs_inode_cachep = kmem_cache_create("nfs_inode_cache",
sizeof(struct nfs_inode),
return 0;
}
-void nfs_destroy_inodecache(void)
+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");
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();