]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - fs/nfs/inode.c
Merge branch 'devel' of master.kernel.org:/home/rmk/linux-2.6-serial
[linux-2.6-omap-h63xx.git] / fs / nfs / inode.c
index 827d69255b1ba5bd508e3ea9113aa3ac3e161865..d0b991a92327f32941a454865c6aed187523d52e 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/unistd.h>
 #include <linux/sunrpc/clnt.h>
 #include <linux/sunrpc/stats.h>
+#include <linux/sunrpc/metrics.h>
 #include <linux/nfs_fs.h>
 #include <linux/nfs_mount.h>
 #include <linux/nfs4_mount.h>
@@ -42,6 +43,7 @@
 #include "nfs4_fs.h"
 #include "callback.h"
 #include "delegation.h"
+#include "iostat.h"
 
 #define NFSDBG_FACILITY                NFSDBG_VFS
 #define NFS_PARANOIA 1
@@ -65,6 +67,7 @@ static void nfs_clear_inode(struct inode *);
 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 int  nfs_show_stats(struct seq_file *, struct vfsmount *);
 static void nfs_zap_acl_cache(struct inode *);
 
 static struct rpc_program      nfs_program;
@@ -78,6 +81,7 @@ static struct super_operations nfs_sops = {
        .clear_inode    = nfs_clear_inode,
        .umount_begin   = nfs_umount_begin,
        .show_options   = nfs_show_options,
+       .show_stats     = nfs_show_stats,
 };
 
 /*
@@ -103,7 +107,7 @@ static struct rpc_version * nfs_version[] = {
 static struct rpc_program      nfs_program = {
        .name                   = "nfs",
        .number                 = NFS_PROGRAM,
-       .nrvers                 = sizeof(nfs_version) / sizeof(nfs_version[0]),
+       .nrvers                 = ARRAY_SIZE(nfs_version),
        .version                = nfs_version,
        .stats                  = &nfs_rpcstat,
        .pipe_dir_name          = "/nfs",
@@ -118,7 +122,7 @@ static struct rpc_version * nfsacl_version[] = {
 struct rpc_program             nfsacl_program = {
        .name =                 "nfsacl",
        .number =               NFS_ACL_PROGRAM,
-       .nrvers =               sizeof(nfsacl_version) / sizeof(nfsacl_version[0]),
+       .nrvers =               ARRAY_SIZE(nfsacl_version),
        .version =              nfsacl_version,
        .stats =                &nfsacl_rpcstat,
 };
@@ -133,7 +137,7 @@ nfs_fattr_to_ino_t(struct nfs_fattr *fattr)
 static int
 nfs_write_inode(struct inode *inode, int sync)
 {
-       int flags = sync ? FLUSH_WAIT : 0;
+       int flags = sync ? FLUSH_SYNC : 0;
        int ret;
 
        ret = nfs_commit_inode(inode, flags);
@@ -237,7 +241,6 @@ static struct inode *
 nfs_get_root(struct super_block *sb, struct nfs_fh *rootfh, struct nfs_fsinfo *fsinfo)
 {
        struct nfs_server       *server = NFS_SB(sb);
-       struct inode *rooti;
        int                     error;
 
        error = server->rpc_ops->getroot(server, rootfh, fsinfo);
@@ -246,10 +249,7 @@ nfs_get_root(struct super_block *sb, struct nfs_fh *rootfh, struct nfs_fsinfo *f
                return ERR_PTR(error);
        }
 
-       rooti = nfs_fhget(sb, rootfh, fsinfo->fattr);
-       if (!rooti)
-               return ERR_PTR(-ENOMEM);
-       return rooti;
+       return nfs_fhget(sb, rootfh, fsinfo->fattr);
 }
 
 /*
@@ -277,6 +277,10 @@ nfs_sb_init(struct super_block *sb, rpc_authflavor_t authflavor)
 
        sb->s_magic      = NFS_SUPER_MAGIC;
 
+       server->io_stats = nfs_alloc_iostats();
+       if (server->io_stats == NULL)
+               return -ENOMEM;
+
        root_inode = nfs_get_root(sb, &server->fh, &fsinfo);
        /* Did getting the root inode fail? */
        if (IS_ERR(root_inode)) {
@@ -290,6 +294,9 @@ nfs_sb_init(struct super_block *sb, rpc_authflavor_t authflavor)
        }
        sb->s_root->d_op = server->rpc_ops->dentry_ops;
 
