diff options
author | Vyacheslav Dubeyko <slava@dubeyko.com> | 2013-07-03 18:08:05 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-07-03 19:08:01 -0400 |
commit | c7ef972c440fc9f1eda28b450cd30ad15c4d60cf (patch) | |
tree | 5f415ed5b082632848cae6e5798a8ac986e0ed38 | |
parent | e88b815e011bcacb7066f1156ce390f6b0adc9df (diff) |
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>
Signed-off-by: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
Tested-by: Vyacheslav Dubeyko <slava@dubeyko.com>
Cc: Joern Engel <joern@logfs.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | fs/nilfs2/alloc.c | 63 | ||||
-rw-r--r-- | fs/nilfs2/alloc.h | 2 | ||||
-rw-r--r-- | fs/nilfs2/ifile.c | 22 | ||||
-rw-r--r-- | fs/nilfs2/ifile.h | 2 | ||||
-rw-r--r-- | fs/nilfs2/super.c | 25 |
5 files changed, 112 insertions, 2 deletions
diff --git a/fs/nilfs2/alloc.c b/fs/nilfs2/alloc.c index eed4d7b26249..741fd02e0444 100644 --- a/fs/nilfs2/alloc.c +++ b/fs/nilfs2/alloc.c | |||
@@ -398,6 +398,69 @@ nilfs_palloc_rest_groups_in_desc_block(const struct inode *inode, | |||
398 | } | 398 | } |
399 | 399 | ||
400 | /** | 400 | /** |
401 | * nilfs_palloc_count_desc_blocks - count descriptor blocks number | ||
402 | * @inode: inode of metadata file using this allocator | ||
403 | * @desc_blocks: descriptor blocks number [out] | ||
404 | */ | ||
405 | static int nilfs_palloc_count_desc_blocks(struct inode *inode, | ||
406 | unsigned long *desc_blocks) | ||
407 | { | ||
408 | unsigned long blknum; | ||
409 | int ret; | ||
410 | |||
411 | ret = nilfs_bmap_last_key(NILFS_I(inode)->i_bmap, &blknum); | ||
412 | if (likely(!ret)) | ||
413 | *desc_blocks = DIV_ROUND_UP( | ||
414 | blknum, NILFS_MDT(inode)->mi_blocks_per_desc_block); | ||
415 | return ret; | ||
416 | } | ||
417 | |||
418 | /** | ||
419 | * nilfs_palloc_mdt_file_can_grow - check potential opportunity for | ||
420 | * MDT file growing | ||
421 | * @inode: inode of metadata file using this allocator | ||
422 | * @desc_blocks: known current descriptor blocks count | ||
423 | */ | ||
424 | static inline bool nilfs_palloc_mdt_file_can_grow(struct inode *inode, | ||
425 | unsigned long desc_blocks) | ||
426 | { | ||
427 | return (nilfs_palloc_groups_per_desc_block(inode) * desc_blocks) < | ||
428 | nilfs_palloc_groups_count(inode); | ||
429 | } | ||
430 | |||
431 | /** | ||
432 | * nilfs_palloc_count_max_entries - count max number of entries that can be | ||
433 | * described by descriptor blocks count | ||
434 | * @inode: inode of metadata file using this allocator | ||
435 | * @nused: current number of used entries | ||
436 | * @nmaxp: max number of entries [out] | ||
437 | */ | ||
438 | int nilfs_palloc_count_max_entries(struct inode *inode, u64 nused, u64 *nmaxp) | ||
439 | { | ||
440 | unsigned long desc_blocks = 0; | ||
441 | u64 entries_per_desc_block, nmax; | ||
442 | int err; | ||
443 | |||
444 | err = nilfs_palloc_count_desc_blocks(inode, &desc_blocks); | ||
445 | if (unlikely(err)) | ||
446 | return err; | ||
447 | |||
448 | entries_per_desc_block = (u64)nilfs_palloc_entries_per_group(inode) * | ||
449 | nilfs_palloc_groups_per_desc_block(inode); | ||
450 | nmax = entries_per_desc_block * desc_blocks; | ||
451 | |||
452 | if (nused == nmax && | ||
453 | nilfs_palloc_mdt_file_can_grow(inode, desc_blocks)) | ||
454 | nmax += entries_per_desc_block; | ||
455 | |||
456 | if (nused > nmax) | ||
457 | return -ERANGE; | ||
458 | |||
459 | *nmaxp = nmax; | ||
460 | return 0; | ||
461 | } | ||
462 | |||
463 | /** | ||
401 | * nilfs_palloc_prepare_alloc_entry - prepare to allocate a persistent object | 464 | * nilfs_palloc_prepare_alloc_entry - prepare to allocate a persistent object |
402 | * @inode: inode of metadata file using this allocator | 465 | * @inode: inode of metadata file using this allocator |
403 | * @req: nilfs_palloc_req structure exchanged for the allocation | 466 | * @req: nilfs_palloc_req structure exchanged for the allocation |
diff --git a/fs/nilfs2/alloc.h b/fs/nilfs2/alloc.h index fb7238100548..4bd6451b5703 100644 --- a/fs/nilfs2/alloc.h +++ b/fs/nilfs2/alloc.h | |||
@@ -48,6 +48,8 @@ int nilfs_palloc_get_entry_block(struct inode *, __u64, int, | |||
48 | void *nilfs_palloc_block_get_entry(const struct inode *, __u64, | 48 | void *nilfs_palloc_block_get_entry(const struct inode *, __u64, |
49 | const struct buffer_head *, void *); | 49 | const struct buffer_head *, void *); |
50 | 50 | ||
51 | int nilfs_palloc_count_max_entries(struct inode *, u64, u64 *); | ||
52 | |||
51 | /** | 53 | /** |
52 | * nilfs_palloc_req - persistent allocator request and reply | 54 | * nilfs_palloc_req - persistent allocator request and reply |
53 | * @pr_entry_nr: entry number (vblocknr or inode number) | 55 | * @pr_entry_nr: entry number (vblocknr or inode number) |
diff --git a/fs/nilfs2/ifile.c b/fs/nilfs2/ifile.c index d8e65bde083c..d788a5928351 100644 --- a/fs/nilfs2/ifile.c +++ b/fs/nilfs2/ifile.c | |||
@@ -160,6 +160,28 @@ int nilfs_ifile_get_inode_block(struct inode *ifile, ino_t ino, | |||
160 | } | 160 | } |
161 | 161 | ||
162 | /** | 162 | /** |
163 | * nilfs_ifile_count_free_inodes - calculate free inodes count | ||
164 | * @ifile: ifile inode | ||
165 | * @nmaxinodes: current maximum of available inodes count [out] | ||
166 | * @nfreeinodes: free inodes count [out] | ||
167 | */ | ||
168 | int nilfs_ifile_count_free_inodes(struct inode *ifile, | ||
169 | u64 *nmaxinodes, u64 *nfreeinodes) | ||
170 | { | ||
171 | u64 nused; | ||
172 | int err; | ||
173 | |||
174 | *nmaxinodes = 0; | ||
175 | *nfreeinodes = 0; | ||
176 | |||
177 | nused = atomic_read(&NILFS_I(ifile)->i_root->inodes_count); | ||
178 | err = nilfs_palloc_count_max_entries(ifile, nused, nmaxinodes); | ||
179 | if (likely(!err)) | ||
180 | *nfreeinodes = *nmaxinodes - nused; | ||
181 | return err; | ||
182 | } | ||
183 | |||
184 | /** | ||
163 | * nilfs_ifile_read - read or get ifile inode | 185 | * nilfs_ifile_read - read or get ifile inode |
164 | * @sb: super block instance | 186 | * @sb: super block instance |
165 | * @root: root object | 187 | * @root: root object |
diff --git a/fs/nilfs2/ifile.h b/fs/nilfs2/ifile.h index 59b6f2b51df6..679674d13372 100644 --- a/fs/nilfs2/ifile.h +++ b/fs/nilfs2/ifile.h | |||
@@ -49,6 +49,8 @@ int nilfs_ifile_create_inode(struct inode *, ino_t *, struct buffer_head **); | |||
49 | int nilfs_ifile_delete_inode(struct inode *, ino_t); | 49 | int nilfs_ifile_delete_inode(struct inode *, ino_t); |
50 | int nilfs_ifile_get_inode_block(struct inode *, ino_t, struct buffer_head **); | 50 | int nilfs_ifile_get_inode_block(struct inode *, ino_t, struct buffer_head **); |
51 | 51 | ||
52 | int nilfs_ifile_count_free_inodes(struct inode *, u64 *, u64 *); | ||
53 | |||
52 | int nilfs_ifile_read(struct super_block *sb, struct nilfs_root *root, | 54 | int nilfs_ifile_read(struct super_block *sb, struct nilfs_root *root, |
53 | size_t inode_size, struct nilfs_inode *raw_inode, | 55 | size_t inode_size, struct nilfs_inode *raw_inode, |
54 | struct inode **inodep); | 56 | struct inode **inodep); |
diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index c7d1f9f18b09..7d257e78fbad 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) | |||
609 | unsigned long overhead; | 609 | unsigned long overhead; |
610 | unsigned long nrsvblocks; | 610 | unsigned long nrsvblocks; |
611 | sector_t nfreeblocks; | 611 | sector_t nfreeblocks; |
612 | u64 nmaxinodes, nfreeinodes; | ||
612 | int err; | 613 | int err; |
613 | 614 | ||
614 | /* | 615 | /* |
@@ -633,14 +634,34 @@ static int nilfs_statfs(struct dentry *dentry, struct kstatfs *buf) | |||
633 | if (unlikely(err)) | 634 | if (unlikely(err)) |
634 | return err; | 635 | return err; |
635 | 636 | ||
637 | err = nilfs_ifile_count_free_inodes(root->ifile, | ||
638 | &nmaxinodes, &nfreeinodes); | ||
639 | if (unlikely(err)) { | ||
640 | printk(KERN_WARNING | ||
641 | "NILFS warning: fail to count free inodes: err %d.\n", | ||
642 | err); | ||
643 | if (err == -ERANGE) { | ||
644 | /* | ||
645 | * If nilfs_palloc_count_max_entries() returns | ||
646 | * -ERANGE error code then we simply treat | ||
647 | * curent inodes count as maximum possible and | ||
648 | * zero as free inodes value. | ||
649 | */ | ||
650 | nmaxinodes = atomic_read(&root->inodes_count); | ||
651 | nfreeinodes = 0; | ||
652 | err = 0; | ||
653 | } else | ||
654 | return err; | ||
655 | } | ||
656 | |||
636 | buf->f_type = NILFS_SUPER_MAGIC; | 657 | buf->f_type = NILFS_SUPER_MAGIC; |
637 | buf->f_bsize = sb->s_blocksize; | 658 | buf->f_bsize = sb->s_blocksize; |
638 | buf->f_blocks = blocks - overhead; | 659 | buf->f_blocks = blocks - overhead; |
639 | buf->f_bfree = nfreeblocks; | 660 | buf->f_bfree = nfreeblocks; |
640 | buf->f_bavail = (buf->f_bfree >= nrsvblocks) ? | 661 | buf->f_bavail = (buf->f_bfree >= nrsvblocks) ? |
641 | (buf->f_bfree - nrsvblocks) : 0; | 662 | (buf->f_bfree - nrsvblocks) : 0; |
642 | buf->f_files = atomic_read(&root->inodes_count); | 663 | buf->f_files = nmaxinodes; |
643 | buf->f_ffree = 0; /* nilfs_count_free_inodes(sb); */ | 664 | buf->f_ffree = nfreeinodes; |
644 | buf->f_namelen = NILFS_NAME_LEN; | 665 | buf->f_namelen = NILFS_NAME_LEN; |
645 | buf->f_fsid.val[0] = (u32)id; | 666 | buf->f_fsid.val[0] = (u32)id; |
646 | buf->f_fsid.val[1] = (u32)(id >> 32); | 667 | buf->f_fsid.val[1] = (u32)(id >> 32); |