quota: add new quotactl Q_XGETQUOTA2
Subsystems (3)
cover quota: add new quotactl Q_XGETQUOTA2
This adds a new quotactl, Q_XGETQUOTA2.
Q_XGETQUOTA2 is exactly like Q_XGETQUOTA, except that it will return quota information for the id equal to or greater than the id requested. In other words, if the specified id has no quota, the command will return quota information for the next higher id which does have a quota set. If no higher id has an active quota, -ESRCH is returned.
So if you ask for id X, you can get back quota for id X, id X+N, or -ESRCH if no higher id has a quota.
This allows filesystems to do efficient iteration in kernelspace, much like extN filesystems do in userspace when asked to report all active quotas.
Today, filesystems such as XFS require getpwent()-style iterations, and for systems which have i.e. LDAP backends, this can be very slow, or even impossible, if iteration is not allowed in the configuration.
I have patches to xfsprogs to allow xfs_quota to use this interface, but I haven't looked at generic quota tools yet TBH. I'll send the xfsprogs patches to the xfs list shortly.
Using an id as input fits very nicely with existing interfaces; however, I could imagine that making it a more generic "cookie" interface might be more extensible; is there any filesystem which wouldn't be collecting all active IDs in a linear fashion, and would rather have an arbitrary cookie passed back & forth? (I hope not) :)
Thanks,
-Eric
PATCH 1/4 quota: add new quotactl Q_XGETQUOTA2
Q_XGETQUOTA2 is exactly like Q_XGETQUOTA, except that it will return quota information for the id equal to or greater than the id requested. In other words, if the specified id has no quota, the command will return quota information for the next higher id which does have a quota set. If no higher id has an active quota, -ESRCH is returned.
This allows filesystems to do efficient iteration in kernelspace, much like extN filesystems do in userspace when asked to report all active quotas.
Today, filesystems such as XFS require getpwent-style iterations, and for systems which have i.e. LDAP backends, this can be very slow, or even impossible, if iteration is not allowed in the configuration.
--- fs/quota/quota.c | 30 ++++++++++++++++++++++++++++++ include/linux/quota.h | 2 ++ include/uapi/linux/dqblk_xfs.h | 1 + 3 files changed, 33 insertions(+), 0 deletions(-)
fs/quota/quota.c +30 -0
@@ -33,6 +33,7 @@ static int check_quotactl_permission(struct super_block *sb, int type, int cmd,/* allow to query information for dquots we "own" */ case Q_GETQUOTA :case Q_XGETQUOTA : +case Q_XGETQUOTA2 :if ((type ==USRQUOTA &&uid_eq (current_euid (),make_kuid (current_user_ns (), id))) || (type ==GRPQUOTA &&in_egroup_p (make_kgid (current_user_ns (), id))))break ;
@@ -625,6 +626,32 @@ static int quota_getxquota(struct super_block *sb, int type, qid_t id,return ret; } +/* +* Return quota for next active quota >= this id, if any exists, +* otherwise return -ESRCH. +*/ +static int quota_getxquota2 (struct super_block *sb,int type,qid_t id, +void __user *addr) +{ +struct fs_disk_quota fdq; +struct qc_dqblk qdq; +struct kqid qid; +int ret; + +if (!sb->s_qcop->get_dqblk2) +return -ENOSYS ; + qid =make_kqid (current_user_ns (), type, id); +if (!qid_valid (qid)) +return -EINVAL ; + ret = sb->s_qcop->get_dqblk2 (sb, qid, &id, &qdq); +if (ret) +return ret; +copy_to_xfs_dqblk (&fdq, &qdq, type, id); +if (copy_to_user (addr, &fdq,sizeof (fdq))) +return -EFAULT ; +return ret; +} +static int quota_rmxquota (struct super_block *sb,void __user *addr) {__u32 flags;
@@ -690,6 +717,8 @@ static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id,return quota_setxquota (sb, type, id, addr);case Q_XGETQUOTA :return quota_getxquota (sb, type, id, addr); +case Q_XGETQUOTA2 : +return quota_getxquota2 (sb, type, id, addr);case Q_XQUOTASYNC :if (sb->s_flags &MS_RDONLY )return -EROFS ;
@@ -712,6 +741,7 @@ static int quotactl_cmd_write(int cmd)case Q_XGETQSTAT :case Q_XGETQSTATV :case Q_XGETQUOTA : +case Q_XGETQUOTA2 :case Q_XQUOTASYNC :return 0 ; }
include/linux/quota.h +2 -0
@@ -425,6 +425,8 @@ struct quotactl_ops {int (*quota_sync)(struct super_block *,int );int (*set_info)(struct super_block *,int ,struct qc_info *);int (*get_dqblk)(struct super_block *,struct kqid ,struct qc_dqblk *); +int (*get_dqblk2)(struct super_block *,struct kqid ,qid_t *, +struct qc_dqblk *);int (*set_dqblk)(struct super_block *,struct kqid ,struct qc_dqblk *);int (*get_state)(struct super_block *,struct qc_state *);int (*rm_xquota)(struct super_block *,unsigned int );
include/uapi/linux/dqblk_xfs.h +1 -0
@@ -39,6 +39,7 @@#define Q_XQUOTARM XQM_CMD(6)/* free disk space used by dquots */ #define Q_XQUOTASYNC XQM_CMD(7)/* delalloc flush, updates dquots */ #define Q_XGETQSTATV XQM_CMD(8)/* newer version of get quota */ +#define Q_XGETQUOTA2 XQM_CMD(9)/* get disk limits and usage >= ID */ /* * fs_disk_quota structure:
Signature · 1 line
1.7.1
PATCH 2/4 xfs: get quota inode from mp & flags rather than dqp
In reply to Eric SandeenAllow us to get the appropriate quota inode from any mp & quota flags, not necessarily associated with a particular dqp. Needed for when we are searching for the next active ID with quotas and we want to examine the quota inode.
--- fs/xfs/xfs_dquot.c | 3 ++- fs/xfs/xfs_qm.h | 10 +++++----- 2 files changed, 7 insertions(+), 6 deletions(-)
fs/xfs/xfs_dquot.c +2 -1
@@ -464,12 +464,13 @@ xfs_qm_dqtobp(struct xfs_bmbt_irec map;int nmaps =1 , error;struct xfs_buf *bp; -struct xfs_inode *quotip =xfs_dq_to_quota_inode (dqp); +struct xfs_inode *quotip;struct xfs_mount *mp = dqp->q_mount;xfs_dqid_t id =be32_to_cpu (dqp->q_core.d_id);struct xfs_trans *tp = (tpp ? *tpp :NULL );uint lock_mode; + quotip =xfs_quota_inode (dqp->q_mount, dqp->dq_flags); dqp->q_fileoffset = (xfs_fileoff_t )id / mp->m_quotainfo->qi_dqperchunk; lock_mode =xfs_ilock_data_map_shared (quotip);
fs/xfs/xfs_qm.h +5 -5
@@ -104,15 +104,15 @@ xfs_dquot_tree( }static inline struct xfs_inode * -xfs_dq_to_quota_inode (struct xfs_dquot *dqp) +xfs_quota_inode (xfs_mount_t *mp,uint dq_flags) { -switch (dqp->dq_flags &XFS_DQ_ALLTYPES ) { +switch (dq_flags &XFS_DQ_ALLTYPES ) {case XFS_DQ_USER : -return dqp->q_mount->m_quotainfo->qi_uquotaip; +return mp->m_quotainfo->qi_uquotaip;case XFS_DQ_GROUP : -return dqp->q_mount->m_quotainfo->qi_gquotaip; +return mp->m_quotainfo->qi_gquotaip;case XFS_DQ_PROJ : -return dqp->q_mount->m_quotainfo->qi_pquotaip; +return mp->m_quotainfo->qi_pquotaip;default :ASSERT (0 ); }
Signature · 1 line
1.7.1
PATCH 3/4 xfs: Factor xfs_seek_hole_data into helper
In reply to Eric SandeenFactor xfs_seek_hole_data into an unlocked helper which takes an xfs inode rather than a file for internal use.
Also allow specification of "end" - the vfs lseek interface is defined such that any offset past eof/i_size shall return -ENXIO, but we will use this for quota code which does not maintain i_size, and we want to be able to SEEK_DATA past i_size as well. So the lseek path can send in i_size, and the quota code can determine its own ending offset.
---fs/xfs/xfs_file.c | 82 ++++++++++++++++++++++++++++++++++++---------------- fs/xfs/xfs_inode.h | 2 +
2 files changed, 59 insertions(+), 25 deletions(-)
fs/xfs/xfs_file.c +0 -0
@@ -1337,31 +1337,31 @@ out:
return found;
}
-STATIC loff_t
-xfs_seek_hole_data(
- struct file *file,
+/*
+ * caller must lock inode with xfs_ilock_data_map_shared,
+ * can we craft an appropriate ASSERT?
+ *
+ * end is because the VFS-level lseek interface is defined such that any
+ * offset past i_size shall return -ENXIO, but we use this for quota code
+ * which does not maintain i_size, and we want to SEEK_DATA past i_size.
+ */
+loff_t
+__xfs_seek_hole_data(
+ struct inode *inode,loff_t start,
+ loff_t end,
int whence)
{
- struct inode *inode = file->f_mapping->host;
struct xfs_inode *ip = XFS_I(inode);
struct xfs_mount *mp = ip->i_mount;loff_t uninitialized_var(offset);
- xfs_fsize_t isize;xfs_fileoff_t fsbno;
- xfs_filblks_t end;
- uint lock;
+ xfs_filblks_t lastbno;
int error;
- if (XFS_FORCED_SHUTDOWN(mp))
- return -EIO;
-
- lock = xfs_ilock_data_map_shared(ip);
-
- isize = i_size_read(inode);
- if (start >= isize) {
+ if (start >= end) {
error = -ENXIO;
- goto out_unlock;
+ goto out_error;
}
/*
@@ -1369,22 +1369,22 @@ xfs_seek_hole_data(
* by fsbno to the end block of the file.
*/
fsbno = XFS_B_TO_FSBT(mp, start);
- end = XFS_B_TO_FSB(mp, isize);
+ lastbno = XFS_B_TO_FSB(mp, end);
for (;;) {
struct xfs_bmbt_irec map[2];
int nmap = 2;
unsigned int i;
- error = xfs_bmapi_read(ip, fsbno, end - fsbno, map, &nmap,
+ error = xfs_bmapi_read(ip, fsbno, lastbno - fsbno, map, &nmap, XFS_BMAPI_ENTIRE);
if (error)
- goto out_unlock;
+ goto out_error;
/* No extents at given offset, must be beyond EOF */ if (nmap == 0) {
error = -ENXIO;
- goto out_unlock;
+ goto out_error;
}
for (i = 0; i < nmap; i++) {
@@ -1426,7 +1426,7 @@ xfs_seek_hole_data(
* hole at the end of any file).
*/
if (whence == SEEK_HOLE) {
- offset = isize;
+ offset = end;
break;
}
/*
@@ -1434,7 +1434,7 @@ xfs_seek_hole_data(
*/ASSERT(whence == SEEK_DATA);
error = -ENXIO;
- goto out_unlock;
+ goto out_error;
}
ASSERT(i > 1);
@@ -1445,14 +1445,14 @@ xfs_seek_hole_data(
*/
fsbno = map[i - 1].br_startoff + map[i - 1].br_blockcount; start = XFS_FSB_TO_B(mp, fsbno);
- if (start >= isize) {
+ if (start >= end) {
if (whence == SEEK_HOLE) {
- offset = isize;
+ offset = end;
break;
}ASSERT(whence == SEEK_DATA);
error = -ENXIO;
- goto out_unlock;
+ goto out_error;
}
}
@@ -1464,7 +1464,39 @@ out:
* situation in particular.
*/
if (whence == SEEK_HOLE)
- offset = min_t(loff_t, offset, isize);
+ offset = min_t(loff_t, offset, end);
+
+ return offset;
+
+out_error:
+ return error;
+}
+
+STATIC loff_t
+xfs_seek_hole_data(
+ struct file *file,
+ loff_t start,
+ int whence)
+{
+ struct inode *inode = file->f_mapping->host;
+ struct xfs_inode *ip = XFS_I(inode);
+ struct xfs_mount *mp = ip->i_mount;
+ uint lock;
+ loff_t offset, end;
+ int error = 0;
+
+ if (XFS_FORCED_SHUTDOWN(mp))
+ return -EIO;
+
+ lock = xfs_ilock_data_map_shared(ip);
+
+ end = i_size_read(inode);
+ offset = __xfs_seek_hole_data(inode, start, end, whence);
+ if (offset < 0) {
+ error = offset;
+ goto out_unlock;
+ }
+
offset = vfs_setpos(file, offset, inode->i_sb->s_maxbytes);
out_unlock:
fs/xfs/xfs_inode.h +0 -0
@@ -437,6 +437,8 @@ int xfs_update_prealloc_flags(struct xfs_inode *ip,
int xfs_zero_eof(struct xfs_inode *ip, xfs_off_t offset, xfs_fsize_t isize, bool *did_zeroing);
int xfs_iozero(struct xfs_inode *ip, loff_t pos, size_t count); +loff_t __xfs_seek_hole_data(struct inode *inode, loff_t start,
+ loff_t eof, int whence);
/* from xfs_iops.c */
Signature · 1 line
1.7.1
PATCH v2 3/4 xfs: Factor xfs_seek_hole_data into helper
Factor xfs_seek_hole_data into an unlocked helper which takes an xfs inode rather than a file for internal use.
Also allow specification of "end" - the vfs lseek interface is defined such that any offset past eof/i_size shall return -ENXIO, but we will use this for quota code which does not maintain i_size, and we want to be able to SEEK_DATA past i_size as well. So the lseek path can send in i_size, and the quota code can determine its own ending offset.
---
(Ugh, no idea what happened to that formatting!)
fs/xfs/xfs_file.c | 82 ++++++++++++++++++++++++++++++++++++---------------- fs/xfs/xfs_inode.h | 2 + 2 files changed, 59 insertions(+), 25 deletions(-)
fs/xfs/xfs_file.c +57 -25
@@ -1337,31 +1337,31 @@ out:return found; } -STATIC loff_t -xfs_seek_hole_data ( -struct file *file, +/* +* caller must lock inode with xfs_ilock_data_map_shared, +* can we craft an appropriate ASSERT? +* +* end is because the VFS-level lseek interface is defined such that any +* offset past i_size shall return -ENXIO, but we use this for quota code +* which does not maintain i_size, and we want to SEEK_DATA past i_size. +*/ +loff_t +__xfs_seek_hole_data ( +struct inode *inode,loff_t start, +loff_t end,int whence) { -struct inode *inode = file->f_mapping->host;struct xfs_inode *ip =XFS_I (inode);struct xfs_mount *mp = ip->i_mount;loff_t uninitialized_var (offset ); -xfs_fsize_t isize;xfs_fileoff_t fsbno; -xfs_filblks_t end; -uint lock; +xfs_filblks_t lastbno;int error; -if (XFS_FORCED_SHUTDOWN (mp)) -return -EIO ; - - lock =xfs_ilock_data_map_shared (ip); - - isize =i_size_read (inode); -if (start >= isize) { +if (start >= end) { error = -ENXIO ; - goto out_unlock; + goto out_error; }/*
@@ -1369,22 +1369,22 @@ xfs_seek_hole_data(* by fsbno to the end block of the file. */ fsbno =XFS_B_TO_FSBT (mp, start); - end =XFS_B_TO_FSB (mp, isize); + lastbno =XFS_B_TO_FSB (mp, end);for (;;) {struct xfs_bmbt_irec map[2 ];int nmap =2 ;unsigned int i; - error =xfs_bmapi_read (ip, fsbno, end - fsbno, map, &nmap, + error =xfs_bmapi_read (ip, fsbno, lastbno - fsbno, map, &nmap,XFS_BMAPI_ENTIRE );if (error) - goto out_unlock; + goto out_error;/* No extents at given offset, must be beyond EOF */ if (nmap ==0 ) { error = -ENXIO ; - goto out_unlock; + goto out_error; }for (i =0 ; i < nmap; i++) {
@@ -1426,7 +1426,7 @@ xfs_seek_hole_data(* hole at the end of any file). */ if (whence ==SEEK_HOLE ) { - offset = isize; + offset = end;break ; }/*
@@ -1434,7 +1434,7 @@ xfs_seek_hole_data(*/ ASSERT (whence ==SEEK_DATA ); error = -ENXIO ; - goto out_unlock; + goto out_error; }ASSERT (i >1 );
@@ -1445,14 +1445,14 @@ xfs_seek_hole_data(*/ fsbno = map[i -1 ].br_startoff + map[i -1 ].br_blockcount; start =XFS_FSB_TO_B (mp, fsbno); -if (start >= isize) { +if (start >= end) {if (whence ==SEEK_HOLE ) { - offset = isize; + offset = end;break ; }ASSERT (whence ==SEEK_DATA ); error = -ENXIO ; - goto out_unlock; + goto out_error; } }
@@ -1464,7 +1464,39 @@ out:* situation in particular. */ if (whence ==SEEK_HOLE ) - offset =min_t (loff_t, offset, isize); + offset =min_t (loff_t, offset, end); + +return offset; + +out_error: +return error; +} + +STATIC loff_t +xfs_seek_hole_data ( +struct file *file, +loff_t start, +int whence) +{ +struct inode *inode = file->f_mapping->host; +struct xfs_inode *ip =XFS_I (inode); +struct xfs_mount *mp = ip->i_mount; +uint lock; +loff_t offset, end; +int error =0 ; + +if (XFS_FORCED_SHUTDOWN (mp)) +return -EIO ; + + lock =xfs_ilock_data_map_shared (ip); + + end =i_size_read (inode); + offset =__xfs_seek_hole_data (inode, start, end, whence); +if (offset <0 ) { + error = offset; + goto out_unlock; + } + offset =vfs_setpos (file, offset, inode->i_sb->s_maxbytes); out_unlock:
fs/xfs/xfs_inode.h +2 -0
@@ -437,6 +437,8 @@ int xfs_update_prealloc_flags(struct xfs_inode *ip,int xfs_zero_eof (struct xfs_inode *ip,xfs_off_t offset,xfs_fsize_t isize,bool *did_zeroing);int xfs_iozero (struct xfs_inode *ip,loff_t pos,size_t count); +loff_t __xfs_seek_hole_data (struct inode *inode,loff_t start, +loff_t eof,int whence);/* from xfs_iops.c */
Signature · 7 lines
1.7.1 _______________________________________________ xfs mailing list [email protected] http://oss.sgi.com/mailman/listinfo/xfs
Jan Kara
reviewerRe: [PATCH 3/4] xfs: Factor xfs_seek_hole_data into helper
In reply to Eric SandeenQuoted 9 lines · Eric Sandeen
Factor
xfs_seek_hole_datainto an unlocked helper which takes an xfs inode rather than a file for internal use.Also allow specification of "end" - the vfs lseek interface is defined such that any offset past eof/i_size shall return
-ENXIO, but we will use this for quota code which does not maintaini_size, and we want to be able toSEEK_DATApasti_sizeas well. So the lseek path can send ini_size, and the quota code can determine its own ending offset.
This patch looks whitespace damaged making it difficult to read...
Honza
Quoted 178 lines
Signed-off-by Eric Sandeen <[email protected]>---
fs/xfs/xfs_file.c| 82 ++++++++++++++++++++++++++++++++++++----------------fs/xfs/xfs_inode.h| 2 +2 files changed, 59 insertions(+), 25 deletions(-)fs/xfs/xfs_file.c +57
-25@@ -1337,31 +1337,31 @@ out:return found; } -STATIC loff_t -xfs_seek_hole_data ( -struct file *file, +/* +* caller must lock inode with xfs_ilock_data_map_shared, +* can we craft an appropriate ASSERT? +* +* end is because the VFS-level lseek interface is defined such that any +* offset past i_size shall return -ENXIO, but we use this for quota code +* which does not maintain i_size, and we want to SEEK_DATA past i_size. +*/ +loff_t +__xfs_seek_hole_data ( +struct inode *inode,loff_t start, +loff_t end,int whence) { -struct inode *inode = file->f_mapping->host;struct xfs_inode *ip =XFS_I (inode);struct xfs_mount *mp = ip->i_mount;loff_t uninitialized_var (offset ); -xfs_fsize_t isize;xfs_fileoff_t fsbno; -xfs_filblks_t end; -uint lock; +xfs_filblks_t lastbno;int error; -if (XFS_FORCED_SHUTDOWN (mp)) -return -EIO ; - - lock =xfs_ilock_data_map_shared (ip); - - isize =i_size_read (inode); -if (start >= isize) { +if (start >= end) { error = -ENXIO ; - goto out_unlock; + goto out_error; }/* @@ -1369,22 +1369,22 @@ xfs_seek_hole_data(* by fsbno to the end block of the file. */ fsbno =XFS_B_TO_FSBT (mp, start); - end =XFS_B_TO_FSB (mp, isize); + lastbno =XFS_B_TO_FSB (mp, end);for (;;) {struct xfs_bmbt_irec map[2 ];int nmap =2 ;unsigned int i; - error =xfs_bmapi_read (ip, fsbno, end - fsbno, map, &nmap, + error =xfs_bmapi_read (ip, fsbno, lastbno - fsbno, map, &nmap,XFS_BMAPI_ENTIRE );if (error) - goto out_unlock; + goto out_error;/* No extents at given offset, must be beyond EOF */ if (nmap ==0 ) { error = -ENXIO ; - goto out_unlock; + goto out_error; }for (i =0 ; i < nmap; i++) {@@ -1426,7 +1426,7 @@ xfs_seek_hole_data(* hole at the end of any file). */ if (whence ==SEEK_HOLE ) { - offset = isize; + offset = end;break ; }/* @@ -1434,7 +1434,7 @@ xfs_seek_hole_data(*/ ASSERT (whence ==SEEK_DATA ); error = -ENXIO ; - goto out_unlock; + goto out_error; }ASSERT (i >1 );@@ -1445,14 +1445,14 @@ xfs_seek_hole_data(*/ fsbno = map[i -1 ].br_startoff + map[i -1 ].br_blockcount; start =XFS_FSB_TO_B (mp, fsbno); -if (start >= isize) { +if (start >= end) {if (whence ==SEEK_HOLE ) { - offset = isize; + offset = end;break ; }ASSERT (whence ==SEEK_DATA ); error = -ENXIO ; - goto out_unlock; + goto out_error; } }@@ -1464,7 +1464,39 @@ out:* situation in particular. */ if (whence ==SEEK_HOLE ) - offset =min_t (loff_t, offset, isize); + offset =min_t (loff_t, offset, end); + +return offset; + +out_error: +return error; +} + +STATIC loff_t +xfs_seek_hole_data ( +struct file *file, +loff_t start, +int whence) +{ +struct inode *inode = file->f_mapping->host; +struct xfs_inode *ip =XFS_I (inode); +struct xfs_mount *mp = ip->i_mount; +uint lock; +loff_t offset, end; +int error =0 ; + +if (XFS_FORCED_SHUTDOWN (mp)) +return -EIO ; + + lock =xfs_ilock_data_map_shared (ip); + + end =i_size_read (inode); + offset =__xfs_seek_hole_data (inode, start, end, whence); +if (offset <0 ) { + error = offset; + goto out_unlock; + } + offset =vfs_setpos (file, offset, inode->i_sb->s_maxbytes);
out_unlock:fs/xfs/xfs_inode.h +2
-0@@ -437,6 +437,8 @@ int xfs_update_prealloc_flags(struct xfs_inode *ip,int xfs_zero_eof (struct xfs_inode *ip,xfs_off_t offset,xfs_fsize_t isize,bool *did_zeroing);int xfs_iozero (struct xfs_inode *ip,loff_t pos,size_t count); +loff_t __xfs_seek_hole_data (struct inode *inode,loff_t start, +loff_t eof,int whence);/* from xfs_iops.c */ Signature · 1 line
1.7.1
Signature · 7 lines
Jan Kara <[email protected]> SUSE Labs, CR _______________________________________________ xfs mailing list [email protected] http://oss.sgi.com/mailman/listinfo/xfs
PATCH v3 3/4 xfs: Factor xfs_seek_hole_data into helper
In reply to Eric SandeenFactor xfs_seek_hole_data into an unlocked helper which takes an xfs inode rather than a file for internal use.
Also allow specification of "end" - the vfs lseek interface is defined such that any offset past eof/i_size shall return -ENXIO, but we will use this for quota code which does not maintain i_size, and we want to be able to SEEK_DATA past i_size as well. So the lseek path can send in i_size, and the quota code can determine its own ending offset.
---
(Ugh, no idea what happened to that formatting!)
(V3 same as V2 but actually hitting both lists - email is hard!)
fs/xfs/xfs_file.c | 82 ++++++++++++++++++++++++++++++++++++---------------- fs/xfs/xfs_inode.h | 2 + 2 files changed, 59 insertions(+), 25 deletions(-)
fs/xfs/xfs_file.c +57 -25
@@ -1337,31 +1337,31 @@ out:return found; } -STATIC loff_t -xfs_seek_hole_data ( -struct file *file, +/* +* caller must lock inode with xfs_ilock_data_map_shared, +* can we craft an appropriate ASSERT? +* +* end is because the VFS-level lseek interface is defined such that any +* offset past i_size shall return -ENXIO, but we use this for quota code +* which does not maintain i_size, and we want to SEEK_DATA past i_size. +*/ +loff_t +__xfs_seek_hole_data ( +struct inode *inode,loff_t start, +loff_t end,int whence) { -struct inode *inode = file->f_mapping->host;struct xfs_inode *ip =XFS_I (inode);struct xfs_mount *mp = ip->i_mount;loff_t uninitialized_var (offset ); -xfs_fsize_t isize;xfs_fileoff_t fsbno; -xfs_filblks_t end; -uint lock; +xfs_filblks_t lastbno;int error; -if (XFS_FORCED_SHUTDOWN (mp)) -return -EIO ; - - lock =xfs_ilock_data_map_shared (ip); - - isize =i_size_read (inode); -if (start >= isize) { +if (start >= end) { error = -ENXIO ; - goto out_unlock; + goto out_error; }/*
@@ -1369,22 +1369,22 @@ xfs_seek_hole_data(* by fsbno to the end block of the file. */ fsbno =XFS_B_TO_FSBT (mp, start); - end =XFS_B_TO_FSB (mp, isize); + lastbno =XFS_B_TO_FSB (mp, end);for (;;) {struct xfs_bmbt_irec map[2 ];int nmap =2 ;unsigned int i; - error =xfs_bmapi_read (ip, fsbno, end - fsbno, map, &nmap, + error =xfs_bmapi_read (ip, fsbno, lastbno - fsbno, map, &nmap,XFS_BMAPI_ENTIRE );if (error) - goto out_unlock; + goto out_error;/* No extents at given offset, must be beyond EOF */ if (nmap ==0 ) { error = -ENXIO ; - goto out_unlock; + goto out_error; }for (i =0 ; i < nmap; i++) {
@@ -1426,7 +1426,7 @@ xfs_seek_hole_data(* hole at the end of any file). */ if (whence ==SEEK_HOLE ) { - offset = isize; + offset = end;break ; }/*
@@ -1434,7 +1434,7 @@ xfs_seek_hole_data(*/ ASSERT (whence ==SEEK_DATA ); error = -ENXIO ; - goto out_unlock; + goto out_error; }ASSERT (i >1 );
@@ -1445,14 +1445,14 @@ xfs_seek_hole_data(*/ fsbno = map[i -1 ].br_startoff + map[i -1 ].br_blockcount; start =XFS_FSB_TO_B (mp, fsbno); -if (start >= isize) { +if (start >= end) {if (whence ==SEEK_HOLE ) { - offset = isize; + offset = end;break ; }ASSERT (whence ==SEEK_DATA ); error = -ENXIO ; - goto out_unlock; + goto out_error; } }
@@ -1464,7 +1464,39 @@ out:* situation in particular. */ if (whence ==SEEK_HOLE ) - offset =min_t (loff_t, offset, isize); + offset =min_t (loff_t, offset, end); + +return offset; + +out_error: +return error; +} + +STATIC loff_t +xfs_seek_hole_data ( +struct file *file, +loff_t start, +int whence) +{ +struct inode *inode = file->f_mapping->host; +struct xfs_inode *ip =XFS_I (inode); +struct xfs_mount *mp = ip->i_mount; +uint lock; +loff_t offset, end; +int error =0 ; + +if (XFS_FORCED_SHUTDOWN (mp)) +return -EIO ; + + lock =xfs_ilock_data_map_shared (ip); + + end =i_size_read (inode); + offset =__xfs_seek_hole_data (inode, start, end, whence); +if (offset <0 ) { + error = offset; + goto out_unlock; + } + offset =vfs_setpos (file, offset, inode->i_sb->s_maxbytes); out_unlock:
fs/xfs/xfs_inode.h +2 -0
@@ -437,6 +437,8 @@ int xfs_update_prealloc_flags(struct xfs_inode *ip,int xfs_zero_eof (struct xfs_inode *ip,xfs_off_t offset,xfs_fsize_t isize,bool *did_zeroing);int xfs_iozero (struct xfs_inode *ip,loff_t pos,size_t count); +loff_t __xfs_seek_hole_data (struct inode *inode,loff_t start, +loff_t eof,int whence);/* from xfs_iops.c */
Signature · 7 lines
1.7.1 _______________________________________________ xfs mailing list [email protected] http://oss.sgi.com/mailman/listinfo/xfs
PATCH 4/4 xfs: wire up Q_XGETQUOTA2 / get_dqblk2
In reply to Eric SandeenAdd code to allow the Q_XGETQUOTA2 quotactl to quickly find all active quotas by examining the quota inode, and skipping over unallocated or uninitialized regions.
Userspace can then use this interface rather than i.e. a getpwent() loop when asked to report all active quotas.
--- fs/xfs/libxfs/xfs_quota_defs.h | 3 +- fs/xfs/xfs_dquot.c | 93 ++++++++++++++++++++++++++++++++++++++++ fs/xfs/xfs_qm.h | 2 +- fs/xfs/xfs_qm_syscalls.c | 13 +++++- fs/xfs/xfs_quotaops.c | 22 +++++++++- 5 files changed, 128 insertions(+), 5 deletions(-)
fs/xfs/libxfs/xfs_quota_defs.h +2 -1
@@ -37,7 +37,7 @@ typedef __uint16_t xfs_qwarncnt_t;#define XFS_DQ_PROJ 0x0002/* project quota */ #define XFS_DQ_GROUP 0x0004/* a group quota */ #define XFS_DQ_DIRTY 0x0008/* dquot is dirty */ -#define XFS_DQ_FREEING 0x0010/* dquot is beeing torn down */ +#define XFS_DQ_FREEING 0x0010/* dquot is being torn down */ #define XFS_DQ_ALLTYPES (XFS_DQ_USER|XFS_DQ_PROJ|XFS_DQ_GROUP)
@@ -116,6 +116,7 @@ typedef __uint16_t xfs_qwarncnt_t;#define XFS_QMOPT_DQREPAIR 0x0001000/* repair dquot if damaged */ #define XFS_QMOPT_GQUOTA 0x0002000/* group dquot requested */ #define XFS_QMOPT_ENOSPC 0x0004000/* enospc instead of edquot (prj) */ +#define XFS_QMOPT_DQNEXT 0x0008000/* return next dquot >= this ID */ /* * flags to xfs_trans_mod_dquot to indicate which field needs to be
fs/xfs/xfs_dquot.c +93 -0
129 lines not on this page · raw message
fs/xfs/xfs_qm.h +1 -1
@@ -165,7 +165,7 @@ extern void xfs_qm_dqrele_all_inodes(struct xfs_mount *, uint);/* quota ops */ extern int xfs_qm_scall_trunc_qfiles (struct xfs_mount *,uint );extern int xfs_qm_scall_getquota (struct xfs_mount *,xfs_dqid_t , -uint ,struct qc_dqblk *); +uint ,struct qc_dqblk *,qid_t *);extern int xfs_qm_scall_setqlim (struct xfs_mount *,xfs_dqid_t ,uint ,struct qc_dqblk *);extern int xfs_qm_scall_quotaon (struct xfs_mount *,uint );
fs/xfs/xfs_qm_syscalls.c +11 -2
@@ -637,17 +637,23 @@ xfs_qm_scall_getquota(struct xfs_mount *mp, xfs_dqid_t id, uint type, - struct qc_dqblk *dst) + struct qc_dqblk *dst, + qid_t *id_out) { struct xfs_dquot *dqp;int error; +uint flags =0 ; + +/* Asking for *id_out means we want the next active one */ +if (id_out) + flags =XFS_QMOPT_DQNEXT ;/* * Try to get the dquot. We don't want it allocated on disk, so * we aren't passing the XFS_QMOPT_DOALLOC flag. If it doesn't * exist, we'll get ENOENT back. */ - error =xfs_qm_dqget (mp,NULL , id, type,0 , &dqp); + error =xfs_qm_dqget (mp,NULL , id, type, flags, &dqp);if (error)return error;
@@ -681,6 +687,9 @@ xfs_qm_scall_getquota( dst->d_rt_spc_timer =be32_to_cpu (dqp->q_core.d_rtbtimer); dst->d_rt_spc_warns =be16_to_cpu (dqp->q_core.d_rtbwarns); +if (id_out) + *id_out =be32_to_cpu (dqp->q_core.d_id); +/* * Internally, we don't reset all the timers when quota enforcement * gets turned off. No need to confuse the user level code,
fs/xfs/xfs_quotaops.c +21 -1
@@ -238,7 +238,26 @@ xfs_fs_get_dqblk(return -ESRCH ;return xfs_qm_scall_getquota (mp,from_kqid (&init_user_ns, qid), -xfs_quota_type (qid.type), qdq); +xfs_quota_type (qid.type), qdq,NULL ); +} + +/* Return quota info for active quota >= this qid */ +STATIC int +xfs_fs_get_dqblk2 ( +struct super_block *sb, +struct kqid qid, +qid_t *id, +struct qc_dqblk *qdq) +{ +struct xfs_mount *mp =XFS_M (sb); + +if (!XFS_IS_QUOTA_RUNNING (mp)) +return -ENOSYS ; +if (!XFS_IS_QUOTA_ON (mp)) +return -ESRCH ; + +return xfs_qm_scall_getquota (mp,from_kqid (&init_user_ns, qid), +xfs_quota_type (qid.type), qdq, id); }STATIC int
@@ -267,5 +286,6 @@ const struct quotactl_ops xfs_quotactl_operations = { .quota_disable = xfs_quota_disable, .rm_xquota = xfs_fs_rm_xquota, .get_dqblk = xfs_fs_get_dqblk, + .get_dqblk2 = xfs_fs_get_dqblk2, .set_dqblk = xfs_fs_set_dqblk, };
Signature · 1 line
1.7.1
PATCH 1/1 linux-quota: wire Q_XGETQUOTA2 into generic repquota
In reply to Eric SandeenHere's a patch to hook Q_XGETQUOTA2 into the generic quota tools repquota command.
Rather than looping over getpwent(), it increments the id sent into the quotactl until it gets back ESRCH.
If Q_XGETQUOTA2 doesn't exist it falls back to the old method.
---
dqblk_xfs.h +1 -0
@@ -10,6 +10,7 @@#define Q_XFS_QUOTAON Q_XQUOTAON#define Q_XFS_QUOTAOFF Q_XQUOTAOFF#define Q_XFS_GETQUOTA Q_XGETQUOTA +#define Q_XFS_GETQUOTA2 Q_XGETQUOTA2#define Q_XFS_SETQLIM Q_XSETQLIM#define Q_XFS_GETQSTAT Q_XGETQSTAT#define Q_XFS_QUOTARM Q_XQUOTARM
quotaio_generic.c +49 -0
52 lines not on this page · raw message
quotaio_generic.h +4 -0
@@ -26,5 +26,9 @@ int vfs_set_dquot(struct dquot *dquot, int flags);int generic_scan_dquots (struct quota_handle *h,int (*process_dquot)(struct dquot *dquot,char *dqname),int (*get_dquot)(struct dquot *dquot)); +/* Generic routine for scanning dquots when kernel can do the scanning */ +int generic_scan_dquots2 (struct quota_handle *h, +int (*process_dquot)(struct dquot *dquot,char *dqname), +int (*get_dquot)(struct dquot *dquot));#endif
quotaio_xfs.c +29 -1
@@ -192,14 +192,42 @@ static int xfs_get_dquot(struct dquot *dq) }/* +* xfs_scan_dquots helper - processes a single dquot with Q_XGETQUOTA2 +*/ +static int xfs_get_dquot2 (struct dquot *dq) +{ +struct xfs_kern_dqblk d; +int qcmd =QCMD (Q_XFS_GETQUOTA2 , dq->dq_h->qh_type); +int ret; + +memset (&d,0 ,sizeof (d)); + ret =quotactl (qcmd, dq->dq_h->qh_quotadev, dq->dq_id, (void *)&d); +if (ret <0 ) { +if (errno ==ENOENT ) +return 0 ; +return -1 ; + } + dq->dq_id = d.d_id; +xfs_kern2utildqblk (&dq->dq_dqb, &d); +return 0 ; +} + +/* * Scan all known dquots and call callback on each */ static int xfs_scan_dquots (struct quota_handle *h,int (*process_dquot) (struct dquot *dquot,char *dqname)) { +int ret; +if (!XFS_USRQUOTA (h) && !XFS_GRPQUOTA (h))return 0 ; -return generic_scan_dquots (h, process_dquot, xfs_get_dquot); + ret =generic_scan_dquots2 (h, process_dquot, xfs_get_dquot2); + +if (ret) + ret =generic_scan_dquots (h, process_dquot, xfs_get_dquot); + +return ret; }/*
quotaio_xfs.h +1 -0
@@ -46,6 +46,7 @@#define Q_XSETQLIM XQM_CMD(0x4)/* set disk limits only */ #define Q_XGETQSTAT XQM_CMD(0x5)/* returns fs_quota_stat_t struct */ #define Q_XQUOTARM XQM_CMD(0x6)/* free quota files' space */ +#define Q_XGETQUOTA2 XQM_CMD(0x9)/* get disk limits and usage >= ID */ /* * fs_disk_quota structure:
Quoted 8 lines · Eric Sandeen
This adds a new quotactl,
Q_XGETQUOTA2.
Q_XGETQUOTA2is exactly likeQ_XGETQUOTA, except that it will return quota information for the id equal to or greater than the id requested. In other words, if the specified id has no quota, the command will return quota information for the next higher id which does have a quota set. If no higher id has an active quota,-ESRCHis returned.
Please add a flags argument to Q_XGETQUOTA2, and then make the new behavior the first flag. Keep Q_XGETQUOTA behavior for the flag-less case. That way we get future etensibility for free.
Jan Kara
reviewerQuoted 10 lines · Christoph Hellwig
Quoted 8 lines · Eric Sandeen
This adds a new quotactl,
Q_XGETQUOTA2.
Q_XGETQUOTA2is exactly likeQ_XGETQUOTA, except that it will return quota information for the id equal to or greater than the id requested. In other words, if the specified id has no quota, the command will return quota information for the next higher id which does have a quota set. If no higher id has an active quota,-ESRCHis returned.
Quoted 3 lines
Please add a flags argument to
Q_XGETQUOTA2, and then make the new behavior the first flag. KeepQ_XGETQUOTAbehavior for the flag-less case. That way we get future etensibility for free.
So this is what I wanted to suggest at first as well. What I somewhat dislike is that 'addr' must now point to something like:
struct getquota_args {
__u64 flags;
struct fs_disk_quota ret;
};which is not as nice as passing pointer to fs_disk_quota directly. But probably still OK. So I agree with the flags idea.
Another issue is that OCFS2 and ext4 with quota in hidden inodes would need call with these capabilities as well (they have the same problem as xfs). For reporting VFS quota we use bytes for space (since some filesystems need it) and we don't need RT fields (easy so zero-fill) and warning fields (there zeros may be confusing). So we would need something like struct qc_dqblk (currently only internal) extended with ID and maybe flags field XFS is using to return quota type which can contain all the information and tell which info is actually valid as return structure.
Honza
Signature · 2 lines
Jan Kara <[email protected]> SUSE Labs, CR
Quoted 15 lines · Jan Kara
Quoted 10 lines · Christoph Hellwig
Quoted 8 lines · Eric Sandeen
This adds a new quotactl,
Q_XGETQUOTA2.
Q_XGETQUOTA2is exactly likeQ_XGETQUOTA, except that it will return quota information for the id equal to or greater than the id requested. In other words, if the specified id has no quota, the command will return quota information for the next higher id which does have a quota set. If no higher id has an active quota,-ESRCHis returned.Quoted 3 lines
Please add a flags argument to
Q_XGETQUOTA2, and then make the new behavior the first flag. KeepQ_XGETQUOTAbehavior for the flag-less case. That way we get future etensibility for free.
Quoted 7 lines
So this is what I wanted to suggest at first as well. What I somewhat dislike is that 'addr' must now point to something like:
struct getquota_args { __u64 flags; struct fs_disk_quota ret; };
Ok...
Quoted 2 lines
which is not as nice as passing pointer to
fs_disk_quotadirectly. But probably still OK. So I agree with the flags idea.
I understand that flags are for future-proofing, for possibly-not-yet-imagined scenarios, but on the other hand, I wonder how many different flavors of "get me a disk quota" we really expect to have?
Quoted 8 lines
Another issue is that OCFS2 and ext4 with quota in hidden inodes would need call with these capabilities as well (they have the same problem as xfs). For reporting VFS quota we use bytes for space (since some filesystems need it) and we don't need RT fields (easy so zero-fill) and warning fields (there zeros may be confusing). So we would need something like struct
qc_dqblk(currently only internal) extended with ID and maybe flags field XFS is using to return quota type which can contain all the information and tell which info is actually valid as return structure.
Hohum, yeah - I forgot that ext4 has (can have?) a hidden quota inode. And I didn't know about OCFS2.
And TBH I did the xfs-specific one because it was trivial to extend, with the id already in the returned quota struct.
So ok, it sounds like this needs a more significant overhaul at the vfs quota level...
-Eric
Quoted 3 lines
Honza
Jan Kara
reviewerQuoted 42 lines · Eric Sandeen
Quoted 15 lines · Jan Kara
Quoted 10 lines · Christoph Hellwig
Quoted 8 lines · Eric Sandeen
This adds a new quotactl,
Q_XGETQUOTA2.
Q_XGETQUOTA2is exactly likeQ_XGETQUOTA, except that it will return quota information for the id equal to or greater than the id requested. In other words, if the specified id has no quota, the command will return quota information for the next higher id which does have a quota set. If no higher id has an active quota,-ESRCHis returned.Quoted 3 lines
Please add a flags argument to
Q_XGETQUOTA2, and then make the new behavior the first flag. KeepQ_XGETQUOTAbehavior for the flag-less case. That way we get future etensibility for free.Quoted 7 lines
So this is what I wanted to suggest at first as well. What I somewhat dislike is that 'addr' must now point to something like:
struct getquota_args { __u64 flags; struct fs_disk_quota ret; };Ok...
Quoted 2 lines
which is not as nice as passing pointer to
fs_disk_quotadirectly. But probably still OK. So I agree with the flags idea.I understand that flags are for future-proofing, for possibly-not-yet-imagined scenarios, but on the other hand, I wonder how many different flavors of "get me a disk quota" we really expect to have?
Quoted 8 lines
Another issue is that OCFS2 and ext4 with quota in hidden inodes would need call with these capabilities as well (they have the same problem as xfs). For reporting VFS quota we use bytes for space (since some filesystems need it) and we don't need RT fields (easy so zero-fill) and warning fields (there zeros may be confusing). So we would need something like struct
qc_dqblk(currently only internal) extended with ID and maybe flags field XFS is using to return quota type which can contain all the information and tell which info is actually valid as return structure.
Quoted 8 lines
Hohum, yeah - I forgot that ext4 has (can have?) a hidden quota inode. And I didn't know about OCFS2.
And TBH I did the xfs-specific one because it was trivial to extend, with the id already in the returned quota struct.
So ok, it sounds like this needs a more significant overhaul at the vfs quota level...
Actually, what I want from you is just an interface which is usable for VFS quotas as well since I'd like to avoid adding GETQUOTA2 quotactl shortly after XGETQUOTA2 :). Using id as a cooking is fine for VFS quotas as well so that part can stay.
I can have a look at implementing the new handler for VFS quota format(s) which should be pretty easy once the interface part is merged or you can do it if you're interested in learning more about quota internals.
Honza
Signature · 2 lines
Jan Kara <[email protected]> SUSE Labs, CR
Quoted 49 lines · Jan Kara
Quoted 48 lines · Eric Sandeen
Quoted 15 lines · Jan Kara
Quoted 10 lines · Christoph Hellwig
Quoted 8 lines · Eric Sandeen
This adds a new quotactl,
Q_XGETQUOTA2.
Q_XGETQUOTA2is exactly likeQ_XGETQUOTA, except that it will return quota information for the id equal to or greater than the id requested. In other words, if the specified id has no quota, the command will return quota information for the next higher id which does have a quota set. If no higher id has an active quota,-ESRCHis returned.Quoted 3 lines
Please add a flags argument to
Q_XGETQUOTA2, and then make the new behavior the first flag. KeepQ_XGETQUOTAbehavior for the flag-less case. That way we get future etensibility for free.Quoted 7 lines
So this is what I wanted to suggest at first as well. What I somewhat dislike is that 'addr' must now point to something like:
struct getquota_args { __u64 flags; struct fs_disk_quota ret; };Ok...
Quoted 2 lines
which is not as nice as passing pointer to
fs_disk_quotadirectly. But probably still OK. So I agree with the flags idea.I understand that flags are for future-proofing, for possibly-not-yet-imagined scenarios, but on the other hand, I wonder how many different flavors of "get me a disk quota" we really expect to have?
Quoted 8 lines
Another issue is that OCFS2 and ext4 with quota in hidden inodes would need call with these capabilities as well (they have the same problem as xfs). For reporting VFS quota we use bytes for space (since some filesystems need it) and we don't need RT fields (easy so zero-fill) and warning fields (there zeros may be confusing). So we would need something like struct
qc_dqblk(currently only internal) extended with ID and maybe flags field XFS is using to return quota type which can contain all the information and tell which info is actually valid as return structure.Hohum, yeah - I forgot that ext4 has (can have?) a hidden quota inode. And I didn't know about OCFS2.
And TBH I did the xfs-specific one because it was trivial to extend, with the id already in the returned quota struct.
Quoted 6 lines
Quoted 2 lines
So ok, it sounds like this needs a more significant overhaul at the vfs quota level...
Actually, what I want from you is just an interface which is usable for VFS quotas as well since I'd like to avoid adding GETQUOTA2 quotactl shortly after XGETQUOTA2 :).
Actually, that's exactly what I thought would *need* to happen ... we already have this weird 15-year-old split-brain quota interface, so if xfs and ext4 both need the same functionality, then we'd probably add both GETQUOTA2 and XGETQUOTA2. If we were doing this all from scratch, sure, but adding a new handles-both-quota-types interface when every other operation is already split between the two almost seems to make matters worse.
-Eric
_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
Quoted 49 lines · Jan Kara
Quoted 48 lines · Eric Sandeen
Quoted 15 lines · Jan Kara
Quoted 10 lines · Christoph Hellwig
Quoted 8 lines · Eric Sandeen
This adds a new quotactl,
Q_XGETQUOTA2.
Q_XGETQUOTA2is exactly likeQ_XGETQUOTA, except that it will return quota information for the id equal to or greater than the id requested. In other words, if the specified id has no quota, the command will return quota information for the next higher id which does have a quota set. If no higher id has an active quota,-ESRCHis returned.Quoted 3 lines
Please add a flags argument to
Q_XGETQUOTA2, and then make the new behavior the first flag. KeepQ_XGETQUOTAbehavior for the flag-less case. That way we get future etensibility for free.Quoted 7 lines
So this is what I wanted to suggest at first as well. What I somewhat dislike is that 'addr' must now point to something like:
struct getquota_args { __u64 flags; struct fs_disk_quota ret; };Ok...
Quoted 2 lines
which is not as nice as passing pointer to
fs_disk_quotadirectly. But probably still OK. So I agree with the flags idea.I understand that flags are for future-proofing, for possibly-not-yet-imagined scenarios, but on the other hand, I wonder how many different flavors of "get me a disk quota" we really expect to have?
Quoted 8 lines
Another issue is that OCFS2 and ext4 with quota in hidden inodes would need call with these capabilities as well (they have the same problem as xfs). For reporting VFS quota we use bytes for space (since some filesystems need it) and we don't need RT fields (easy so zero-fill) and warning fields (there zeros may be confusing). So we would need something like struct
qc_dqblk(currently only internal) extended with ID and maybe flags field XFS is using to return quota type which can contain all the information and tell which info is actually valid as return structure.Hohum, yeah - I forgot that ext4 has (can have?) a hidden quota inode. And I didn't know about OCFS2.
And TBH I did the xfs-specific one because it was trivial to extend, with the id already in the returned quota struct.
Quoted 6 lines
Quoted 2 lines
So ok, it sounds like this needs a more significant overhaul at the vfs quota level...
Actually, what I want from you is just an interface which is usable for VFS quotas as well since I'd like to avoid adding GETQUOTA2 quotactl shortly after XGETQUOTA2 :).
Actually, that's exactly what I thought would *need* to happen ... we already have this weird 15-year-old split-brain quota interface, so if xfs and ext4 both need the same functionality, then we'd probably add both GETQUOTA2 and XGETQUOTA2. If we were doing this all from scratch, sure, but adding a new handles-both-quota-types interface when every other operation is already split between the two almost seems to make matters worse.
-Eric
Jan Kara
reviewerQuoted 57 lines · Eric Sandeen
Quoted 49 lines · Jan Kara
Quoted 48 lines · Eric Sandeen
Quoted 15 lines · Jan Kara
Quoted 10 lines · Christoph Hellwig
Quoted 8 lines · Eric Sandeen
This adds a new quotactl,
Q_XGETQUOTA2.
Q_XGETQUOTA2is exactly likeQ_XGETQUOTA, except that it will return quota information for the id equal to or greater than the id requested. In other words, if the specified id has no quota, the command will return quota information for the next higher id which does have a quota set. If no higher id has an active quota,-ESRCHis returned.Quoted 3 lines
Please add a flags argument to
Q_XGETQUOTA2, and then make the new behavior the first flag. KeepQ_XGETQUOTAbehavior for the flag-less case. That way we get future etensibility for free.Quoted 7 lines
So this is what I wanted to suggest at first as well. What I somewhat dislike is that 'addr' must now point to something like:
struct getquota_args { __u64 flags; struct fs_disk_quota ret; };Ok...
Quoted 2 lines
which is not as nice as passing pointer to
fs_disk_quotadirectly. But probably still OK. So I agree with the flags idea.I understand that flags are for future-proofing, for possibly-not-yet-imagined scenarios, but on the other hand, I wonder how many different flavors of "get me a disk quota" we really expect to have?
Quoted 8 lines
Another issue is that OCFS2 and ext4 with quota in hidden inodes would need call with these capabilities as well (they have the same problem as xfs). For reporting VFS quota we use bytes for space (since some filesystems need it) and we don't need RT fields (easy so zero-fill) and warning fields (there zeros may be confusing). So we would need something like struct
qc_dqblk(currently only internal) extended with ID and maybe flags field XFS is using to return quota type which can contain all the information and tell which info is actually valid as return structure.Hohum, yeah - I forgot that ext4 has (can have?) a hidden quota inode. And I didn't know about OCFS2.
And TBH I did the xfs-specific one because it was trivial to extend, with the id already in the returned quota struct.
Quoted 6 lines
Quoted 2 lines
So ok, it sounds like this needs a more significant overhaul at the vfs quota level...
Actually, what I want from you is just an interface which is usable for VFS quotas as well since I'd like to avoid adding GETQUOTA2 quotactl shortly after XGETQUOTA2 :).
Quoted 6 lines
Actually, that's exactly what I thought would *need* to happen ... we already have this weird 15-year-old split-brain quota interface, so if xfs and ext4 both need the same functionality, then we'd probably add both GETQUOTA2 and XGETQUOTA2. If we were doing this all from scratch, sure, but adding a new handles-both-quota-types interface when every other operation is already split between the two almost seems to make matters worse.
Well, currently GETQUOTA and XGETQUOTA (and all the other quotactls) are actually translated so they work regardless of the underlying filesystem. So the only difference between XFS and VFS quotactls is in the formatting of input/output structures. So from kernel POV it seems somewhat pointless to add two calls doing the same thing and differing just in the formatting of output - especially when we want the call to be extensible.
I agree that having a unified call means having a new structure for passing dquot info between kernel and userspace. So just for adding that one small feature you want it seems like an overkill. But when thinking about new extensible getquota quotactl it IMHO makes sense to unify the VFS/XFS split brain. Thoughts?
Honza
Signature · 2 lines
Jan Kara <[email protected]> SUSE Labs, CR
Hi Jan -
Quoted 2 lines · Jan Kara
Quoted 1 line · Eric Sandeen
On 1/11/16 10:28 AM, Jan Kara wrote:
...
Quoted 18 lines
Quoted 10 lines
Quoted 3 lines
Actually, what I want from you is just an interface which is usable for VFS quotas as well since I'd like to avoid adding GETQUOTA2 quotactl shortly after XGETQUOTA2 :).
Actually, that's exactly what I thought would *need* to happen ... we already have this weird 15-year-old split-brain quota interface, so if xfs and ext4 both need the same functionality, then we'd probably add both GETQUOTA2 and XGETQUOTA2. If we were doing this all from scratch, sure, but adding a new handles-both-quota-types interface when every other operation is already split between the two almost seems to make matters worse.
Well, currently GETQUOTA and XGETQUOTA (and all the other quotactls) are actually translated so they work regardless of the underlying filesystem. So the only difference between XFS and VFS quotactls is in the formatting of input/output structures. So from kernel POV it seems somewhat pointless to add two calls doing the same thing and differing just in the formatting of output - especially when we want the call to be extensible.
Quoted 5 lines
I agree that having a unified call means having a new structure for passing dquot info between kernel and userspace. So just for adding that one small feature you want it seems like an overkill. But when thinking about new extensible getquota quotactl it IMHO makes sense to unify the VFS/XFS split brain. Thoughts?
My first lazy/hacky thought is "how terrible would it be to overload the quotactl syscall return value with quota ID for Q_GETQUOTA2 calls?"
For a purpose-built interface of "find the next ID" that wouldn't require any structure or interface changes...
We could name it Q_GETNEXTQUOTA / Q_XGETNEXTQUOTA to make it explicit about the purpose, and document that return behavior. Done & done. ;)
A new grand unified extensible quota call sounds like a great idea, I just hate to gate this work on designing a brand-new interface.
-Eric
Quoted 2 lines · Eric Sandeen
My first lazy/hacky thought is "how terrible would it be to overload the quotactl syscall return value with quota ID for
Q_GETQUOTA2calls?"
Never mind, we can use all 32 bits of the unsigned ID, I think, so that doesn't work. (thanks Zach) :)
-Eric
Jan Kara
reviewerQuoted 26 lines · Eric Sandeen
Hi Jan -
Quoted 2 lines · Jan Kara
Quoted 1 line · Eric Sandeen
On 1/11/16 10:28 AM, Jan Kara wrote:
...
Quoted 18 lines
Quoted 10 lines
Quoted 3 lines
Actually, what I want from you is just an interface which is usable for VFS quotas as well since I'd like to avoid adding GETQUOTA2 quotactl shortly after XGETQUOTA2 :).
Actually, that's exactly what I thought would *need* to happen ... we already have this weird 15-year-old split-brain quota interface, so if xfs and ext4 both need the same functionality, then we'd probably add both GETQUOTA2 and XGETQUOTA2. If we were doing this all from scratch, sure, but adding a new handles-both-quota-types interface when every other operation is already split between the two almost seems to make matters worse.
Well, currently GETQUOTA and XGETQUOTA (and all the other quotactls) are actually translated so they work regardless of the underlying filesystem. So the only difference between XFS and VFS quotactls is in the formatting of input/output structures. So from kernel POV it seems somewhat pointless to add two calls doing the same thing and differing just in the formatting of output - especially when we want the call to be extensible.
Quoted 8 lines
Quoted 5 lines
I agree that having a unified call means having a new structure for passing dquot info between kernel and userspace. So just for adding that one small feature you want it seems like an overkill. But when thinking about new extensible getquota quotactl it IMHO makes sense to unify the VFS/XFS split brain. Thoughts?
My first lazy/hacky thought is "how terrible would it be to overload the quotactl syscall return value with quota ID for
Q_GETQUOTA2calls?"
As you said, that won't quite work...
Quoted 8 lines
For a purpose-built interface of "find the next ID" that wouldn't require any structure or interface changes...
We could name it
Q_GETNEXTQUOTA/Q_XGETNEXTQUOTAto make it explicit about the purpose, and document that return behavior. Done & done. ;)A new grand unified extensible quota call sounds like a great idea, I just hate to gate this work on designing a brand-new interface.
OK, ok. I like Dave's proposal for quotactl2(). So let's leave the unification for later and implent Q_GETNEXTQUOTA and Q_XGETNEXTQUOTA with the functionality of your original Q_XGETQUOTA2. Having separate call to get next ID would save us one new quotactl but OTOH we would need two syscalls (and quota structure lookups) to report one structure and there are potentially *lots* of them.
Honza
Signature · 2 lines
Jan Kara <[email protected]> SUSE Labs, CR
Quoted 6 lines · Jan Kara
OK, ok. I like Dave's proposal for
quotactl2(). So let's leave the unification for later and implentQ_GETNEXTQUOTAandQ_XGETNEXTQUOTAwith the functionality of your originalQ_XGETQUOTA2. Having separate call to get next ID would save us one new quotactl but OTOH we would need two syscalls (and quota structure lookups) to report one structure and there are potentially *lots* of them.
Oh well. Guess I should give in and just accept the original patch..
Quoted 1 line · Jan Kara
On Fri 15-01-16 11:31:00, Eric Sandeen wrote:
...
Quoted 9 lines
Quoted 8 lines
For a purpose-built interface of "find the next ID" that wouldn't require any structure or interface changes...
We could name it
Q_GETNEXTQUOTA/Q_XGETNEXTQUOTAto make it explicit about the purpose, and document that return behavior. Done & done. ;)A new grand unified extensible quota call sounds like a great idea, I just hate to gate this work on designing a brand-new interface.
Quoted 6 lines
OK, ok. I like Dave's proposal for
quotactl2(). So let's leave the unification for later and implentQ_GETNEXTQUOTAandQ_XGETNEXTQUOTAwith the functionality of your originalQ_XGETQUOTA2. Having separate call to get next ID would save us one new quotactl but OTOH we would need two syscalls (and quota structure lookups) to report one structure and there are potentially *lots* of them.
Ok, I can re-do it with the new Q_[X]GETNEXTQUOTA names, I've already done the non-xfs one as well, just starting testing on that.
With or without the flags argument?
Thanks,
-Eric
Jan Kara
reviewerQuoted 21 lines · Eric Sandeen
Quoted 1 line · Jan Kara
On Fri 15-01-16 11:31:00, Eric Sandeen wrote:
...
Quoted 9 lines
Quoted 8 lines
For a purpose-built interface of "find the next ID" that wouldn't require any structure or interface changes...
We could name it
Q_GETNEXTQUOTA/Q_XGETNEXTQUOTAto make it explicit about the purpose, and document that return behavior. Done & done. ;)A new grand unified extensible quota call sounds like a great idea, I just hate to gate this work on designing a brand-new interface.
Quoted 6 lines
OK, ok. I like Dave's proposal for
quotactl2(). So let's leave the unification for later and implentQ_GETNEXTQUOTAandQ_XGETNEXTQUOTAwith the functionality of your originalQ_XGETQUOTA2. Having separate call to get next ID would save us one new quotactl but OTOH we would need two syscalls (and quota structure lookups) to report one structure and there are potentially *lots* of them.
Quoted 4 lines
Ok, I can re-do it with the new Q_[X]GETNEXTQUOTA names, I've already done the non-xfs one as well, just starting testing on that.
With or without the flags argument?
Without. For further extensibility I'd really go for the unified API in the end.
Honza
Signature · 2 lines
Jan Kara <[email protected]> SUSE Labs, CR
Quoted 22 lines · Jan Kara
Quoted 21 lines · Eric Sandeen
Quoted 1 line · Jan Kara
On Fri 15-01-16 11:31:00, Eric Sandeen wrote:
...
Quoted 15 lines
Quoted 8 lines
For a purpose-built interface of "find the next ID" that wouldn't require any structure or interface changes...
We could name it
Q_GETNEXTQUOTA/Q_XGETNEXTQUOTAto make it explicit about the purpose, and document that return behavior. Done & done. ;)A new grand unified extensible quota call sounds like a great idea, I just hate to gate this work on designing a brand-new interface.
OK, ok. I like Dave's proposal for
quotactl2(). So let's leave the unification for later and implentQ_GETNEXTQUOTAandQ_XGETNEXTQUOTAwith the functionality of your originalQ_XGETQUOTA2. Having separate call to get next ID would save us one new quotactl but OTOH we would need two syscalls (and quota structure lookups) to report one structure and there are potentially *lots* of them.
Quoted 7 lines
Quoted 4 lines
Ok, I can re-do it with the new Q_[X]GETNEXTQUOTA names, I've already done the non-xfs one as well, just starting testing on that.
With or without the flags argument?
Without. For further extensibility I'd really go for the unified API in the end.
Thanks. I'll get new patches out in a bit, putting some polish on them and the userspace, and seeing about a regression test as well.
Realized I need to think semi-carefully about what we do for IDs found on disk but not in the user database; today I think extN will show everything; XFS only shows IDs in the DB, unless an ID range is specified - probably need to keep all behavior the same, without some explicit commandline switches to do differently.
Thanks,
-Eric
_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
Quoted 15 lines · Jan Kara
Quoted 6 lines · Eric Sandeen
Actually, that's exactly what I thought would *need* to happen ... we already have this weird 15-year-old split-brain quota interface, so if xfs and ext4 both need the same functionality, then we'd probably add both GETQUOTA2 and XGETQUOTA2. If we were doing this all from scratch, sure, but adding a new handles-both-quota-types interface when every other operation is already split between the two almost seems to make matters worse.
Well, currently GETQUOTA and XGETQUOTA (and all the other quotactls) are actually translated so they work regardless of the underlying filesystem. So the only difference between XFS and VFS quotactls is in the formatting of input/output structures. So from kernel POV it seems somewhat pointless to add two calls doing the same thing and differing just in the formatting of output - especially when we want the call to be extensible.
Quoted 5 lines
I agree that having a unified call means having a new structure for passing dquot info between kernel and userspace. So just for adding that one small feature you want it seems like an overkill. But when thinking about new extensible getquota quotactl it IMHO makes sense to unify the VFS/XFS split brain. Thoughts?
A new unified userspace quota API would be nice, but it's a completely separate piece of work. We'd also need to do userspace work to support it, so I think this is a valid medium term goal, but not somethign that should gate the work Eric is doing.
i.e. it might be best to introduce a quotactl2 syscall for a unified interface, such that the syscall itself has a flags argument rather than having to jump through hoops to embed flags in argument structures.....
FWIW, converting xfs_quota to use a new kernel API is trivial (half an hour's work) as it already has a kernel API abstraction layer for cross platform support. Hence we can quickly get userspace support in place to test such a new kernel API...
Cheers,
Dave.
Signature · 2 lines
Dave Chinner [email protected]