+       /* mount time stamp, in seconds */
+       server->mount_time = jiffies;
+
        /* Get some general file system info */
        if (server->namelen == 0 &&
            server->rpc_ops->pathconf(server, &server->fh, &pathinfo) >= 0)
@@ -582,7 +589,7 @@ nfs_statfs(struct super_block *sb, struct kstatfs *buf)
 
 }
 
-static int nfs_show_options(struct seq_file *m, struct vfsmount *mnt)
+static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, int showdefaults)
 {
        static struct proc_nfs_info {
                int flag;
@@ -598,20 +605,19 @@ static int nfs_show_options(struct seq_file *m, struct vfsmount *mnt)
                { 0, NULL, NULL }
        };
        struct proc_nfs_info *nfs_infop;
-       struct nfs_server *nfss = NFS_SB(mnt->mnt_sb);
        char buf[12];
        char *proto;
 
        seq_printf(m, ",vers=%d", nfss->rpc_ops->version);
        seq_printf(m, ",rsize=%d", nfss->rsize);
        seq_printf(m, ",wsize=%d", nfss->wsize);
-       if (nfss->acregmin != 3*HZ)
+       if (nfss->acregmin != 3*HZ || showdefaults)
                seq_printf(m, ",acregmin=%d", nfss->acregmin/HZ);
-       if (nfss->acregmax != 60*HZ)
+       if (nfss->acregmax != 60*HZ || showdefaults)
                seq_printf(m, ",acregmax=%d", nfss->acregmax/HZ);
-       if (nfss->acdirmin != 30*HZ)
+       if (nfss->acdirmin != 30*HZ || showdefaults)
                seq_printf(m, ",acdirmin=%d", nfss->acdirmin/HZ);
-       if (nfss->acdirmax != 60*HZ)
+       if (nfss->acdirmax != 60*HZ || showdefaults)
                seq_printf(m, ",acdirmax=%d", nfss->acdirmax/HZ);
        for (nfs_infop = nfs_info; nfs_infop->flag; nfs_infop++) {
                if (nfss->flags & nfs_infop->flag)
@@ -633,8 +639,91 @@ static int nfs_show_options(struct seq_file *m, struct vfsmount *mnt)
        seq_printf(m, ",proto=%s", proto);
        seq_printf(m, ",timeo=%lu", 10U * nfss->retrans_timeo / HZ);
        seq_printf(m, ",retrans=%u", nfss->retrans_count);
+}
+
+static int nfs_show_options(struct seq_file *m, struct vfsmount *mnt)
+{
+       struct nfs_server *nfss = NFS_SB(mnt->mnt_sb);
+
+       nfs_show_mount_options(m, nfss, 0);
+
        seq_puts(m, ",addr=");
        seq_escape(m, nfss->hostname, " \t\n\\");
+
+       return 0;
+}
+
+static int nfs_show_stats(struct seq_file *m, struct vfsmount *mnt)
+{
+       int i, cpu;
+       struct nfs_server *nfss = NFS_SB(mnt->mnt_sb);
+       struct rpc_auth *auth = nfss->client->cl_auth;
+       struct nfs_iostats totals = { };
+
+       seq_printf(m, "statvers=%s", NFS_IOSTAT_VERS);
+
+       /*
+        * Display all mount option settings
+        */
+       seq_printf(m, "\n\topts:\t");
+       seq_puts(m, mnt->mnt_sb->s_flags & MS_RDONLY ? "ro" : "rw");
+       seq_puts(m, mnt->mnt_sb->s_flags & MS_SYNCHRONOUS ? ",sync" : "");
+       seq_puts(m, mnt->mnt_sb->s_flags & MS_NOATIME ? ",noatime" : "");
+       seq_puts(m, mnt->mnt_sb->s_flags & MS_NODIRATIME ? ",nodiratime" : "");
+       nfs_show_mount_options(m, nfss, 1);
+
+       seq_printf(m, "\n\tage:\t%lu", (jiffies - nfss->mount_time) / HZ);
+
+       seq_printf(m, "\n\tcaps:\t");
+       seq_printf(m, "caps=0x%x", nfss->caps);
+       seq_printf(m, ",wtmult=%d", nfss->wtmult);
+       seq_printf(m, ",dtsize=%d", nfss->dtsize);
+       seq_printf(m, ",bsize=%d", nfss->bsize);
+       seq_printf(m, ",namelen=%d", nfss->namelen);
+
+#ifdef CONFIG_NFS_V4
+       if (nfss->rpc_ops->version == 4) {
+               seq_printf(m, "\n\tnfsv4:\t");
+               seq_printf(m, "bm0=0x%x", nfss->attr_bitmask[0]);
+               seq_printf(m, ",bm1=0x%x", nfss->attr_bitmask[1]);
+               seq_printf(m, ",acl=0x%x", nfss->acl_bitmask);
+       }
+#endif
+
+       /*
+        * Display security flavor in effect for this mount
+        */
+       seq_printf(m, "\n\tsec:\tflavor=%d", auth->au_ops->au_flavor);
+       if (auth->au_flavor)
+               seq_printf(m, ",pseudoflavor=%d", auth->au_flavor);
+
+       /*
+        * Display superblock I/O counters
+        */
+       for_each_possible_cpu(cpu) {
+               struct nfs_iostats *stats;
+
+               preempt_disable();
+               stats = per_cpu_ptr(nfss->io_stats, cpu);
+
+               for (i = 0; i < __NFSIOS_COUNTSMAX; i++)
+                       totals.events[i] += stats->events[i];
+               for (i = 0; i < __NFSIOS_BYTESMAX; i++)
+                       totals.bytes[i] += stats->bytes[i];
+
+               preempt_enable();
+       }
+
+       seq_printf(m, "\n\tevents:\t");
+       for (i = 0; i < __NFSIOS_COUNTSMAX; i++)
+               seq_printf(m, "%lu ", totals.events[i]);
+       seq_printf(m, "\n\tbytes:\t");
+       for (i = 0; i < __NFSIOS_BYTESMAX; i++)
+               seq_printf(m, "%Lu ", totals.bytes[i]);
+       seq_printf(m, "\n");
+
+       rpc_print_iostats(m, nfss->client);
+
        return 0;
 }
 
@@ -664,6 +753,8 @@ static void nfs_zap_caches_locked(struct inode *inode)
        struct nfs_inode *nfsi = NFS_I(inode);
        int mode = inode->i_mode;
 
+       nfs_inc_stats(inode, NFSIOS_ATTRINVALIDATE);
+
        NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode);
        NFS_ATTRTIMEO_UPDATE(inode) = jiffies;
 
@@ -755,7 +846,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
                .fh     = fh,
                .fattr  = fattr
        };
-       struct inode *inode = NULL;
+       struct inode *inode = ERR_PTR(-ENOENT);
        unsigned long hash;
 
        if ((fattr->valid & NFS_ATTR_FATTR) == 0)
@@ -768,8 +859,11 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
 
        hash = nfs_fattr_to_ino_t(fattr);
 
-       if (!(inode = iget5_locked(sb, hash, nfs_find_actor, nfs_init_locked, &desc)))
+       inode = iget5_locked(sb, hash, nfs_find_actor, nfs_init_locked, &desc);
+       if (inode == NULL) {
+               inode = ERR_PTR(-ENOMEM);
                goto out_no_inode;
+       }
 
        if (inode->i_state & I_NEW) {
                struct nfs_inode *nfsi = NFS_I(inode);
@@ -838,7 +932,7 @@ out:
        return inode;
 
 out_no_inode:
-       printk("nfs_fhget: iget failed\n");
+       dprintk("nfs_fhget: iget failed with error %ld\n", PTR_ERR(inode));
        goto out;
 }
 
@@ -851,6 +945,8 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr)
        struct nfs_fattr fattr;
        int error;
 
+       nfs_inc_stats(inode, NFSIOS_VFSSETATTR);
+
        if (attr->ia_valid & ATTR_SIZE) {
                if (!S_ISREG(inode->i_mode) || attr->ia_size == i_size_read(inode))
                        attr->ia_valid &= ~ATTR_SIZE;
@@ -904,6 +1000,7 @@ void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr)
                spin_unlock(&inode->i_lock);
        }
        if ((attr->ia_valid & ATTR_SIZE) != 0) {
+               nfs_inc_stats(inode, NFSIOS_SETATTRTRUNC);
                inode->i_size = attr->ia_size;
                vmtruncate(inode, attr->ia_size);
        }
