]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - fs/nfs/inode.c
NFSv4: Allow user to set the port used by the NFSv4 callback channel
[mirror_ubuntu-artful-kernel.git] / fs / nfs / inode.c
index 6391d89642144366591df7e7c0e6733b12916899..648cb1aef3b1098b4f3b51ed983d331d5b428e0d 100644 (file)
@@ -40,6 +40,7 @@
 #include <asm/uaccess.h>
 
 #include "nfs4_fs.h"
+#include "callback.h"
 #include "delegation.h"
 
 #define NFSDBG_FACILITY                NFSDBG_VFS
@@ -54,7 +55,7 @@
 #define NFS_MAX_READAHEAD      (RPC_DEF_SLOT_TABLE - 1)
 
 static void nfs_invalidate_inode(struct inode *);
-static int nfs_update_inode(struct inode *, struct nfs_fattr *, unsigned long);
+static int nfs_update_inode(struct inode *, struct nfs_fattr *);
 
 static struct inode *nfs_alloc_inode(struct super_block *sb);
 static void nfs_destroy_inode(struct inode *);
@@ -221,10 +222,10 @@ nfs_calc_block_size(u64 tsize)
 static inline unsigned long
 nfs_block_size(unsigned long bsize, unsigned char *nrbitsp)
 {
-       if (bsize < 1024)
-               bsize = NFS_DEF_FILE_IO_BUFFER_SIZE;
-       else if (bsize >= NFS_MAX_FILE_IO_BUFFER_SIZE)
-               bsize = NFS_MAX_FILE_IO_BUFFER_SIZE;
+       if (bsize < NFS_MIN_FILE_IO_SIZE)
+               bsize = NFS_DEF_FILE_IO_SIZE;
+       else if (bsize >= NFS_MAX_FILE_IO_SIZE)
+               bsize = NFS_MAX_FILE_IO_SIZE;
 
        return nfs_block_bits(bsize, nrbitsp);
 }
@@ -307,20 +308,15 @@ nfs_sb_init(struct super_block *sb, rpc_authflavor_t authflavor)
        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;
-
+       if (server->rsize > NFS_MAX_FILE_IO_SIZE)
+               server->rsize = NFS_MAX_FILE_IO_SIZE;
        server->rpages = (server->rsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
-       if (server->rpages > NFS_READ_MAXIOV) {
-               server->rpages = NFS_READ_MAXIOV;
-               server->rsize = server->rpages << PAGE_CACHE_SHIFT;
-       }
 
+       if (server->wsize > max_rpc_payload)
+               server->wsize = max_rpc_payload;
+       if (server->wsize > NFS_MAX_FILE_IO_SIZE)
+               server->wsize = NFS_MAX_FILE_IO_SIZE;
        server->wpages = (server->wsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
-        if (server->wpages > NFS_WRITE_MAXIOV) {
-               server->wpages = NFS_WRITE_MAXIOV;
-                server->wsize = server->wpages << PAGE_CACHE_SHIFT;
-       }
 
        if (sb->s_blocksize == 0)
                sb->s_blocksize = nfs_block_bits(server->wsize,
@@ -575,11 +571,10 @@ nfs_statfs(struct super_block *sb, struct kstatfs *buf)
        buf->f_namelen = server->namelen;
  out:
        unlock_kernel();
-
        return 0;
 
  out_err:
-       printk(KERN_WARNING "nfs_statfs: statfs error = %d\n", -error);
+       dprintk("%s: statfs error = %d\n", __FUNCTION__, -error);
        buf->f_bsize = buf->f_blocks = buf->f_bfree = buf->f_bavail = -1;
        goto out;
 
@@ -640,17 +635,35 @@ static int nfs_show_options(struct seq_file *m, struct vfsmount *mnt)
        return 0;
 }
 
+/**
+ * nfs_sync_mapping - helper to flush all mmapped dirty data to disk
+ */
+int nfs_sync_mapping(struct address_space *mapping)
+{
+       int ret;
+
+       if (mapping->nrpages == 0)
+               return 0;
+       unmap_mapping_range(mapping, 0, 0, 0);
+       ret = filemap_fdatawrite(mapping);
+       if (ret != 0)
+               goto out;
+       ret = filemap_fdatawait(mapping);
+       if (ret != 0)
+               goto out;
+       ret = nfs_wb_all(mapping->host);
+out:
+       return ret;
+}
+
 /*
  * Invalidate the local caches
  */
-void
-nfs_zap_caches(struct inode *inode)
+static void nfs_zap_caches_locked(struct inode *inode)
 {
        struct nfs_inode *nfsi = NFS_I(inode);
        int mode = inode->i_mode;
 
-       spin_lock(&inode->i_lock);
-
        NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode);
        NFS_ATTRTIMEO_UPDATE(inode) = jiffies;
 
@@ -659,7 +672,12 @@ nfs_zap_caches(struct inode *inode)
                nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL|NFS_INO_REVAL_PAGECACHE;
        else
                nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL|NFS_INO_REVAL_PAGECACHE;
+}
 
+void nfs_zap_caches(struct inode *inode)
+{
+       spin_lock(&inode->i_lock);
+       nfs_zap_caches_locked(inode);
        spin_unlock(&inode->i_lock);
 }
 
@@ -676,16 +694,13 @@ static void nfs_zap_acl_cache(struct inode *inode)
 }
 
 /*
- * Invalidate, but do not unhash, the inode
+ * Invalidate, but do not unhash, the inode.
+ * NB: must be called with inode->i_lock held!
  */
