xfs quota usage

| 分类 Linux  | 标签 xfs 

set project quota

Enabling project quota on an XFS filesystem (restrict files in vm1 directories to only using 1 gigabyte of space).

# rm -f /etc/projects /etc/projid
# mount -o prjquota /dev/sda4 /data
# xfs_quota -x -c 'project -s -p /data/vm1 1000' /data
# xfs_quota -x -c 'limit -p bhard=1g 1000' /data

project command

project [ -cCs [ -d depth ] [ -p path ] id | name ]
      The -c, -C, and -s options allow the directory tree quota
      mechanism to be maintained.  -d allows to limit recursion
      level when processing project directories and -p allows to
      specify project paths at command line ( instead of
      /etc/projects ). All options are discussed in detail below.

setup project

  • Q1: implementation

当我们对某个目录调用xfs_quota设置project quota时,会遍历该目录下的所有文件(目录),然后对每个文件设置project id:

///xfsprogs
static int
setup_project(
	const char		*path,
	const struct stat	*stat,
	int			flag,
	struct FTW		*data)
{
...
	if ((fd = open(path, O_RDONLY|O_NOCTTY)) == -1) {
		exitcode = 1;
		fprintf(stderr, _("%s: cannot open %s: %s\n"),
			progname, path, strerror(errno));
		return 0;
	} else if (xfsctl(path, fd, XFS_IOC_FSGETXATTR, &fsx) < 0) {
		exitcode = 1;
		fprintf(stderr, _("%s: cannot get flags on %s: %s\n"),
			progname, path, strerror(errno));
		close(fd);
		return 0;
	}

	fsx.fsx_projid = prid;
	fsx.fsx_xflags |= XFS_XFLAG_PROJINHERIT;
	if (xfsctl(path, fd, XFS_IOC_FSSETXATTR, &fsx) < 0) { ///see xfs_file_ioctl
		exitcode = 1;
		fprintf(stderr, _("%s: cannot set project on %s: %s\n"),
			progname, path, strerror(errno));
	}
	close(fd);

In kernel:

xfs_file_ioctl -> xfs_ioc_fssetxattr -> xfs_ioctl_setattr

  • Q2: skipping special file
# xfs_quota -x -c 'project -s vm44' /data        
Setting up project vm44 (path /data/docker/overlay/a698018e8a59c5c440e72a11958eb6aebdbd1f1872e657b8da91a799e8f2ea5a/)...
xfs_quota: skipping special file /data/docker/overlay/a698018e8a59c5c440e72a11958eb6aebdbd1f1872e657b8da91a799e8f2ea5a/upper/etc/mtab

XFS quota在setup时,会略过一些特殊文件,比如符号链接、块设备、字符设备、FIFO、socket:

//xfsprogs
static int
setup_project(
	const char		*path,
	const struct stat	*stat,
	int			flag,
	struct FTW		*data)
{
...
	if (EXCLUDED_FILE_TYPES(stat->st_mode)) {
		fprintf(stderr, _("%s: skipping special file %s\n"), progname, path);
		return 0;
	}
  • Q3: Don’t cross mount points

xfs_quota不会跨文件系统设置quota:

///xfsprogs
static void
project_operations(
	char		*project,
	char		*dir,
	int		type)
{
	switch (type) {
	case CHECK_PROJECT:
		printf(_("Checking project %s (path %s)...\n"), project, dir);
		nftw(dir, check_project, 100, FTW_PHYS|FTW_MOUNT);
		break;
	case SETUP_PROJECT:
		printf(_("Setting up project %s (path %s)...\n"), project, dir);
		nftw(dir, setup_project, 100, FTW_PHYS|FTW_MOUNT);
		break;
	case CLEAR_PROJECT:
		printf(_("Clearing project %s (path %s)...\n"), project, dir);
		nftw(dir, clear_project, 100, FTW_PHYS|FTW_MOUNT);
		break;
	}
}

FTW_MOUNT and FTW_PHYS:

       FTW_MOUNT
              If set, stay within the same filesystem (i.e., do not cross
              mount points).

       FTW_PHYS
              If set, do not follow symbolic links.  (This is what you
              want.)  If not set, symbolic links are followed, but no file
              is reported twice.

limit command

limit [ -g | -p | -u ] bsoft=N | bhard=N | isoft=N | ihard=N |
      rtbsoft=N | rtbhard=N -d | id | name
      Set quota block limits (bhard/bsoft), inode count limits
      (ihard/isoft) and/or realtime block limits (rtbhard/rtbsoft).
      The -d option (defaults) can be used to set the default value
      that will be used, otherwise a specific user/group/project
      name or numeric identifier must be specified.
  • implementation
//xfsprogs
static void
set_limits(
	__uint32_t	id,
	uint		type,
	uint		mask,
	char		*dev,
	__uint64_t	*bsoft,
	__uint64_t	*bhard,
	__uint64_t	*isoft,
	__uint64_t	*ihard, 
	__uint64_t	*rtbsoft,
	__uint64_t	*rtbhard)
{
	fs_disk_quota_t	d;

	memset(&d, 0, sizeof(d));
	d.d_version = FS_DQUOT_VERSION;
	d.d_id = id;
	d.d_flags = type;
	d.d_fieldmask = mask;
	d.d_blk_hardlimit = *bhard;
	d.d_blk_softlimit = *bsoft;
	d.d_ino_hardlimit = *ihard;
	d.d_ino_softlimit = *isoft;
	d.d_rtb_hardlimit = *rtbhard;
	d.d_rtb_softlimit = *rtbsoft;

	if (xfsquotactl(XFS_SETQLIM, dev, type, id, (void *)&d) < 0) {
		exitcode = 1;
		fprintf(stderr, _("%s: cannot set limits: %s\n"),
				progname, strerror(errno));
	}
}

In kernel:

quotactl -> do_quotactl -> xfs_fs_set_xquota

/* Copy parameters and call proper function */
static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id,
		       void __user *addr)
{
...
		case Q_XSETQLIM: {
			struct fs_disk_quota fdq;

			if (copy_from_user(&fdq, addr, sizeof(fdq)))
				return -EFAULT;
		       return sb->s_qcop->set_xquota(sb, type, id, &fdq);///xfs_fs_set_xquota
		}

Reference


上一篇     下一篇