@@ -951,7 +1048,7 @@ int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
        int err;
 
        /* Flush out writes to the server in order to update c/mtime */
-       nfs_sync_inode(inode, 0, 0, FLUSH_WAIT|FLUSH_NOCOMMIT);
+       nfs_sync_inode_wait(inode, 0, 0, FLUSH_NOCOMMIT);
 
        /*
         * We may force a getattr if the user cares about atime.
@@ -1189,6 +1286,7 @@ int nfs_attribute_timeout(struct inode *inode)
  */
 int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
 {
+       nfs_inc_stats(inode, NFSIOS_INODEREVALIDATE);
        if (!(NFS_I(inode)->cache_validity & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA))
                        && !nfs_attribute_timeout(inode))
                return NFS_STALE(inode) ? -ESTALE : 0;
@@ -1205,6 +1303,7 @@ 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) {
+               nfs_inc_stats(inode, NFSIOS_DATAINVALIDATE);
                if (S_ISREG(inode->i_mode))
                        nfs_sync_mapping(mapping);
                invalidate_inode_pages2(mapping);
@@ -1526,6 +1625,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
 
        /* Update attrtimeo value if we're out of the unstable period */
        if (invalid & NFS_INO_INVALID_ATTR) {
+               nfs_inc_stats(inode, NFSIOS_ATTRINVALIDATE);
                nfsi->attrtimeo = NFS_MINATTRTIMEO(inode);
                nfsi->attrtimeo_timestamp = jiffies;
        } else if (time_after(jiffies, nfsi->attrtimeo_timestamp+nfsi->attrtimeo)) {
@@ -1683,7 +1783,7 @@ static struct super_block *nfs_get_sb(struct file_system_type *fs_type,
 
        s->s_flags = flags;
 
-       error = nfs_fill_super(s, data, flags & MS_VERBOSE ? 1 : 0);
+       error = nfs_fill_super(s, data, flags & MS_SILENT ? 1 : 0);
        if (error) {
                up_write(&s->s_umount);
                deactivate_super(s);
@@ -1716,6 +1816,7 @@ static void nfs_kill_super(struct super_block *s)
 
        rpciod_down();          /* release rpciod */
 
+       nfs_free_iostats(server->io_stats);
        kfree(server->hostname);
        kfree(server);
 }
@@ -1742,6 +1843,7 @@ static struct super_operations nfs4_sops = {
        .clear_inode    = nfs4_clear_inode,
        .umount_begin   = nfs_umount_begin,
        .show_options   = nfs_show_options,
+       .show_stats     = nfs_show_stats,
 };
 
 /*
@@ -2002,7 +2104,7 @@ static struct super_block *nfs4_get_sb(struct file_system_type *fs_type,
 
        s->s_flags = flags;
 
-       error = nfs4_fill_super(s, data, flags & MS_VERBOSE ? 1 : 0);
+       error = nfs4_fill_super(s, data, flags & MS_SILENT ? 1 : 0);
        if (error) {
                up_write(&s->s_umount);
                deactivate_super(s);
@@ -2035,6 +2137,7 @@ static void nfs4_kill_super(struct super_block *sb)
 
        rpciod_down();
 
+       nfs_free_iostats(server->io_stats);
        kfree(server->hostname);
        kfree(server);
 }
@@ -2170,7 +2273,8 @@ static int nfs_init_inodecache(void)
 {
        nfs_inode_cachep = kmem_cache_create("nfs_inode_cache",
                                             sizeof(struct nfs_inode),
-                                            0, SLAB_RECLAIM_ACCOUNT,
+                                            0, (SLAB_RECLAIM_ACCOUNT|
+                                               SLAB_MEM_SPREAD),
                                             init_once, NULL);
        if (nfs_inode_cachep == NULL)
                return -ENOMEM;