-static void
-nfs_invalidate_inode(struct inode *inode)
+static void nfs_invalidate_inode(struct inode *inode)
 {
-       umode_t save_mode = inode->i_mode;
-
-       make_bad_inode(inode);
-       inode->i_mode = save_mode;
-       nfs_zap_caches(inode);
+       set_bit(NFS_INO_STALE, &NFS_FLAGS(inode));
+       nfs_zap_caches_locked(inode);
 }
 
 struct nfs_find_desc {
@@ -938,6 +953,8 @@ int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
        int need_atime = NFS_I(inode)->cache_validity & NFS_INO_INVALID_ATIME;
        int err;
 
+       /* Flush out writes to the server in order to update c/mtime */
+       nfs_sync_inode(inode, 0, 0, FLUSH_WAIT|FLUSH_NOCOMMIT);
        if (__IS_FLG(inode, MS_NOATIME))
                need_atime = 0;
        else if (__IS_FLG(inode, MS_NODIRATIME) && S_ISDIR(inode->i_mode))
@@ -1081,8 +1098,6 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
        int              status = -ESTALE;
        struct nfs_fattr fattr;
        struct nfs_inode *nfsi = NFS_I(inode);
-       unsigned long verifier;
-       unsigned long cache_validity;
 
        dfprintk(PAGECACHE, "NFS: revalidating (%s/%Ld)\n",
                inode->i_sb->s_id, (long long)NFS_FILEID(inode));
@@ -1107,8 +1122,6 @@ __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) {
                dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Ld) getattr failed, error=%d\n",
@@ -1123,7 +1136,7 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
        }
 
        spin_lock(&inode->i_lock);
-       status = nfs_update_inode(inode, &fattr, verifier);
+       status = nfs_update_inode(inode, &fattr);
        if (status) {
                spin_unlock(&inode->i_lock);
                dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Ld) refresh failed, error=%d\n",
@@ -1131,20 +1144,11 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
                         (long long)NFS_FILEID(inode), status);
                goto out;
        }
-       cache_validity = nfsi->cache_validity;
-       nfsi->cache_validity &= ~NFS_INO_REVAL_PAGECACHE;
-
-       /*
-        * We may need to keep the attributes marked as invalid if
-        * we raced with nfs_end_attr_update().
-        */
-       if (time_after_eq(verifier, nfsi->cache_change_attribute))
-               nfsi->cache_validity &= ~(NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ATIME);
        spin_unlock(&inode->i_lock);
 
        nfs_revalidate_mapping(inode, inode->i_mapping);
 
-       if (cache_validity & NFS_INO_INVALID_ACL)
+       if (nfsi->cache_validity & NFS_INO_INVALID_ACL)
                nfs_zap_acl_cache(inode);
 
        dfprintk(PAGECACHE, "NFS: (%s/%Ld) revalidation complete\n",
@@ -1193,11 +1197,8 @@ void nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping)
        struct nfs_inode *nfsi = NFS_I(inode);
 
        if (nfsi->cache_validity & NFS_INO_INVALID_DATA) {
-               if (S_ISREG(inode->i_mode)) {
-                       if (filemap_fdatawrite(mapping) == 0)
-                               filemap_fdatawait(mapping);
-                       nfs_wb_all(inode);
-               }
+               if (S_ISREG(inode->i_mode))
+                       nfs_sync_mapping(mapping);
                invalidate_inode_pages2(mapping);
 
                spin_lock(&inode->i_lock);
@@ -1248,6 +1249,33 @@ void nfs_end_data_update(struct inode *inode)
        atomic_dec(&nfsi->data_updates);
 }
 
+static void nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr *fattr)
+{
+       struct nfs_inode *nfsi = NFS_I(inode);
+
+       if ((fattr->valid & NFS_ATTR_PRE_CHANGE) != 0
+                       && nfsi->change_attr == fattr->pre_change_attr) {
+               nfsi->change_attr = fattr->change_attr;
+               nfsi->cache_change_attribute = jiffies;
+       }
+
+       /* If we have atomic WCC data, we may update some attributes */
+       if ((fattr->valid & NFS_ATTR_WCC) != 0) {
+               if (timespec_equal(&inode->i_ctime, &fattr->pre_ctime)) {
+                       memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime));
+                       nfsi->cache_change_attribute = jiffies;
+               }
+               if (timespec_equal(&inode->i_mtime, &fattr->pre_mtime)) {
+                       memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime));
+                       nfsi->cache_change_attribute = jiffies;
+               }
+               if (inode->i_size == fattr->pre_size && nfsi->npages == 0) {
+                       inode->i_size = fattr->size;
+                       nfsi->cache_change_attribute = jiffies;
+               }
+       }
+}
+
 /**
  * nfs_check_inode_attributes - verify consistency of the inode attribute cache
  * @inode - pointer to inode
@@ -1264,22 +1292,20 @@ static int nfs_check_inode_attributes(struct inode *inode, struct nfs_fattr *fat
        int data_unstable;
 
 
+       if ((fattr->valid & NFS_ATTR_FATTR) == 0)
+               return 0;
+
        /* Are we in the process of updating data on the server? */
        data_unstable = nfs_caches_unstable(inode);
 
-       if (fattr->valid & NFS_ATTR_FATTR_V4) {
-               if ((fattr->valid & NFS_ATTR_PRE_CHANGE) != 0
-                               && nfsi->change_attr == fattr->pre_change_attr)
-                       nfsi->change_attr = fattr->change_attr;
-               if (nfsi->change_attr != fattr->change_attr) {
-                       nfsi->cache_validity |= NFS_INO_INVALID_ATTR;
-                       if (!data_unstable)
-                               nfsi->cache_validity |= NFS_INO_REVAL_PAGECACHE;
-               }
-       }
+       /* Do atomic weak cache consistency updates */
+       nfs_wcc_update_inode(inode, fattr);
 
-       if ((fattr->valid & NFS_ATTR_FATTR) == 0) {
-               return 0;
+       if ((fattr->valid & NFS_ATTR_FATTR_V4) != 0 &&
+                       nfsi->change_attr != fattr->change_attr) {
+               nfsi->cache_validity |= NFS_INO_INVALID_ATTR;
+               if (!data_unstable)
+                       nfsi->cache_validity |= NFS_INO_REVAL_PAGECACHE;
        }
 
        /* Has the inode gone and changed behind our back? */
@@ -1291,14 +1317,6 @@ static int nfs_check_inode_attributes(struct inode *inode, struct nfs_fattr *fat
        cur_size = i_size_read(inode);
        new_isize = nfs_size_to_loff_t(fattr->size);
 
-       /* If we have atomic WCC data, we may update some attributes */
-       if ((fattr->valid & NFS_ATTR_WCC) != 0) {
-               if (timespec_equal(&inode->i_ctime, &fattr->pre_ctime))
-                       memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime));
-               if (timespec_equal(&inode->i_mtime, &fattr->pre_mtime))
-                       memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime));
-       }
-
        /* Verify a few of the more important attributes */
        if (!timespec_equal(&inode->i_mtime, &fattr->mtime)) {
                nfsi->cache_validity |= NFS_INO_INVALID_ATTR;
@@ -1347,10 +1365,8 @@ int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
                return 0;
        spin_lock(&inode->i_lock);
        nfsi->cache_validity &= ~NFS_INO_REVAL_PAGECACHE;
-       if (nfs_verify_change_attribute(inode, fattr->time_start))
-               nfsi->cache_validity &= ~(NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ATIME);
        if (time_after(fattr->time_start, nfsi->last_updated))
-               status = nfs_update_inode(inode, fattr, fattr->time_start);
+               status = nfs_update_inode(inode, fattr);
        else
                status = nfs_check_inode_attributes(inode, fattr);
 
@@ -1376,10 +1392,7 @@ int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr)
                nfsi->cache_validity |= NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ACCESS;
                goto out;
        }
-       status = nfs_update_inode(inode, fattr, fattr->time_start);
-       if (time_after_eq(fattr->time_start, nfsi->cache_change_attribute))
-               nfsi->cache_validity &= ~(NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ATIME|NFS_INO_REVAL_PAGECACHE);
-       nfsi->cache_change_attribute = jiffies;
+       status = nfs_update_inode(inode, fattr);
 out:
        spin_unlock(&inode->i_lock);
        return status;
@@ -1397,12 +1410,12 @@ out:
  *
  * A very similar scenario holds for the dir cache.
  */
-static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, unsigned long verifier)
+static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
 {
        struct nfs_inode *nfsi = NFS_I(inode);
        loff_t cur_isize, new_isize;
        unsigned int    invalid = 0;
-       int data_unstable;
+       int data_stable;
 
        dfprintk(VFS, "NFS: %s(%s/%ld ct=%d info=0x%x)\n",
                        __FUNCTION__, inode->i_sb->s_id, inode->i_ino,
@@ -1411,14 +1424,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, unsign
        if ((fattr->valid & NFS_ATTR_FATTR) == 0)
                return 0;
 
-       if (nfsi->fileid != fattr->fileid) {
-               printk(KERN_ERR "%s: inode number mismatch\n"
-                      "expected (%s/0x%Lx), got (%s/0x%Lx)\n",
-                      __FUNCTION__,
-                      inode->i_sb->s_id, (long long)nfsi->fileid,
-                      inode->i_sb->s_id, (long long)fattr->fileid);
-               goto out_err;
-       }
+       if (nfsi->fileid != fattr->fileid)
+               goto out_fileid;
 
        /*
         * Make sure the inode's type hasn't changed.
@@ -1433,8 +1440,12 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, unsign
        nfsi->last_updated = jiffies;
 
        /* Are we racing with known updates of the metadata on the server? */
-       data_unstable = ! (nfs_verify_change_attribute(inode, verifier) ||
-               (nfsi->cache_validity & NFS_INO_REVAL_PAGECACHE));
+       data_stable = nfs_verify_change_attribute(inode, fattr->time_start);
+       if (data_stable)
+               nfsi->cache_validity &= ~(NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ATIME);
+
+       /* Do atomic weak cache consistency updates */
+       nfs_wcc_update_inode(inode, fattr);
 
        /* Check if our cached file size is stale */
        new_isize = nfs_size_to_loff_t(fattr->size);
@@ -1443,7 +1454,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, unsign
                /* Do we perhaps have any outstanding writes? */
                if (nfsi->npages == 0) {
                        /* No, but did we race with nfs_end_data_update()? */
-                       if (time_after_eq(verifier,  nfsi->cache_change_attribute)) {
+                       if (data_stable) {
                                inode->i_size = new_isize;
                                invalid |= NFS_INO_INVALID_DATA;
                        }
@@ -1452,6 +1463,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, unsign
                        inode->i_size = new_isize;
                        invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;
                }
+               nfsi->cache_change_attribute = jiffies;
                dprintk("NFS: isize change on server for file %s/%ld\n",
                                inode->i_sb->s_id, inode->i_ino);
        }
@@ -1461,8 +1473,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, unsign
                memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime));
                dprintk("NFS: mtime change on server for file %s/%ld\n",
                                inode->i_sb->s_id, inode->i_ino);
-               if (!data_unstable)
-                       invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;
+               invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;
+               nfsi->cache_change_attribute = jiffies;
        }
 
        if ((fattr->valid & NFS_ATTR_FATTR_V4)
@@ -1470,15 +1482,15 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, unsign
                dprintk("NFS: change_attr change on server for file %s/%ld\n",
                       inode->i_sb->s_id, inode->i_ino);
                nfsi->change_attr = fattr->change_attr;
-               if (!data_unstable)
-                       invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
+               invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
+               nfsi->cache_change_attribute = jiffies;
        }
 
        /* If ctime has changed we should definitely clear access+acl caches */
        if (!timespec_equal(&inode->i_ctime, &fattr->ctime)) {
-               if (!data_unstable)
-                       invalid |= NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
+               invalid |= NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
                memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime));
