This commit was manufactured by cvs2svn to create tag
[linux-2.6.git] / fs / nfs / inode.c
index 717a411..38318ce 100644 (file)
@@ -65,8 +65,6 @@ static void nfs_umount_begin(struct super_block *);
 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,
@@ -81,7 +79,7 @@ static struct super_operations nfs_sops = {
 /*
  * RPC cruft for NFS
  */
-static struct rpc_stat         nfs_rpcstat = {
+struct rpc_stat                        nfs_rpcstat = {
        .program                = &nfs_program
 };
 static struct rpc_version *    nfs_version[] = {
@@ -98,7 +96,7 @@ 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]),
@@ -250,7 +248,6 @@ nfs_sb_init(struct super_block *sb, rpc_authflavor_t authflavor)
                        .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));
@@ -287,12 +284,6 @@ nfs_sb_init(struct super_block *sb, rpc_authflavor_t authflavor)
        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;
@@ -330,10 +321,6 @@ nfs_sb_init(struct super_block *sb, rpc_authflavor_t authflavor)
        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;
@@ -381,9 +368,10 @@ nfs_create_client(struct nfs_server *server, const struct nfs_mount_data *data)
                goto out_fail;
        }
 
-       clnt->cl_intr     = 1;
-       clnt->cl_softrtry = 1;
-       clnt->cl_tagxid   = 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;
@@ -474,7 +462,6 @@ nfs_fill_super(struct super_block *sb, struct nfs_mount_data *data, int silent)
        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;
@@ -504,27 +491,13 @@ nfs_statfs(struct super_block *sb, struct kstatfs *buf)
        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;
 
@@ -555,6 +528,7 @@ static int nfs_show_options(struct seq_file *m, struct vfsmount *mnt)
                { 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 }
        };
@@ -597,9 +571,9 @@ nfs_zap_caches(struct inode *inode)
 
        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;
 }
 
 /*
@@ -637,7 +611,7 @@ nfs_find_actor(struct inode *inode, void *opaque)
                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;
 }
@@ -749,7 +723,12 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
 
 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;
@@ -802,8 +781,13 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr)
                        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;
@@ -813,7 +797,7 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr)
  * 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);
@@ -877,12 +861,6 @@ struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx)
 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)
@@ -931,7 +909,7 @@ void nfs_file_clear_open_context(struct file *filp)
        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);
        }
@@ -945,9 +923,8 @@ int nfs_open(struct inode *inode, struct file *filp)
        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)
@@ -987,14 +964,14 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
        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;
@@ -1006,14 +983,14 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
        /* 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;
        }
@@ -1052,6 +1029,7 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
                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);
@@ -1206,7 +1184,7 @@ int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
                        || inode->i_uid != uid
                        || inode->i_gid != gid
                        || inode->i_xid != xid)
-               nfsi->flags |= NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ACCESS;
+               nfsi->flags |= NFS_INO_INVALID_ATTR;
 
        /* Has the link count changed? */
        if (inode->i_nlink != fattr->nlink)
@@ -1318,7 +1296,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, unsign
 #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));
@@ -1331,8 +1309,14 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, unsign
        if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO) ||
            inode->i_uid != uid ||
            inode->i_gid != gid ||
-           inode->i_xid != xid)
-               invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS;
+           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;
@@ -1383,8 +1367,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, unsign
         */
        nfs_invalidate_inode(inode);
  out_err:
-       NFS_FLAGS(inode) |= NFS_INO_STALE;
-       return -ESTALE;
+       return -EIO;
 }
 
 /*
@@ -1498,6 +1481,8 @@ static void nfs_kill_super(struct super_block *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))
@@ -1508,6 +1493,8 @@ static void nfs_kill_super(struct super_block *s)
 
        rpciod_down();          /* release rpciod */
 
+       destroy_nfsv4_state(server);
+
        if (server->hostname != NULL)
                kfree(server->hostname);
        kfree(server);
@@ -1587,7 +1574,9 @@ static int nfs4_fill_super(struct super_block *sb, struct nfs4_mount_data *data,
        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;
@@ -1655,17 +1644,9 @@ static int nfs4_fill_super(struct super_block *sb, struct nfs4_mount_data *data,
                        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);
        }
@@ -1688,6 +1669,8 @@ static int nfs4_fill_super(struct super_block *sb, struct nfs4_mount_data *data,
                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) {
@@ -1702,8 +1685,6 @@ static int nfs4_fill_super(struct super_block *sb, struct nfs4_mount_data *data,
                }
        }
 
-       sb->s_time_gran = 1;
-
        sb->s_op = &nfs4_sops;
        err = nfs_sb_init(sb, authflavour);
        if (err == 0)
@@ -1841,22 +1822,8 @@ out_free:
 
 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 = {
@@ -1886,13 +1853,9 @@ 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;
 
@@ -1932,7 +1895,7 @@ static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
        }
 }
  
-static int nfs_init_inodecache(void)
+int nfs_init_inodecache(void)
 {
        nfs_inode_cachep = kmem_cache_create("nfs_inode_cache",
                                             sizeof(struct nfs_inode),
@@ -1944,7 +1907,7 @@ static int nfs_init_inodecache(void)
        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");
@@ -1973,12 +1936,6 @@ static int __init init_nfs_fs(void)
        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
@@ -1989,14 +1946,8 @@ static int __init init_nfs_fs(void)
                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:
@@ -2009,9 +1960,6 @@ out4:
 
 static void __exit exit_nfs_fs(void)
 {
-#ifdef CONFIG_NFS_DIRECTIO
-       nfs_destroy_directcache();
-#endif
        nfs_destroy_writepagecache();
        nfs_destroy_readpagecache();
        nfs_destroy_inodecache();