在XFS文件系统上实现针对目录的配额限制
在Linux系统上支持对用户以及对用户组设置磁盘配额的文件系统很多,常见的Ext4文件系统对配额的支持就很好,但是如果要针对某个目录进行配额限制的话,就比较难办了。
至少在Ext4文件系统上并没有什么好的办法,有些比较hack的办法,比如使用 fuse
挂载一个目录,并在这个文件系统里实现目录级别的配额,虽然可以实现,但是问题就是 fuse
的性能要差很多。
然后调查了一下XFS,XFS文件系统支持 Project Quota
功能,通过该特性,可以支持目录级别的配额限制。
要使用Project Quota
功能,需要在挂载时指定-o prjquota
参数,并且这个参数还不能和usrquota
、grpquota
一起使用,也就是说,如果开启Project Quota
就无法使用针对用户和用户组的配额限制。
[root@test ~]# mount -o prjquota /dev/sdb1 /tmp/data0
这里把/dev/sdb1
挂载到/tmp/data0
。挂载之后,就可以使用xfs_quota
工具对该分区的quota进行操作了。
[root@test ~]# xfs_quota -x -c report /tmp/data0
Project quota on /tmp/data0 (/dev/sdb1)
Blocks
Project ID Used Soft Hard Warn/Grace
---------- --------------------------------------------------
#0 4 0 0 00 [--------]
使用-x
开启专家模式,-c report
执行report命令,后面跟上挂载点,这样可以列出所有的Project ID以及对应的配额使用情况。
如果要限制某个目录的配额,首先需要保证该目录存在,然后调用project
命令创建一个project,再调用limit
命令设置配额。
[root@test ~]# mkdir /tmp/data0/100MB # 创建对应文件夹
[root@test ~]# xfs_quota -x -c 'project -s -p /tmp/data0/100MB 1' # 为文件夹分配ProjectID 1
Setting up project 1 (path /tmp/data0/100MB)...
Processed 1 (/etc/projects and cmdline) paths for project 1 with recursion depth infinite (-1).
[root@test ~]# xfs_quota -x -c 'limit -p bhard=100m 1' /tmp/data0/ # 限制Project 1的配额为100MB
[root@test ~]# xfs_quota -x -c report /tmp/data0
Project quota on /tmp/data0 (/dev/sdb1)
Blocks
Project ID Used Soft Hard Warn/Grace
---------- --------------------------------------------------
#0 4 0 0 00 [--------]
#1 0 0 102400 00 [--------]
[root@test ~]# dd if=/dev/zero of=/tmp/data0/100MB/test bs=1M count=101
dd: error writing '/tmp/data0/100MB/test': No space left on device # 配额生效
101+0 records in
100+0 records out
104857600 bytes (105 MB, 100 MiB) copied, 1.01324 s, 103 MB/s
[root@test ~]# xfs_quota -x -c report /tmp/data0
Project quota on /tmp/data0 (/dev/sdb1)
Blocks
Project ID Used Soft Hard Warn/Grace
---------- --------------------------------------------------
#0 4 0 0 00 [--------]
#1 102400 0 102400 00 [--------]
[root@test ~]# xfs_quota -c 'quota -p 1' /tmp/data0 #查询某个project的配额使用情况
Disk quotas for Project #1 (1)
Filesystem Blocks Quota Limit Warn/Time Mounted on
/dev/loop0 102400 0 102400 00 [--------] /tmp/data0
看到已经设置好对应的配额。并能正常工作。其中需要注意的。使用 -c quota
查询某个project的配额使用情况时,只有当使用的空间超过0才会被正常显示,否则是无法通过该方式查询的。
上面的测试是在本地的机器上做测试的,所有的功能都能正常工作,但是在线上机器上做测试的时候,发现可以正常设置quota,并且quota也能正常生效,但是在调用 report
命令的时候,线上机器永远只会显示Project ID为0的
配额情况,而不会显示其他Project的配额,需要说明的是本地的系统是ArchLinx,使用4.9版本内核,线上系统使用CentOS 7,使用3.10的内核。因为内核版本不一样,不排除是内核版本导致的问题,但是也不能确定就是内核问题。
于是决定看一下xfs_quota
这个工具的代码,看一下 report
这个命令是如何实现的。xfs_quota
这个工具属于xfsprogs
这个包,所以在https://www.kernel.org/pub/linux/utils/fs/xfs/xfsprogs/xfsprogs-4.9.0.tar.xz
下载了4.9版本的源代码。
发现在 quota/report.c
文件中,report_mount
函数有这样一段代码:
...
if (flags & GETNEXTQUOTA_FLAG)
cmd = XFS_GETNEXTQUOTA;
else
cmd = XFS_GETQUOTA;
/* Fall back silently if XFS_GETNEXTQUOTA fails, warn on XFS_GETQUOTA*/
if (xfsquotactl(cmd, dev, type, id, (void *)&d) < 0) {
if (errno != ENOENT && errno != ENOSYS && errno != ESRCH &&
cmd == XFS_GETQUOTA)
perror("XFS_GETQUOTA");
return 0;
}
...
看到注释,尝试使用XFS_GETNEXTQUOTA
操作失败后,自动fall back到XFS_GETQUOTA
,会不会是这个问题?尝试一下,如果XFS_GETNEXTQUOTA
失败,直接打印错误信息。
将代码修改成:
if (xfsquotactl(cmd, dev, type, id, (void *)&d) < 0) {
printf("not support XFS_GETNEXTQUOTA\n");
if (errno != ENOENT && errno != ENOSYS && errno != ESRCH &&
cmd == XFS_GETQUOTA)
perror("XFS_GETQUOTA");
return 0;
}
编译后运行一下,果然在线上机器上打印出not support XFS_GETNEXTQUOTA
,说明CentOS 7的3.10内核不支持XFS_GETNEXTQUOTA
这个操作。
然后就去翻了一下内核代码,发现了这个提交 wire up Q_XGETNEXTQUOTA / get_nextdqblk,这个操作应该是在Linux 4.6版本引入的,所以CentOS 7的3.10内核就不支持该操作了。
不过没有这个特性,也不会影响实际的Quota功能,所以线上可以正常使用。