+               nfsi->cache_change_attribute = jiffies;
        }
        memcpy(&inode->i_atime, &fattr->atime, sizeof(inode->i_atime));
 
@@ -1516,6 +1528,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, unsign
        if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode)
                                || S_ISLNK(inode->i_mode)))
                invalid &= ~NFS_INO_INVALID_DATA;
+       if (data_stable)
+               invalid &= ~(NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ATIME|NFS_INO_REVAL_PAGECACHE);
        if (!nfs_have_delegation(inode, FMODE_READ))
                nfsi->cache_validity |= invalid;
 
@@ -1528,15 +1542,21 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, unsign
        printk(KERN_DEBUG "%s: inode %ld mode changed, %07o to %07o\n",
                        __FUNCTION__, inode->i_ino, inode->i_mode, fattr->mode);
 #endif
+ out_err:
        /*
         * No need to worry about unhashing the dentry, as the
         * lookup validation will know that the inode is bad.
         * (But we fall through to invalidate the caches.)
         */
        nfs_invalidate_inode(inode);
- out_err:
-       set_bit(NFS_INO_STALE, &NFS_FLAGS(inode));
        return -ESTALE;
+
+ out_fileid:
+       printk(KERN_ERR "NFS: server %s error: fileid changed\n"
+               "fsid %s: expected fileid 0x%Lx, got 0x%Lx\n",
+               NFS_SERVER(inode)->hostname, inode->i_sb->s_id,
+               (long long)nfsi->fileid, (long long)fattr->fileid);
+       goto out_err;
 }
 
 /*
@@ -1820,23 +1840,9 @@ static int nfs4_fill_super(struct super_block *sb, struct nfs4_mount_data *data,
                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);
        }
-       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))
@@ -2031,6 +2037,21 @@ static struct file_system_type nfs4_fs_type = {
        .fs_flags       = FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
 };
 
+static const int nfs_set_port_min = 0;
+static const int nfs_set_port_max = 65535;
+static int param_set_port(const char *val, struct kernel_param *kp)
+{
+       char *endp;
+       int num = simple_strtol(val, &endp, 0);
+       if (endp == val || *endp || num < nfs_set_port_min || num > nfs_set_port_max)
+               return -EINVAL;
+       *((int *)kp->arg) = num;
+       return 0;
+}
+
+module_param_call(callback_tcpport, param_set_port, param_get_int,
+                &nfs_callback_set_tcpport, 0644);
+
 #define nfs4_init_once(nfsi) \
        do { \
                INIT_LIST_HEAD(&(nfsi)->open_states); \
@@ -2038,8 +2059,25 @@ static struct file_system_type nfs4_fs_type = {
                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)
+
+static inline int register_nfs4fs(void)
+{
+       int ret;
+
+       ret = nfs_register_sysctl();
+       if (ret != 0)
+               return ret;
+       ret = register_filesystem(&nfs4_fs_type);
+       if (ret != 0)
+               nfs_unregister_sysctl();
+       return ret;
+}
+
+static inline void unregister_nfs4fs(void)
+{
+       unregister_filesystem(&nfs4_fs_type);
+       nfs_unregister_sysctl();
+}
 #else
 #define nfs4_init_once(nfsi) \
        do { } while (0)
@@ -2068,6 +2106,7 @@ static struct inode *nfs_alloc_inode(struct super_block *sb)
                return NULL;
        nfsi->flags = 0UL;
        nfsi->cache_validity = 0UL;
+       nfsi->cache_change_attribute = jiffies;
 #ifdef CONFIG_NFS_V3_ACL
        nfsi->acl_access = ERR_PTR(-EAGAIN);
        nfsi->acl_default = ERR_PTR(-EAGAIN);
@@ -2163,11 +2202,11 @@ out:
 #ifdef CONFIG_PROC_FS
        rpc_proc_unregister("nfs");
 #endif
-       nfs_destroy_writepagecache();
 #ifdef CONFIG_NFS_DIRECTIO
-out0:
        nfs_destroy_directcache();
+out0:
 #endif
+       nfs_destroy_writepagecache();
 out1:
        nfs_destroy_readpagecache();
 out2: