linux-fsdevel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] nilfs2: implement calculation of free inodes count
@ 2013-05-03 13:12 Vyacheslav Dubeyko
       [not found] ` <1367586746.5050.4.camel-dzAnj6fV1RxGeWtTaGDT1UEK6ufn8VP3@public.gmane.org>
  0 siblings, 1 reply; 5+ messages in thread
From: Vyacheslav Dubeyko @ 2013-05-03 13:12 UTC (permalink / raw)
  To: linux-nilfs
  Cc: Ryusuke Konishi, linux-fsdevel, Andrew Morton, Clemens Eisserer

From: Vyacheslav Dubeyko <slava@dubeyko.com>
Subject: [PATCH] nilfs2: implement calculation of free inodes count

Currently, NILFS2 returns 0 as free inodes count (f_ffree) and current used inodes count as total file nodes in file system (f_files):

df -i
Filesystem      Inodes  IUsed   IFree IUse% Mounted on
/dev/loop0           2      2       0  100% /mnt/nilfs2

This patch implements real calculation of free inodes count. First of all, it is calculated total file nodes in file system as (desc_blocks_count * groups_per_desc_block * entries_per_group). Then, it is calculated free inodes count as difference the total file nodes and used inodes count. As a result, we have such output for NILFS2:

df -i
Filesystem       Inodes   IUsed    IFree IUse% Mounted on
/dev/loop0      4194304 2114701  2079603   51% /mnt/nilfs2

Reported-by: Clemens Eisserer <linuxhippy@gmail.com>
Signed-off-by: Vyacheslav Dubeyko <slava@dubeyko.com>
CC: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
Tested-by: Vyacheslav Dubeyko <slava@dubeyko.com>
---
 fs/nilfs2/alloc.c |   36 ++++++++------------------
 fs/nilfs2/alloc.h |   24 ++++++++++++++++++
 fs/nilfs2/ifile.c |   73 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 fs/nilfs2/ifile.h |    4 +++
 fs/nilfs2/mdt.h   |    2 ++
 fs/nilfs2/super.c |    9 +++++--
 6 files changed, 120 insertions(+), 28 deletions(-)

diff --git a/fs/nilfs2/alloc.c b/fs/nilfs2/alloc.c
index eed4d7b..6c61ae9 100644
--- a/fs/nilfs2/alloc.c
+++ b/fs/nilfs2/alloc.c
@@ -30,29 +30,6 @@
 #include "mdt.h"
 #include "alloc.h"
 
-
-/**
- * nilfs_palloc_groups_per_desc_block - get the number of groups that a group
- *					descriptor block can maintain
- * @inode: inode of metadata file using this allocator
- */
-static inline unsigned long
-nilfs_palloc_groups_per_desc_block(const struct inode *inode)
-{
-	return (1UL << inode->i_blkbits) /
-		sizeof(struct nilfs_palloc_group_desc);
-}
-
-/**
- * nilfs_palloc_groups_count - get maximum number of groups
- * @inode: inode of metadata file using this allocator
- */
-static inline unsigned long
-nilfs_palloc_groups_count(const struct inode *inode)
-{
-	return 1UL << (BITS_PER_LONG - (inode->i_blkbits + 3 /* log2(8) */));
-}
-
 /**
  * nilfs_palloc_init_blockgroup - initialize private variables for allocator
  * @inode: inode of metadata file using this allocator
@@ -80,6 +57,13 @@ int nilfs_palloc_init_blockgroup(struct inode *inode, unsigned entry_size)
 		mi->mi_blocks_per_group + 1;
 		/* Number of blocks per descriptor including the
 		   descriptor block */
+	atomic_set(&mi->mi_desc_blocks_count, 1);
+		/*
+		 * The field mi_desc_blocks_count is used for
+		 * storing knowledge about current count of
+		 * desciptor blocks. Initially, it is initialized
+		 * by one.
+		 */
 	return 0;
 }
 
@@ -246,9 +230,9 @@ static int nilfs_palloc_get_block(struct inode *inode, unsigned long blkoff,
  * @create: create flag
  * @bhp: pointer to store the resultant buffer head
  */
-static int nilfs_palloc_get_desc_block(struct inode *inode,
-				       unsigned long group,
-				       int create, struct buffer_head **bhp)
+int nilfs_palloc_get_desc_block(struct inode *inode,
+				unsigned long group,
+				int create, struct buffer_head **bhp)
 {
 	struct nilfs_palloc_cache *cache = NILFS_MDT(inode)->mi_palloc_cache;
 
diff --git a/fs/nilfs2/alloc.h b/fs/nilfs2/alloc.h
index fb72381..073b571 100644
--- a/fs/nilfs2/alloc.h
+++ b/fs/nilfs2/alloc.h
@@ -30,6 +30,28 @@
 #include <linux/fs.h>
 
 /**
+ * nilfs_palloc_groups_count - get maximum number of groups
+ * @inode: inode of metadata file using this allocator
+ */
+static inline unsigned long
+nilfs_palloc_groups_count(const struct inode *inode)
+{
+	return 1UL << (BITS_PER_LONG - (inode->i_blkbits + 3 /* log2(8) */));
+}
+
+/**
+ * nilfs_palloc_groups_per_desc_block - get the number of groups that a group
+ *					descriptor block can maintain
+ * @inode: inode of metadata file using this allocator
+ */
+static inline unsigned long
+nilfs_palloc_groups_per_desc_block(const struct inode *inode)
+{
+	return (1UL << inode->i_blkbits) /
+		sizeof(struct nilfs_palloc_group_desc);
+}
+
+/**
  * nilfs_palloc_entries_per_group - get the number of entries per group
  * @inode: inode of metadata file using this allocator
  *
@@ -45,6 +67,8 @@ nilfs_palloc_entries_per_group(const struct inode *inode)
 int nilfs_palloc_init_blockgroup(struct inode *, unsigned);
 int nilfs_palloc_get_entry_block(struct inode *, __u64, int,
 				 struct buffer_head **);
+int nilfs_palloc_get_desc_block(struct inode *, unsigned long, int,
+				struct buffer_head **);
 void *nilfs_palloc_block_get_entry(const struct inode *, __u64,
 				   const struct buffer_head *, void *);
 
diff --git a/fs/nilfs2/ifile.c b/fs/nilfs2/ifile.c
index d8e65bd..4f25549 100644
--- a/fs/nilfs2/ifile.c
+++ b/fs/nilfs2/ifile.c
@@ -160,6 +160,79 @@ int nilfs_ifile_get_inode_block(struct inode *ifile, ino_t ino,
 }
 
 /**
+ * nilfs_count_free_inodes - calculate free inodes count
+ * @root: root object
+ * @nmaxinodes: current maximum of available inodes count [out]
+ * @nfreeinodes: free inodes count [out]
+ */
+int nilfs_count_free_inodes(struct nilfs_root *root,
+				__statfs_word *nmaxinodes,
+				__statfs_word *nfreeinodes)
+{
+	struct inode *ifile;
+	struct buffer_head *desc_bh;
+	unsigned long groups_per_desc_block, entries_per_group;
+	unsigned long entries_per_desc_block;
+	unsigned long ngroups;
+	unsigned int desc_blocks;
+	__statfs_word nused, nmax;
+	unsigned long i;
+	int err = 0;
+
+	BUG_ON(!root || !nfreeinodes || !nmaxinodes);
+
+	ifile = root->ifile;
+	*nmaxinodes = 0;
+	*nfreeinodes = 0;
+
+	ngroups = nilfs_palloc_groups_count(ifile);
+	groups_per_desc_block = nilfs_palloc_groups_per_desc_block(ifile);
+	entries_per_group = nilfs_palloc_entries_per_group(ifile);
+	nused = atomic_read(&root->inodes_count);
+	entries_per_desc_block = groups_per_desc_block * entries_per_group;
+	desc_blocks =
+		atomic_read(&NILFS_IFILE_I(ifile)->mi.mi_desc_blocks_count);
+	nmax = desc_blocks * entries_per_desc_block;
+
+	if (nused >= nmax) {
+		for (i = groups_per_desc_block * (unsigned long)desc_blocks;
+				i < ngroups;
+					i += groups_per_desc_block) {
+
+			err = nilfs_palloc_get_desc_block(ifile, i, 0,
+								&desc_bh);
+			if (err)
+				break;
+			else
+				desc_blocks++;
+
+			brelse(desc_bh);
+		}
+
+		nmax = entries_per_desc_block * desc_blocks;
+
+		if (nused == nmax) {
+			desc_blocks++;
+			if ((desc_blocks * groups_per_desc_block) < ngroups)
+				nmax += entries_per_desc_block;
+			else
+				desc_blocks--;
+		}
+
+		atomic_set(&NILFS_IFILE_I(ifile)->mi.mi_desc_blocks_count,
+				desc_blocks);
+
+		if (nused > nmax)
+			return err ? err : -ERANGE;
+	}
+
+	*nmaxinodes = nmax;
+	*nfreeinodes = nmax - nused;
+
+	return 0;
+}
+
+/**
  * nilfs_ifile_read - read or get ifile inode
  * @sb: super block instance
  * @root: root object
diff --git a/fs/nilfs2/ifile.h b/fs/nilfs2/ifile.h
index 59b6f2b..57a8564 100644
--- a/fs/nilfs2/ifile.h
+++ b/fs/nilfs2/ifile.h
@@ -27,6 +27,7 @@
 
 #include <linux/fs.h>
 #include <linux/buffer_head.h>
+#include <linux/statfs.h>
 #include <linux/nilfs2_fs.h>
 #include "mdt.h"
 #include "alloc.h"
@@ -49,6 +50,9 @@ int nilfs_ifile_create_inode(struct inode *, ino_t *, struct buffer_head **);
 int nilfs_ifile_delete_inode(struct inode *, ino_t);
 int nilfs_ifile_get_inode_block(struct inode *, ino_t, struct buffer_head **);
 
+int nilfs_count_free_inodes(struct nilfs_root *,
+			    __statfs_word *, __statfs_word *);
+
 int nilfs_ifile_read(struct super_block *sb, struct nilfs_root *root,
 		     size_t inode_size, struct nilfs_inode *raw_inode,
 		     struct inode **inodep);
diff --git a/fs/nilfs2/mdt.h b/fs/nilfs2/mdt.h
index ab172e8..c01b6fb 100644
--- a/fs/nilfs2/mdt.h
+++ b/fs/nilfs2/mdt.h
@@ -53,6 +53,7 @@ struct nilfs_shadow_map {
  * @mi_shadow: shadow of bmap and page caches
  * @mi_blocks_per_group: number of blocks in a group
  * @mi_blocks_per_desc_block: number of blocks per descriptor block
+ * @mi_desc_blocks_count: number of descriptor blocks
  */
 struct nilfs_mdt_info {
 	struct rw_semaphore	mi_sem;
@@ -64,6 +65,7 @@ struct nilfs_mdt_info {
 	struct nilfs_shadow_map *mi_shadow;
 	unsigned long		mi_blocks_per_group;
 	unsigned long		mi_blocks_per_desc_block;
+	atomic_t		mi_desc_blocks_count;
 };
 
 static inline struct nilfs_mdt_info *NILFS_MDT(const struct inode *inode)
diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c
index c7d1f9f..548676b 100644
--- a/fs/nilfs2/super.c
+++ b/fs/nilfs2/super.c
@@ -609,6 +609,7 @@ static int nilfs_statfs(struct dentry *dentry, struct kstatfs *buf)
 	unsigned long overhead;
 	unsigned long nrsvblocks;
 	sector_t nfreeblocks;
+	__statfs_word nmaxinodes, nfreeinodes;
 	int err;
 
 	/*
@@ -633,14 +634,18 @@ static int nilfs_statfs(struct dentry *dentry, struct kstatfs *buf)
 	if (unlikely(err))
 		return err;
 
+	err = nilfs_count_free_inodes(root, &nmaxinodes, &nfreeinodes);
+	if (unlikely(err))
+		return err;
+
 	buf->f_type = NILFS_SUPER_MAGIC;
 	buf->f_bsize = sb->s_blocksize;
 	buf->f_blocks = blocks - overhead;
 	buf->f_bfree = nfreeblocks;
 	buf->f_bavail = (buf->f_bfree >= nrsvblocks) ?
 		(buf->f_bfree - nrsvblocks) : 0;
-	buf->f_files = atomic_read(&root->inodes_count);
-	buf->f_ffree = 0; /* nilfs_count_free_inodes(sb); */
+	buf->f_files = nmaxinodes;
+	buf->f_ffree = nfreeinodes;
 	buf->f_namelen = NILFS_NAME_LEN;
 	buf->f_fsid.val[0] = (u32)id;
 	buf->f_fsid.val[1] = (u32)(id >> 32);
-- 
1.7.9.5




^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH] nilfs2: implement calculation of free inodes count
       [not found] ` <1367586746.5050.4.camel-dzAnj6fV1RxGeWtTaGDT1UEK6ufn8VP3@public.gmane.org>
@ 2013-05-06 14:07   ` Ryusuke Konishi
       [not found]     ` <CAKFNMo=mnO=kTVWySGLYTC1o8A3uavEo6VhtthgT_kJhN+0Zfg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
  0 siblings, 1 reply; 5+ messages in thread
From: Ryusuke Konishi @ 2013-05-06 14:07 UTC (permalink / raw)
  To: Vyacheslav Dubeyko
  Cc: linux-nilfs, linux-fsdevel-u79uwXL29TY76Z2rM5mHXA, Andrew Morton,
	Clemens Eisserer

Hi Vyacheslav,

2013/5/3 Vyacheslav Dubeyko <slava-yeENwD64cLxBDgjK7y7TUQ@public.gmane.org>
>
> From: Vyacheslav Dubeyko <slava-yeENwD64cLxBDgjK7y7TUQ@public.gmane.org>
> Subject: [PATCH] nilfs2: implement calculation of free inodes count
>
> Currently, NILFS2 returns 0 as free inodes count (f_ffree) and current used inodes count as total file nodes in file system (f_files):
>
> df -i
> Filesystem      Inodes  IUsed   IFree IUse% Mounted on
> /dev/loop0           2      2       0  100% /mnt/nilfs2
>
> This patch implements real calculation of free inodes count. First of all, it is calculated total file nodes in file system as (desc_blocks_count * groups_per_desc_block * entries_per_group). Then, it is calculated free inodes count as difference the total file nodes and used inodes count. As a result, we have such output for NILFS2:
>
> df -i
> Filesystem       Inodes   IUsed    IFree IUse% Mounted on
> /dev/loop0      4194304 2114701  2079603   51% /mnt/nilfs2
>
> Reported-by: Clemens Eisserer <linuxhippy-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> Signed-off-by: Vyacheslav Dubeyko <slava-yeENwD64cLxBDgjK7y7TUQ@public.gmane.org>
> CC: Ryusuke Konishi <konishi.ryusuke-Zyj7fXuS5i5L9jVzuh4AOg@public.gmane.org>
> Tested-by: Vyacheslav Dubeyko <slava-yeENwD64cLxBDgjK7y7TUQ@public.gmane.org>

I agree to use count of descriptor blocks of ifile to
calculate the approximate value of the total file nodes.

Here are my comments on the patch:

(1) Consider using nilfs_bmap_last_key()  instead of repeating read
     of descriptor blocks to decide new desc_blocks count.
     The current logic may incur many device read accesses
     even if it is updated in a stepwise fashion with
     NILFS_IFILE_I(ifile)->mi.mi_desc_blocks_count.

(2) Do not use __statfs_word type for local variables or arguments of
     functions.  I think an integer type such as u64 should be used
     instead.

(3) Consider moving the main part of nilfs_count_free_inodes()
     function to alloc.c, for example, as a function like:

     int nilfs_palloc_count_max_entries(struct inode *inode, u64 nentries,
                                                        u64 *nmaxentries);

     Then, nilfs_palloc_groups_per_desc_block() and
     nilfs_palloc_groups_count() do not need to be moved,
     and nilfs_root argument becomes eliminable from the routine
     added to ifile.c.

(4) Please consider the name convention of functions in ifile.c.
     The ifile.c includes routines related to ifile inode,
     and all its functions have the same name convention (i.e.
     nilfs_ifile_xxxx() ).

(5) nilfs_count_free_inodes() may return -ERANGE.
     (It's OK if inode_count is given as an argument of the function.)
     But, nilfs_statfs() should not return -ERANGE as-is.

     In that case, I think nilfs_statfs() should output a warning
     message and ignore the error code.

Regards,
Ryusuke Konishi

>
> ---
>  fs/nilfs2/alloc.c |   36 ++++++++------------------
>  fs/nilfs2/alloc.h |   24 ++++++++++++++++++
>  fs/nilfs2/ifile.c |   73 +++++++++++++++++++++++++++++++++++++++++++++++++++++
>  fs/nilfs2/ifile.h |    4 +++
>  fs/nilfs2/mdt.h   |    2 ++
>  fs/nilfs2/super.c |    9 +++++--
>  6 files changed, 120 insertions(+), 28 deletions(-)
>
> diff --git a/fs/nilfs2/alloc.c b/fs/nilfs2/alloc.c
> index eed4d7b..6c61ae9 100644
> --- a/fs/nilfs2/alloc.c
> +++ b/fs/nilfs2/alloc.c
> @@ -30,29 +30,6 @@
>  #include "mdt.h"
>  #include "alloc.h"
>
> -
> -/**
> - * nilfs_palloc_groups_per_desc_block - get the number of groups that a group
> - *                                     descriptor block can maintain
> - * @inode: inode of metadata file using this allocator
> - */
> -static inline unsigned long
> -nilfs_palloc_groups_per_desc_block(const struct inode *inode)
> -{
> -       return (1UL << inode->i_blkbits) /
> -               sizeof(struct nilfs_palloc_group_desc);
> -}
> -
> -/**
> - * nilfs_palloc_groups_count - get maximum number of groups
> - * @inode: inode of metadata file using this allocator
> - */
> -static inline unsigned long
> -nilfs_palloc_groups_count(const struct inode *inode)
> -{
> -       return 1UL << (BITS_PER_LONG - (inode->i_blkbits + 3 /* log2(8) */));
> -}
> -
>  /**
>   * nilfs_palloc_init_blockgroup - initialize private variables for allocator
>   * @inode: inode of metadata file using this allocator
> @@ -80,6 +57,13 @@ int nilfs_palloc_init_blockgroup(struct inode *inode, unsigned entry_size)
>                 mi->mi_blocks_per_group + 1;
>                 /* Number of blocks per descriptor including the
>                    descriptor block */
> +       atomic_set(&mi->mi_desc_blocks_count, 1);
> +               /*
> +                * The field mi_desc_blocks_count is used for
> +                * storing knowledge about current count of
> +                * desciptor blocks. Initially, it is initialized
> +                * by one.
> +                */
>         return 0;
>  }
>
> @@ -246,9 +230,9 @@ static int nilfs_palloc_get_block(struct inode *inode, unsigned long blkoff,
>   * @create: create flag
>   * @bhp: pointer to store the resultant buffer head
>   */
> -static int nilfs_palloc_get_desc_block(struct inode *inode,
> -                                      unsigned long group,
> -                                      int create, struct buffer_head **bhp)
> +int nilfs_palloc_get_desc_block(struct inode *inode,
> +                               unsigned long group,
> +                               int create, struct buffer_head **bhp)
>  {
>         struct nilfs_palloc_cache *cache = NILFS_MDT(inode)->mi_palloc_cache;
>
> diff --git a/fs/nilfs2/alloc.h b/fs/nilfs2/alloc.h
> index fb72381..073b571 100644
> --- a/fs/nilfs2/alloc.h
> +++ b/fs/nilfs2/alloc.h
> @@ -30,6 +30,28 @@
>  #include <linux/fs.h>
>
>  /**
> + * nilfs_palloc_groups_count - get maximum number of groups
> + * @inode: inode of metadata file using this allocator
> + */
> +static inline unsigned long
> +nilfs_palloc_groups_count(const struct inode *inode)
> +{
> +       return 1UL << (BITS_PER_LONG - (inode->i_blkbits + 3 /* log2(8) */));
> +}
> +
> +/**
> + * nilfs_palloc_groups_per_desc_block - get the number of groups that a group
> + *                                     descriptor block can maintain
> + * @inode: inode of metadata file using this allocator
> + */
> +static inline unsigned long
> +nilfs_palloc_groups_per_desc_block(const struct inode *inode)
> +{
> +       return (1UL << inode->i_blkbits) /
> +               sizeof(struct nilfs_palloc_group_desc);
> +}
> +
> +/**
>   * nilfs_palloc_entries_per_group - get the number of entries per group
>   * @inode: inode of metadata file using this allocator
>   *
> @@ -45,6 +67,8 @@ nilfs_palloc_entries_per_group(const struct inode *inode)
>  int nilfs_palloc_init_blockgroup(struct inode *, unsigned);
>  int nilfs_palloc_get_entry_block(struct inode *, __u64, int,
>                                  struct buffer_head **);
> +int nilfs_palloc_get_desc_block(struct inode *, unsigned long, int,
> +                               struct buffer_head **);
>  void *nilfs_palloc_block_get_entry(const struct inode *, __u64,
>                                    const struct buffer_head *, void *);
>
> diff --git a/fs/nilfs2/ifile.c b/fs/nilfs2/ifile.c
> index d8e65bd..4f25549 100644
> --- a/fs/nilfs2/ifile.c
> +++ b/fs/nilfs2/ifile.c
> @@ -160,6 +160,79 @@ int nilfs_ifile_get_inode_block(struct inode *ifile, ino_t ino,
>  }
>
>  /**
> + * nilfs_count_free_inodes - calculate free inodes count
> + * @root: root object
> + * @nmaxinodes: current maximum of available inodes count [out]
> + * @nfreeinodes: free inodes count [out]
> + */
> +int nilfs_count_free_inodes(struct nilfs_root *root,
> +                               __statfs_word *nmaxinodes,
> +                               __statfs_word *nfreeinodes)
> +{
> +       struct inode *ifile;
> +       struct buffer_head *desc_bh;
> +       unsigned long groups_per_desc_block, entries_per_group;
> +       unsigned long entries_per_desc_block;
> +       unsigned long ngroups;
> +       unsigned int desc_blocks;
> +       __statfs_word nused, nmax;
> +       unsigned long i;
> +       int err = 0;
> +
> +       BUG_ON(!root || !nfreeinodes || !nmaxinodes);
> +
> +       ifile = root->ifile;
> +       *nmaxinodes = 0;
> +       *nfreeinodes = 0;
> +
> +       ngroups = nilfs_palloc_groups_count(ifile);
> +       groups_per_desc_block = nilfs_palloc_groups_per_desc_block(ifile);
> +       entries_per_group = nilfs_palloc_entries_per_group(ifile);
> +       nused = atomic_read(&root->inodes_count);
> +       entries_per_desc_block = groups_per_desc_block * entries_per_group;
> +       desc_blocks =
> +               atomic_read(&NILFS_IFILE_I(ifile)->mi.mi_desc_blocks_count);
> +       nmax = desc_blocks * entries_per_desc_block;
> +
> +       if (nused >= nmax) {
> +               for (i = groups_per_desc_block * (unsigned long)desc_blocks;
> +                               i < ngroups;
> +                                       i += groups_per_desc_block) {
> +
> +                       err = nilfs_palloc_get_desc_block(ifile, i, 0,
> +                                                               &desc_bh);
> +                       if (err)
> +                               break;
> +                       else
> +                               desc_blocks++;
> +
> +                       brelse(desc_bh);
> +               }
> +
> +               nmax = entries_per_desc_block * desc_blocks;
> +
> +               if (nused == nmax) {
> +                       desc_blocks++;
> +                       if ((desc_blocks * groups_per_desc_block) < ngroups)
> +                               nmax += entries_per_desc_block;
> +                       else
> +                               desc_blocks--;
> +               }
> +
> +               atomic_set(&NILFS_IFILE_I(ifile)->mi.mi_desc_blocks_count,
> +                               desc_blocks);
> +
> +               if (nused > nmax)
> +                       return err ? err : -ERANGE;
> +       }
> +
> +       *nmaxinodes = nmax;
> +       *nfreeinodes = nmax - nused;
> +
> +       return 0;
> +}
> +
> +/**
>   * nilfs_ifile_read - read or get ifile inode
>   * @sb: super block instance
>   * @root: root object
> diff --git a/fs/nilfs2/ifile.h b/fs/nilfs2/ifile.h
> index 59b6f2b..57a8564 100644
> --- a/fs/nilfs2/ifile.h
> +++ b/fs/nilfs2/ifile.h
> @@ -27,6 +27,7 @@
>
>  #include <linux/fs.h>
>  #include <linux/buffer_head.h>
> +#include <linux/statfs.h>
>  #include <linux/nilfs2_fs.h>
>  #include "mdt.h"
>  #include "alloc.h"
> @@ -49,6 +50,9 @@ int nilfs_ifile_create_inode(struct inode *, ino_t *, struct buffer_head **);
>  int nilfs_ifile_delete_inode(struct inode *, ino_t);
>  int nilfs_ifile_get_inode_block(struct inode *, ino_t, struct buffer_head **);
>
> +int nilfs_count_free_inodes(struct nilfs_root *,
> +                           __statfs_word *, __statfs_word *);
> +
>  int nilfs_ifile_read(struct super_block *sb, struct nilfs_root *root,
>                      size_t inode_size, struct nilfs_inode *raw_inode,
>                      struct inode **inodep);
> diff --git a/fs/nilfs2/mdt.h b/fs/nilfs2/mdt.h
> index ab172e8..c01b6fb 100644
> --- a/fs/nilfs2/mdt.h
> +++ b/fs/nilfs2/mdt.h
> @@ -53,6 +53,7 @@ struct nilfs_shadow_map {
>   * @mi_shadow: shadow of bmap and page caches
>   * @mi_blocks_per_group: number of blocks in a group
>   * @mi_blocks_per_desc_block: number of blocks per descriptor block
> + * @mi_desc_blocks_count: number of descriptor blocks
>   */
>  struct nilfs_mdt_info {
>         struct rw_semaphore     mi_sem;
> @@ -64,6 +65,7 @@ struct nilfs_mdt_info {
>         struct nilfs_shadow_map *mi_shadow;
>         unsigned long           mi_blocks_per_group;
>         unsigned long           mi_blocks_per_desc_block;
> +       atomic_t                mi_desc_blocks_count;
>  };
>
>  static inline struct nilfs_mdt_info *NILFS_MDT(const struct inode *inode)
> diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c
> index c7d1f9f..548676b 100644
> --- a/fs/nilfs2/super.c
> +++ b/fs/nilfs2/super.c
> @@ -609,6 +609,7 @@ static int nilfs_statfs(struct dentry *dentry, struct kstatfs *buf)
>         unsigned long overhead;
>         unsigned long nrsvblocks;
>         sector_t nfreeblocks;
> +       __statfs_word nmaxinodes, nfreeinodes;
>         int err;
>
>         /*
> @@ -633,14 +634,18 @@ static int nilfs_statfs(struct dentry *dentry, struct kstatfs *buf)
>         if (unlikely(err))
>                 return err;
>
> +       err = nilfs_count_free_inodes(root, &nmaxinodes, &nfreeinodes);
> +       if (unlikely(err))
> +               return err;
> +
>         buf->f_type = NILFS_SUPER_MAGIC;
>         buf->f_bsize = sb->s_blocksize;
>         buf->f_blocks = blocks - overhead;
>         buf->f_bfree = nfreeblocks;
>         buf->f_bavail = (buf->f_bfree >= nrsvblocks) ?
>                 (buf->f_bfree - nrsvblocks) : 0;
> -       buf->f_files = atomic_read(&root->inodes_count);
> -       buf->f_ffree = 0; /* nilfs_count_free_inodes(sb); */
> +       buf->f_files = nmaxinodes;
> +       buf->f_ffree = nfreeinodes;
>         buf->f_namelen = NILFS_NAME_LEN;
>         buf->f_fsid.val[0] = (u32)id;
>         buf->f_fsid.val[1] = (u32)(id >> 32);
> --
> 1.7.9.5
>
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in
> the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] nilfs2: implement calculation of free inodes count
       [not found]     ` <CAKFNMo=mnO=kTVWySGLYTC1o8A3uavEo6VhtthgT_kJhN+0Zfg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2013-05-07 12:49       ` Vyacheslav Dubeyko
  2013-05-07 14:38         ` Ryusuke Konishi
  0 siblings, 1 reply; 5+ messages in thread
From: Vyacheslav Dubeyko @ 2013-05-07 12:49 UTC (permalink / raw)
  To: Ryusuke Konishi
  Cc: linux-nilfs, linux-fsdevel-u79uwXL29TY76Z2rM5mHXA, Andrew Morton,
	Clemens Eisserer

Hi Ryusuke,

On Mon, 2013-05-06 at 23:07 +0900, Ryusuke Konishi wrote:

[snip]
> I agree to use count of descriptor blocks of ifile to
> calculate the approximate value of the total file nodes.
> 
> Here are my comments on the patch:
> 
> (1) Consider using nilfs_bmap_last_key()  instead of repeating read
>      of descriptor blocks to decide new desc_blocks count.
>      The current logic may incur many device read accesses
>      even if it is updated in a stepwise fashion with
>      NILFS_IFILE_I(ifile)->mi.mi_desc_blocks_count.
> 

Maybe I misunderstand something but I think that nilfs_bmap_last_key()
can be less efficient solution. As I understand, descriptor block with 4
KB in size can describe 1024 groups. Every group can describe 32768
inodes. As a result, we can describe 32768 * 1024 = 33554432 inodes by
means of one descriptor block. So, the most frequent use-case will be
calculation with 1 descriptor block, from my point of view. Yes, I agree
that it is possible not read mi_desc_blocks_count in the beginning of
nilfs_count_free_inodes() but to use simply 1 as constant value. But,
anyway, even if we need to define a real count of descriptor blocks then
it makes only once (if we exhaust descriptor block capacity or after
mount in the case of presence of several descriptor blocks). This
counted value is saved in mi_desc_blocks_count and is used in further
calculations by means of reading mi_desc_blocks_count during exhausting
of next 33554432 inodes count.

Do you mean that nilfs_bmap_last_key() can initiate lesser read requests
as my way of using nilfs_palloc_get_desc_block() call?

> (2) Do not use __statfs_word type for local variables or arguments of
>      functions.  I think an integer type such as u64 should be used
>      instead.
> 

Ok. I agree.

> (3) Consider moving the main part of nilfs_count_free_inodes()
>      function to alloc.c, for example, as a function like:
> 
>      int nilfs_palloc_count_max_entries(struct inode *inode, u64 nentries,
>                                                         u64 *nmaxentries);
> 
>      Then, nilfs_palloc_groups_per_desc_block() and
>      nilfs_palloc_groups_count() do not need to be moved,
>      and nilfs_root argument becomes eliminable from the routine
>      added to ifile.c.
> 

Ok. I'll do it.

> (4) Please consider the name convention of functions in ifile.c.
>      The ifile.c includes routines related to ifile inode,
>      and all its functions have the same name convention (i.e.
>      nilfs_ifile_xxxx() ).
> 

Ok. I agree.

> (5) nilfs_count_free_inodes() may return -ERANGE.
>      (It's OK if inode_count is given as an argument of the function.)
>      But, nilfs_statfs() should not return -ERANGE as-is.
> 
>      In that case, I think nilfs_statfs() should output a warning
>      message and ignore the error code.
> 

Currently, it is processed returned error of nilfs_count_free_blocks()
in nilfs_statfs(). Yes, nilfs_count_free_blocks() doesn't return any
error really. But, potentially, nilfs_statfs() can return error from
this method. So, as I understand, you suggest simply to warn in
nilfs_statfs() about errors in called methods and doesn't return these
errors from it. Am I correct?

With the best regards,
Vyacheslav Dubeyko.

> Regards,
> Ryusuke Konishi
> 


--
To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] nilfs2: implement calculation of free inodes count
  2013-05-07 12:49       ` Vyacheslav Dubeyko
@ 2013-05-07 14:38         ` Ryusuke Konishi
       [not found]           ` <20130507.233850.160073573.konishi.ryusuke-Zyj7fXuS5i5L9jVzuh4AOg@public.gmane.org>
  0 siblings, 1 reply; 5+ messages in thread
From: Ryusuke Konishi @ 2013-05-07 14:38 UTC (permalink / raw)
  To: Vyacheslav Dubeyko
  Cc: linux-nilfs, linux-fsdevel-u79uwXL29TY76Z2rM5mHXA, Andrew Morton,
	Clemens Eisserer

Hi Vyacheslav,
On Tue, 07 May 2013 16:49:37 +0400, Vyacheslav Dubeyko wrote:
> Hi Ryusuke,
> 
> On Mon, 2013-05-06 at 23:07 +0900, Ryusuke Konishi wrote:
> 
> [snip]
>> I agree to use count of descriptor blocks of ifile to
>> calculate the approximate value of the total file nodes.
>> 
>> Here are my comments on the patch:
>> 
>> (1) Consider using nilfs_bmap_last_key()  instead of repeating read
>>      of descriptor blocks to decide new desc_blocks count.
>>      The current logic may incur many device read accesses
>>      even if it is updated in a stepwise fashion with
>>      NILFS_IFILE_I(ifile)->mi.mi_desc_blocks_count.
>> 
> 
> Maybe I misunderstand something but I think that nilfs_bmap_last_key()
> can be less efficient solution. As I understand, descriptor block with 4
> KB in size can describe 1024 groups. Every group can describe 32768
> inodes. As a result, we can describe 32768 * 1024 = 33554432 inodes by
> means of one descriptor block. So, the most frequent use-case will be
> calculation with 1 descriptor block, from my point of view. Yes, I agree
> that it is possible not read mi_desc_blocks_count in the beginning of
> nilfs_count_free_inodes() but to use simply 1 as constant value. But,
> anyway, even if we need to define a real count of descriptor blocks then
> it makes only once (if we exhaust descriptor block capacity or after
> mount in the case of presence of several descriptor blocks). This
> counted value is saved in mi_desc_blocks_count and is used in further
> calculations by means of reading mi_desc_blocks_count during exhausting
> of next 33554432 inodes count.

Ok, I agree that your calculation makes sense.  So, repeating the read
of descriptor blocks is not a problem in the real world.

Please go on with the current approach.

> Do you mean that nilfs_bmap_last_key() can initiate lesser read requests
> as my way of using nilfs_palloc_get_desc_block() call?

Yes, nilfs_bmap_last_key() does not involve read of leaf blocks of
nilfs btree (i.e. data blocks including descriptor block, etc) unlike
with nilfs_palloc_get_desc_block function, however it is negligible
anyway as you pointed out.
 
>> (2) Do not use __statfs_word type for local variables or arguments of
>>      functions.  I think an integer type such as u64 should be used
>>      instead.
>> 
> 
> Ok. I agree.
> 
>> (3) Consider moving the main part of nilfs_count_free_inodes()
>>      function to alloc.c, for example, as a function like:
>> 
>>      int nilfs_palloc_count_max_entries(struct inode *inode, u64 nentries,
>>                                                         u64 *nmaxentries);
>> 
>>      Then, nilfs_palloc_groups_per_desc_block() and
>>      nilfs_palloc_groups_count() do not need to be moved,
>>      and nilfs_root argument becomes eliminable from the routine
>>      added to ifile.c.
>> 
> 
> Ok. I'll do it.
> 
>> (4) Please consider the name convention of functions in ifile.c.
>>      The ifile.c includes routines related to ifile inode,
>>      and all its functions have the same name convention (i.e.
>>      nilfs_ifile_xxxx() ).
>> 
> 
> Ok. I agree.
> 
>> (5) nilfs_count_free_inodes() may return -ERANGE.
>>      (It's OK if inode_count is given as an argument of the function.)
>>      But, nilfs_statfs() should not return -ERANGE as-is.
>> 
>>      In that case, I think nilfs_statfs() should output a warning
>>      message and ignore the error code.
>> 
> 
> Currently, it is processed returned error of nilfs_count_free_blocks()
> in nilfs_statfs(). Yes, nilfs_count_free_blocks() doesn't return any
> error really. But, potentially, nilfs_statfs() can return error from
> this method. So, as I understand, you suggest simply to warn in
> nilfs_statfs() about errors in called methods and doesn't return these
> errors from it. Am I correct?

I mean that only -ERANGE should not be returned to user space as-is
because it looks an internal error code indicating that there is an
inconsistency in the file system metadata.  Other errors like -EIO or
-ENOMEM can be returned to user space.  These error codes are actually
specified in the man page of statfs.


With regards,
Ryusuke Konishi

> With the best regards,
> Vyacheslav Dubeyko.
> 
>> Regards,
>> Ryusuke Konishi
>> 
> 
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in
> the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] nilfs2: implement calculation of free inodes count
       [not found]           ` <20130507.233850.160073573.konishi.ryusuke-Zyj7fXuS5i5L9jVzuh4AOg@public.gmane.org>
@ 2013-05-07 15:17             ` Ryusuke Konishi
  0 siblings, 0 replies; 5+ messages in thread
From: Ryusuke Konishi @ 2013-05-07 15:17 UTC (permalink / raw)
  To: Vyacheslav Dubeyko
  Cc: linux-nilfs, linux-fsdevel-u79uwXL29TY76Z2rM5mHXA, Andrew Morton,
	Clemens Eisserer

On Tue, 07 May 2013 23:38:50 +0900 (JST), Ryusuke Konishi wrote:
> Hi Vyacheslav,
> On Tue, 07 May 2013 16:49:37 +0400, Vyacheslav Dubeyko wrote:
>> Hi Ryusuke,
>> 
>> On Mon, 2013-05-06 at 23:07 +0900, Ryusuke Konishi wrote:
>> 
>> [snip]
>>> I agree to use count of descriptor blocks of ifile to
>>> calculate the approximate value of the total file nodes.
>>> 
>>> Here are my comments on the patch:
>>> 
>>> (1) Consider using nilfs_bmap_last_key()  instead of repeating read
>>>      of descriptor blocks to decide new desc_blocks count.
>>>      The current logic may incur many device read accesses
>>>      even if it is updated in a stepwise fashion with
>>>      NILFS_IFILE_I(ifile)->mi.mi_desc_blocks_count.
>>> 
[snip]
>> Do you mean that nilfs_bmap_last_key() can initiate lesser read requests
>> as my way of using nilfs_palloc_get_desc_block() call?
> 
> Yes, nilfs_bmap_last_key() does not involve read of leaf blocks of
> nilfs btree (i.e. data blocks including descriptor block, etc) unlike
> with nilfs_palloc_get_desc_block function, however it is negligible
> anyway as you pointed out.

Oops, I have missed the point.  Most important difference in these two
functions is that you do not need to repeat calling the function in
the case of nilfs_bmap_last_key().  nilfs_bmap_last_key() returns the
maximum index of allocated data blocks with one call.

Regards,
Ryusuke Konishi
--
To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2013-05-07 15:17 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-05-03 13:12 [PATCH] nilfs2: implement calculation of free inodes count Vyacheslav Dubeyko
     [not found] ` <1367586746.5050.4.camel-dzAnj6fV1RxGeWtTaGDT1UEK6ufn8VP3@public.gmane.org>
2013-05-06 14:07   ` Ryusuke Konishi
     [not found]     ` <CAKFNMo=mnO=kTVWySGLYTC1o8A3uavEo6VhtthgT_kJhN+0Zfg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2013-05-07 12:49       ` Vyacheslav Dubeyko
2013-05-07 14:38         ` Ryusuke Konishi
     [not found]           ` <20130507.233850.160073573.konishi.ryusuke-Zyj7fXuS5i5L9jVzuh4AOg@public.gmane.org>
2013-05-07 15:17             ` Ryusuke Konishi

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).