Linux常用命令分析-df命令
df命令用于显示硬盘空间及使用情况,由系统shell调用,调用关系为:
df_main -> fopen(“/proc/mounts“, “r”) -> df -> statfs -> __statfs64
实现可归结:从/proc/mounts设备节点获取mount分区信息,然后调用statfs得到对应分区具体使用情况。
yuziming@ubuntu:~$ cat /proc/mounts
sysfs /sys sysfs rw,nosuid,nodev,noexec,relatime 0 0
proc /proc proc rw,nosuid,nodev,noexec,relatime 0 0
udev /dev devtmpfs rw,relatime,size=165067044k,nr_inodes=41266761,mode=755 0 0
devpts /dev/pts devpts rw,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=000 0 0
tmpfs /run tmpfs rw,nosuid,noexec,relatime,size=33015724k,mode=755 0 0
/dev/dm-0 / ext4 rw,relatime,errors=remount-ro,data=ordered 0 0
none /sys/fs/cgroup tmpfs rw,relatime,size=4k,mode=755 0 0
none /sys/fs/fuse/connections fusectl rw,relatime 0 0
none /sys/kernel/debug debugfs rw,relatime 0 0
none /sys/kernel/security securityfs rw,relatime 0 0
none /run/lock tmpfs rw,nosuid,nodev,noexec,relatime,size=5120k 0 0
none /run/shm tmpfs rw,nosuid,nodev,relatime 0 0
none /run/user tmpfs rw,nosuid,nodev,noexec,relatime,size=102400k,mode=755 0 0
none /sys/fs/pstore pstore rw,relatime 0 0
/dev/sda1 /boot ext2 rw,relatime,block_validity,barrier,user_xattr,acl 0 0
/dev/mapper/vg-home /home ext4 rw,relatime,data=ordered 0 0
binfmt_misc /proc/sys/fs/binfmt_misc binfmt_misc rw,nosuid,nodev,noexec,relatime 0 0
systemd /sys/fs/cgroup/systemd cgroup rw,nosuid,nodev,noexec,relatime,name=systemd 0 0
yuziming@ubuntu:~$ df
Filesystem 1K-blocks Used Available Use% Mounted on
udev 165067044 4 165067040 1% /dev
tmpfs 33015724 11644 33004080 1% /run
/dev/dm-0 961105240 30495884 881764968 4% /
none 4 0 4 0% /sys/fs/cgroup
none 5120 0 5120 0% /run/lock
none 165078604 0 165078604 0% /run/shm
none 102400 0 102400 0% /run/user
/dev/sda1 188403 40130 138545 23% /boot
/dev/mapper/vg-home 20396685124 17693446316 1679307212 92% /home
/proc/mounts设备节点工作原理不在此讨论,我们重点分析下statfs的实现。
1、statfs函数
statfs由脚本生成,其定义在/bionic/libc/arch-arm/syscalls/__statfs64.S中,文件内容:
/* autogenerated by gensyscalls.py */
#include<sys/linux-syscalls.h>
.text
.type __statfs64, #functions
.globl __statfs64
.fnstart
__statfs64:
.save {r4,r7}
stmfd sp!,{r4,r7}
ldr r7, =__NR_statfs64
swi #0
ldmfs sp!,{r4,r7}
movs r0,r0
bxpl lr
b __set_syscall_errno
.fnend
__NR_statfs64是执行内核中的系统调用:
/kernel/fs/statfs.c
SYSCALL_DEFINE3(statfs64, const char __user *, pathname, size_t, sz, struct statfs64 __user *, buf)
{
struct path path;
long error;
if (sz != sizeof(*buf))
return -EINVAL;
error = user_path(pathname, &path);
if (!error) {
struct statfs64 tmp;
error = vfs_statfs64(path.dentry, &tmp);
if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
error = -EFAULT;
path_put(&path);
}
return error;
}
接下来,调用文件系统的接口,获取分区信息(以yaffs为例):
vfs_statfs64 -> … -> “dentry->d_sb->s_op->statfs(dentry, buf)” -> yaffs_statfs
static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf)
{
yaffs_Device *dev = yaffs_SuperToDevice(sb);
T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_statfs\n"));
yaffs_GrossLock(dev);
buf->f_type = YAFFS_MAGIC;
buf->f_bsize = sb->s_blocksize;
buf->f_namelen = 255;
if (sb->s_blocksize > dev->nDataBytePerChunk) {
buf->f_blocks = (dev->endBlock - dev->startBlock + 1) * dev->nChunksPerBlock / (sb->s_blocksize / dev->nDataytesPerChunk);
buf->f_bfree = yaffs_GetNumberOfFreeChunks(dev)/(sb->s_blocksize / dev->nDataBytesPerChunk);
} else {
buf->f_blocks = (dev->endBlock - dev->startBlock + 1) * dev->nChunksPerBlock * (dev->nDataBytesPerChunk / sb->s_blocksize);
buf->f_bfree = yaffs_GetNumberOfFreeChunks(dev) * (dev->nDataBytesPerChunk / sb->s_blocksize);
}
buf->f_files = 0;
buf->f_ffree = 0;
buf->f_bavail = buf->f_bfree;
yaffs_GrossUnlock(dev);
return 0;
}
至此硬盘分区使用情况就获取完成了,至于文件系统管理设备的方法,请自行阅读Linux文件系统相关知识,就不在此赘述了。