How to Free Inode Usage

How to Free Inode Usage?

It's quite easy for a disk to have a large number of inodes used even if the disk is not very full.

An inode is allocated to a file so, if you have gazillions of files, all 1 byte each, you'll run out of inodes long before you run out of disk.

It's also possible that deleting files will not reduce the inode count if the files have multiple hard links. As I said, inodes belong to the file, not the directory entry. If a file has two directory entries linked to it, deleting one will not free the inode.

Additionally, you can delete a directory entry but, if a running process still has the file open, the inode won't be freed.

My initial advice would be to delete all the files you can, then reboot the box to ensure no processes are left holding the files open.

If you do that and you still have a problem, let us know.

By the way, if you're looking for the directories that contain lots of files, this script may help:

#!/bin/bash

# count_em - count files in all subdirectories under current directory.
echo 'echo $(ls -a "$1" | wc -l) $1' >/tmp/count_em_$$
chmod 700 /tmp/count_em_$$
find . -mount -type d -print0 | xargs -0 -n1 /tmp/count_em_$$ | sort -n
rm -f /tmp/count_em_$$

Inode usage without df -i

What you seek, is reported by the statvfs() function, for each mounted filesystem (specified by providing a path to any file or directory on said mounted filesystem).

If the system has GNU coreutils installed, it has a small utility called stat. For each path to a file or directory on a filesystem,

stat -c '%d %c' -f /path

reports the number of free inodes and the total number of inodes, one line per path given. If the system uses busybox, then

busybox stat -c '%d %c' -f /path

does the same thing.

If you need more control with the output, or neither of the above work for you for some reason, you can easily write your own utility to report a summary:
Here is an example, inode-stats.c:

#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/statvfs.h>
#include <stdint.h>
#include <inttypes.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>

int main(int argc, char *argv[])
{
dev_t device[argc];
int devices = 0;
uint64_t total_inodes = 0;
uint64_t avail_inodes = 0; /* Free to normal users */
uint64_t free_inodes = 0; /* Free to superuser */
int arg, i;

if (argc < 2 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
printf("\n");
printf("Usage: %s [ -h | --help ]\n", argv[0]);
printf(" %s mountpoint [ mountpoint ... ]\n", argv[0]);
printf("\n");
printf("This program will report the percentage of inodes in use,\n");
printf("the number free inodes available for normal users,\n");
printf("the number of free inodes available for root,\n");
printf("and the total number of inodes,\n");
printf("in the filesystems referred to the supplied paths.\n");
printf("\n");
printf("Each mount is only counted once, even if multiple paths\n");
printf("to the same mount are given as parameters.\n");
printf("\n");
return EXIT_SUCCESS;
}

for (arg = 1; arg < argc; arg++) {
struct stat info;
struct statvfs vfsinfo;

if (stat(argv[arg], &info) == -1) {
fprintf(stderr, "%s: %s.\n", argv[arg], strerror(errno));
continue;
}
if (statvfs(argv[arg], &vfsinfo) == -1) {
fprintf(stderr, "%s: %s.\n", argv[arg], strerror(errno));
continue;
}

/* Check if device already seen. */
for (i = 0; i < devices; i++)
if (info.st_dev == device[i])
break;
if (i < devices)
continue;

/* Add to known devices. */
device[devices++] = info.st_dev;

/* Add to inode counters. */
total_inodes += (uint64_t)vfsinfo.f_files;
avail_inodes += (uint64_t)vfsinfo.f_favail;
free_inodes += (uint64_t)vfsinfo.f_ffree;
}

if (total_inodes < 0) {
fprintf(stderr, "No inodes!\n");
return EXIT_FAILURE;
}

/* Print result. */
printf("%.3f%% - %" PRIu64 " free (%" PRIu64 " for root) out of %" PRIu64 " inodes.\n",
100.0 - 100.0 * (double)avail_inodes / (double)total_inodes,
avail_inodes, free_inodes, total_inodes);
return EXIT_SUCCESS;
}

Compile it using e.g.

gcc -Wall -O2 inode-stats.c -o inode-stats

optionally install it using e.g.

sudo install -o root -g root -m 0755 inode-stats /usr/bin

and run it, supplying a path to any directory or file in the mounts (mounted filesystems) you are interested in. For example,

inode-stats / /usr /var /home

The program is smart enough to only count mounts once, even if you supply multiple paths to directories/files in it -- unlike GNU coreutils' or busybox stat.

You can trivially change the output report format, and easily add other statistics (like free disk space, using (uint64_t)vfsinfo.f_bavail * (uint64_t)vfsinfo.f_bsize for amount of disk space available for normal users, and (uint64_t)vfsinfo.f_blocks * (uint64_t)vfsinfo.f_frsize for total size of each filesystem).

Where are all my inodes being used?

So basically you're looking for which directories have a lot of files? Here's a first stab at it:

find . -type d -print0 | xargs -0 -n1 count_files | sort -n

where "count_files" is a shell script that does (thanks Jonathan)

echo $(ls -a "$1" | wc -l) $1

How to get number of free inodes? (`df -i` equivalent)

You can use syscall.Statfs. Its arguments are a pathname and a pointer to a Statfs_t struct. It fills in the struct with statistics for the filesystem that contains the file or directory specified by the pathname. Typically you'd use . or / or the pathname of a mount point.

Here's a Go program that takes a pathname as its argument and displays inode information.

package main

import (
"fmt"
"os"
"syscall"
)

func main() {
var statfs syscall.Statfs_t
path := os.Args[1]
if err := syscall.Statfs(path, &statfs); err != nil {
fmt.Fprintf(os.Stderr, "Cannot stat %s: %v\n", path, err)
os.Exit(1)
}
fmt.Printf("Inodes: total %d, free %d\n", statfs.Files, statfs.Ffree)
}

Number of free inodes on a partition containing a directory

This can be done using the statvfs system call. In Python (both 2 and 3), this can be accessed using os.statvfs. The call describes the filesystem containing the file/directory the path specifies.

So to get the number of free inodes, use

#import os
os.statvfs('/some/directory').f_favail

Also, it's possible that some percentage of the inodes are reserved for the root user. If the script is running as root and you want to allow it to use the reserved inodes, use f_ffree instead of f_favail.

calculate percentage inode usage using python

If you use Python 2.x, int / int results in int floored. You should convert it to float first.

>>> 1/2
0
>>> 1.0/2
0.5
>>> float(1)/2
0.5

print(float(total_inode - free_inode) / total_inode)


Related Topics



Leave a reply



Submit