Commit af30cb44 authored by Chandra Seetharaman's avatar Chandra Seetharaman Committed by Ben Myers

quota: Add a new quotactl command Q_XGETQSTATV

XFS now supports three types of quotas (user, group and project).

Current version of Q_XGETSTAT has support for only two types of quotas.
In order to support three types of quotas, the interface, specifically
struct fs_quota_stat, need to be expanded. Current version of fs_quota_stat
does not allow expansion without breaking backward compatibility.

So, a quotactl command and new fs_quota_stat structure need to be added.

This patch adds a new command Q_XGETQSTATV to quotactl() which takes
a new data structure fs_quota_statv. This new data structure provides
support for future expansion and backward compatibility.

Callers of the new quotactl command have to set the version of the data
structure being passed, and kernel will fill as much data as requested.
If the kernel does not support the user-space provided version, EINVAL
will be returned. User-space can reduce the version number and call the same
quotactl again.
Signed-off-by: default avatarChandra Seetharaman <sekharan@us.ibm.com>
Reviewed-by: default avatarJan Kara <jack@suse.cz>
Reviewed-by: default avatarRich Johnston <rjohnston@sgi.com>
Signed-off-by: default avatarBen Myers <bpm@sgi.com>

[v2: Applied rjohnston's suggestions as per Chandra's request. -bpm]
parent c2bfbc9b
...@@ -27,6 +27,7 @@ static int check_quotactl_permission(struct super_block *sb, int type, int cmd, ...@@ -27,6 +27,7 @@ static int check_quotactl_permission(struct super_block *sb, int type, int cmd,
case Q_SYNC: case Q_SYNC:
case Q_GETINFO: case Q_GETINFO:
case Q_XGETQSTAT: case Q_XGETQSTAT:
case Q_XGETQSTATV:
case Q_XQUOTASYNC: case Q_XQUOTASYNC:
break; break;
/* allow to query information for dquots we "own" */ /* allow to query information for dquots we "own" */
...@@ -217,6 +218,31 @@ static int quota_getxstate(struct super_block *sb, void __user *addr) ...@@ -217,6 +218,31 @@ static int quota_getxstate(struct super_block *sb, void __user *addr)
return ret; return ret;
} }
static int quota_getxstatev(struct super_block *sb, void __user *addr)
{
struct fs_quota_statv fqs;
int ret;
if (!sb->s_qcop->get_xstatev)
return -ENOSYS;
memset(&fqs, 0, sizeof(fqs));
if (copy_from_user(&fqs, addr, 1)) /* Just read qs_version */
return -EFAULT;
/* If this kernel doesn't support user specified version, fail */
switch (fqs.qs_version) {
case FS_QSTATV_VERSION1:
break;
default:
return -EINVAL;
}
ret = sb->s_qcop->get_xstatev(sb, &fqs);
if (!ret && copy_to_user(addr, &fqs, sizeof(fqs)))
return -EFAULT;
return ret;
}
static int quota_setxquota(struct super_block *sb, int type, qid_t id, static int quota_setxquota(struct super_block *sb, int type, qid_t id,
void __user *addr) void __user *addr)
{ {
...@@ -293,6 +319,8 @@ static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id, ...@@ -293,6 +319,8 @@ static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id,
return quota_setxstate(sb, cmd, addr); return quota_setxstate(sb, cmd, addr);
case Q_XGETQSTAT: case Q_XGETQSTAT:
return quota_getxstate(sb, addr); return quota_getxstate(sb, addr);
case Q_XGETQSTATV:
return quota_getxstatev(sb, addr);
case Q_XSETQLIM: case Q_XSETQLIM:
return quota_setxquota(sb, type, id, addr); return quota_setxquota(sb, type, id, addr);
case Q_XGETQUOTA: case Q_XGETQUOTA:
...@@ -317,6 +345,7 @@ static int quotactl_cmd_write(int cmd) ...@@ -317,6 +345,7 @@ static int quotactl_cmd_write(int cmd)
case Q_GETINFO: case Q_GETINFO:
case Q_SYNC: case Q_SYNC:
case Q_XGETQSTAT: case Q_XGETQSTAT:
case Q_XGETQSTATV:
case Q_XGETQUOTA: case Q_XGETQUOTA:
case Q_XQUOTASYNC: case Q_XQUOTASYNC:
return 0; return 0;
......
...@@ -328,6 +328,7 @@ struct quotactl_ops { ...@@ -328,6 +328,7 @@ struct quotactl_ops {
int (*set_dqblk)(struct super_block *, struct kqid, struct fs_disk_quota *); int (*set_dqblk)(struct super_block *, struct kqid, struct fs_disk_quota *);
int (*get_xstate)(struct super_block *, struct fs_quota_stat *); int (*get_xstate)(struct super_block *, struct fs_quota_stat *);
int (*set_xstate)(struct super_block *, unsigned int, int); int (*set_xstate)(struct super_block *, unsigned int, int);
int (*get_xstatev)(struct super_block *, struct fs_quota_statv *);
}; };
struct quota_format_type { struct quota_format_type {
......
...@@ -38,6 +38,7 @@ ...@@ -38,6 +38,7 @@
#define Q_XGETQSTAT XQM_CMD(5) /* get quota subsystem status */ #define Q_XGETQSTAT XQM_CMD(5) /* get quota subsystem status */
#define Q_XQUOTARM XQM_CMD(6) /* free disk space used by dquots */ #define Q_XQUOTARM XQM_CMD(6) /* free disk space used by dquots */
#define Q_XQUOTASYNC XQM_CMD(7) /* delalloc flush, updates dquots */ #define Q_XQUOTASYNC XQM_CMD(7) /* delalloc flush, updates dquots */
#define Q_XGETQSTATV XQM_CMD(8) /* newer version of get quota */
/* /*
* fs_disk_quota structure: * fs_disk_quota structure:
...@@ -163,4 +164,50 @@ typedef struct fs_quota_stat { ...@@ -163,4 +164,50 @@ typedef struct fs_quota_stat {
__u16 qs_iwarnlimit; /* limit for num warnings */ __u16 qs_iwarnlimit; /* limit for num warnings */
} fs_quota_stat_t; } fs_quota_stat_t;
/*
* fs_quota_statv is used by Q_XGETQSTATV for a given file system. It provides
* a centralized way to get meta information about the quota subsystem. eg.
* space taken up for user, group, and project quotas, number of dquots
* currently incore.
*
* This version has proper versioning support with appropriate padding for
* future expansions, and ability to expand for future without creating any
* backward compatibility issues.
*
* Q_XGETQSTATV uses the passed in value of the requested version via
* fs_quota_statv.qs_version to determine the return data layout of
* fs_quota_statv. The kernel will fill the data fields relevant to that
* version.
*
* If kernel does not support user space caller specified version, EINVAL will
* be returned. User space caller can then reduce the version number and retry
* the same command.
*/
#define FS_QSTATV_VERSION1 1 /* fs_quota_statv.qs_version */
/*
* Some basic information about 'quota files' for Q_XGETQSTATV command
*/
struct fs_qfilestatv {
__u64 qfs_ino; /* inode number */
__u64 qfs_nblks; /* number of BBs 512-byte-blks */
__u32 qfs_nextents; /* number of extents */
__u32 qfs_pad; /* pad for 8-byte alignment */
};
struct fs_quota_statv {
__s8 qs_version; /* version for future changes */
__u8 qs_pad1; /* pad for 16bit alignment */
__u16 qs_flags; /* FS_QUOTA_.* flags */
__u32 qs_incoredqs; /* number of dquots incore */
struct fs_qfilestatv qs_uquota; /* user quota information */
struct fs_qfilestatv qs_gquota; /* group quota information */
struct fs_qfilestatv qs_pquota; /* project quota information */
__s32 qs_btimelimit; /* limit for blks timer */
__s32 qs_itimelimit; /* limit for inodes timer */
__s32 qs_rtbtimelimit;/* limit for rt blks timer */
__u16 qs_bwarnlimit; /* limit for num warnings */
__u16 qs_iwarnlimit; /* limit for num warnings */
__u64 qs_pad2[8]; /* for future proofing */
};
#endif /* _LINUX_DQBLK_XFS_H */ #endif /* _LINUX_DQBLK_XFS_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment