mirror of https://gitee.com/openkylin/linux.git
Merge branch 'xfs-get-next-dquot-4.6' of git://git.kernel.org/pub/scm/linux/kernel/git/dgc/linux-xfs into for_next
This commit is contained in:
commit
92bd85fa1f
|
@ -79,7 +79,7 @@ unsigned int qtype_enforce_flag(int type)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int quota_quotaon(struct super_block *sb, int type, int cmd, qid_t id,
|
||||
static int quota_quotaon(struct super_block *sb, int type, qid_t id,
|
||||
struct path *path)
|
||||
{
|
||||
if (!sb->s_qcop->quota_on && !sb->s_qcop->quota_enable)
|
||||
|
@ -222,6 +222,34 @@ static int quota_getquota(struct super_block *sb, int type, qid_t id,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return quota for next active quota >= this id, if any exists,
|
||||
* otherwise return -ESRCH via ->get_nextdqblk
|
||||
*/
|
||||
static int quota_getnextquota(struct super_block *sb, int type, qid_t id,
|
||||
void __user *addr)
|
||||
{
|
||||
struct kqid qid;
|
||||
struct qc_dqblk fdq;
|
||||
struct if_nextdqblk idq;
|
||||
int ret;
|
||||
|
||||
if (!sb->s_qcop->get_nextdqblk)
|
||||
return -ENOSYS;
|
||||
qid = make_kqid(current_user_ns(), type, id);
|
||||
if (!qid_valid(qid))
|
||||
return -EINVAL;
|
||||
ret = sb->s_qcop->get_nextdqblk(sb, &qid, &fdq);
|
||||
if (ret)
|
||||
return ret;
|
||||
/* struct if_nextdqblk is a superset of struct if_dqblk */
|
||||
copy_to_if_dqblk((struct if_dqblk *)&idq, &fdq);
|
||||
idq.dqb_id = from_kqid(current_user_ns(), qid);
|
||||
if (copy_to_user(addr, &idq, sizeof(idq)))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void copy_from_if_dqblk(struct qc_dqblk *dst, struct if_dqblk *src)
|
||||
{
|
||||
dst->d_spc_hardlimit = qbtos(src->dqb_bhardlimit);
|
||||
|
@ -625,6 +653,34 @@ 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 via ->get_nextdqblk.
|
||||
*/
|
||||
static int quota_getnextxquota(struct super_block *sb, int type, qid_t id,
|
||||
void __user *addr)
|
||||
{
|
||||
struct fs_disk_quota fdq;
|
||||
struct qc_dqblk qdq;
|
||||
struct kqid qid;
|
||||
qid_t id_out;
|
||||
int ret;
|
||||
|
||||
if (!sb->s_qcop->get_nextdqblk)
|
||||
return -ENOSYS;
|
||||
qid = make_kqid(current_user_ns(), type, id);
|
||||
if (!qid_valid(qid))
|
||||
return -EINVAL;
|
||||
ret = sb->s_qcop->get_nextdqblk(sb, &qid, &qdq);
|
||||
if (ret)
|
||||
return ret;
|
||||
id_out = from_kqid(current_user_ns(), qid);
|
||||
copy_to_xfs_dqblk(&fdq, &qdq, type, id_out);
|
||||
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;
|
||||
|
@ -659,7 +715,7 @@ static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id,
|
|||
|
||||
switch (cmd) {
|
||||
case Q_QUOTAON:
|
||||
return quota_quotaon(sb, type, cmd, id, path);
|
||||
return quota_quotaon(sb, type, id, path);
|
||||
case Q_QUOTAOFF:
|
||||
return quota_quotaoff(sb, type);
|
||||
case Q_GETFMT:
|
||||
|
@ -670,6 +726,8 @@ static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id,
|
|||
return quota_setinfo(sb, type, addr);
|
||||
case Q_GETQUOTA:
|
||||
return quota_getquota(sb, type, id, addr);
|
||||
case Q_GETNEXTQUOTA:
|
||||
return quota_getnextquota(sb, type, id, addr);
|
||||
case Q_SETQUOTA:
|
||||
return quota_setquota(sb, type, id, addr);
|
||||
case Q_SYNC:
|
||||
|
@ -690,6 +748,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_XGETNEXTQUOTA:
|
||||
return quota_getnextxquota(sb, type, id, addr);
|
||||
case Q_XQUOTASYNC:
|
||||
if (sb->s_flags & MS_RDONLY)
|
||||
return -EROFS;
|
||||
|
@ -708,10 +768,12 @@ static int quotactl_cmd_write(int cmd)
|
|||
switch (cmd) {
|
||||
case Q_GETFMT:
|
||||
case Q_GETINFO:
|
||||
case Q_GETNEXTQUOTA:
|
||||
case Q_SYNC:
|
||||
case Q_XGETQSTAT:
|
||||
case Q_XGETQSTATV:
|
||||
case Q_XGETQUOTA:
|
||||
case Q_XGETNEXTQUOTA:
|
||||
case Q_XQUOTASYNC:
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -92,26 +92,28 @@ xfs_qm_adjust_dqlimits(
|
|||
{
|
||||
struct xfs_quotainfo *q = mp->m_quotainfo;
|
||||
struct xfs_disk_dquot *d = &dq->q_core;
|
||||
struct xfs_def_quota *defq;
|
||||
int prealloc = 0;
|
||||
|
||||
ASSERT(d->d_id);
|
||||
defq = xfs_get_defquota(dq, q);
|
||||
|
||||
if (q->qi_bsoftlimit && !d->d_blk_softlimit) {
|
||||
d->d_blk_softlimit = cpu_to_be64(q->qi_bsoftlimit);
|
||||
if (defq->bsoftlimit && !d->d_blk_softlimit) {
|
||||
d->d_blk_softlimit = cpu_to_be64(defq->bsoftlimit);
|
||||
prealloc = 1;
|
||||
}
|
||||
if (q->qi_bhardlimit && !d->d_blk_hardlimit) {
|
||||
d->d_blk_hardlimit = cpu_to_be64(q->qi_bhardlimit);
|
||||
if (defq->bhardlimit && !d->d_blk_hardlimit) {
|
||||
d->d_blk_hardlimit = cpu_to_be64(defq->bhardlimit);
|
||||
prealloc = 1;
|
||||
}
|
||||
if (q->qi_isoftlimit && !d->d_ino_softlimit)
|
||||
d->d_ino_softlimit = cpu_to_be64(q->qi_isoftlimit);
|
||||
if (q->qi_ihardlimit && !d->d_ino_hardlimit)
|
||||
d->d_ino_hardlimit = cpu_to_be64(q->qi_ihardlimit);
|
||||
if (q->qi_rtbsoftlimit && !d->d_rtb_softlimit)
|
||||
d->d_rtb_softlimit = cpu_to_be64(q->qi_rtbsoftlimit);
|
||||
if (q->qi_rtbhardlimit && !d->d_rtb_hardlimit)
|
||||
d->d_rtb_hardlimit = cpu_to_be64(q->qi_rtbhardlimit);
|
||||
if (defq->isoftlimit && !d->d_ino_softlimit)
|
||||
d->d_ino_softlimit = cpu_to_be64(defq->isoftlimit);
|
||||
if (defq->ihardlimit && !d->d_ino_hardlimit)
|
||||
d->d_ino_hardlimit = cpu_to_be64(defq->ihardlimit);
|
||||
if (defq->rtbsoftlimit && !d->d_rtb_softlimit)
|
||||
d->d_rtb_softlimit = cpu_to_be64(defq->rtbsoftlimit);
|
||||
if (defq->rtbhardlimit && !d->d_rtb_hardlimit)
|
||||
d->d_rtb_hardlimit = cpu_to_be64(defq->rtbhardlimit);
|
||||
|
||||
if (prealloc)
|
||||
xfs_dquot_set_prealloc_limits(dq);
|
||||
|
@ -232,7 +234,8 @@ xfs_qm_init_dquot_blk(
|
|||
{
|
||||
struct xfs_quotainfo *q = mp->m_quotainfo;
|
||||
xfs_dqblk_t *d;
|
||||
int curid, i;
|
||||
xfs_dqid_t curid;
|
||||
int i;
|
||||
|
||||
ASSERT(tp);
|
||||
ASSERT(xfs_buf_islocked(bp));
|
||||
|
@ -243,7 +246,6 @@ xfs_qm_init_dquot_blk(
|
|||
* ID of the first dquot in the block - id's are zero based.
|
||||
*/
|
||||
curid = id - (id % q->qi_dqperchunk);
|
||||
ASSERT(curid >= 0);
|
||||
memset(d, 0, BBTOB(q->qi_dqchunklen));
|
||||
for (i = 0; i < q->qi_dqperchunk; i++, d++, curid++) {
|
||||
d->dd_diskdq.d_magic = cpu_to_be16(XFS_DQUOT_MAGIC);
|
||||
|
@ -464,12 +466,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);
|
||||
|
@ -684,6 +687,56 @@ xfs_qm_dqread(
|
|||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* Advance to the next id in the current chunk, or if at the
|
||||
* end of the chunk, skip ahead to first id in next allocated chunk
|
||||
* using the SEEK_DATA interface.
|
||||
*/
|
||||
int
|
||||
xfs_dq_get_next_id(
|
||||
xfs_mount_t *mp,
|
||||
uint type,
|
||||
xfs_dqid_t *id,
|
||||
loff_t eof)
|
||||
{
|
||||
struct xfs_inode *quotip;
|
||||
xfs_fsblock_t start;
|
||||
loff_t offset;
|
||||
uint lock;
|
||||
xfs_dqid_t next_id;
|
||||
int error = 0;
|
||||
|
||||
/* Simple advance */
|
||||
next_id = *id + 1;
|
||||
|
||||
/* If new ID is within the current chunk, advancing it sufficed */
|
||||
if (next_id % mp->m_quotainfo->qi_dqperchunk) {
|
||||
*id = next_id;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Nope, next_id is now past the current chunk, so find the next one */
|
||||
start = (xfs_fsblock_t)next_id / mp->m_quotainfo->qi_dqperchunk;
|
||||
|
||||
quotip = xfs_quota_inode(mp, type);
|
||||
lock = xfs_ilock_data_map_shared(quotip);
|
||||
|
||||
offset = __xfs_seek_hole_data(VFS_I(quotip), XFS_FSB_TO_B(mp, start),
|
||||
eof, SEEK_DATA);
|
||||
if (offset < 0)
|
||||
error = offset;
|
||||
|
||||
xfs_iunlock(quotip, lock);
|
||||
|
||||
/* -ENXIO is essentially "no more data" */
|
||||
if (error)
|
||||
return (error == -ENXIO ? -ENOENT: error);
|
||||
|
||||
/* Convert next data offset back to a quota id */
|
||||
*id = XFS_B_TO_FSB(mp, offset) * mp->m_quotainfo->qi_dqperchunk;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Given the file system, inode OR id, and type (UDQUOT/GDQUOT), return a
|
||||
* a locked dquot, doing an allocation (if requested) as needed.
|
||||
|
@ -704,6 +757,7 @@ xfs_qm_dqget(
|
|||
struct xfs_quotainfo *qi = mp->m_quotainfo;
|
||||
struct radix_tree_root *tree = xfs_dquot_tree(qi, type);
|
||||
struct xfs_dquot *dqp;
|
||||
loff_t eof = 0;
|
||||
int error;
|
||||
|
||||
ASSERT(XFS_IS_QUOTA_RUNNING(mp));
|
||||
|
@ -731,6 +785,21 @@ xfs_qm_dqget(
|
|||
}
|
||||
#endif
|
||||
|
||||
/* Get the end of the quota file if we need it */
|
||||
if (flags & XFS_QMOPT_DQNEXT) {
|
||||
struct xfs_inode *quotip;
|
||||
xfs_fileoff_t last;
|
||||
uint lock_mode;
|
||||
|
||||
quotip = xfs_quota_inode(mp, type);
|
||||
lock_mode = xfs_ilock_data_map_shared(quotip);
|
||||
error = xfs_bmap_last_offset(quotip, &last, XFS_DATA_FORK);
|
||||
xfs_iunlock(quotip, lock_mode);
|
||||
if (error)
|
||||
return error;
|
||||
eof = XFS_FSB_TO_B(mp, last);
|
||||
}
|
||||
|
||||
restart:
|
||||
mutex_lock(&qi->qi_tree_lock);
|
||||
dqp = radix_tree_lookup(tree, id);
|
||||
|
@ -744,6 +813,18 @@ xfs_qm_dqget(
|
|||
goto restart;
|
||||
}
|
||||
|
||||
/* uninit / unused quota found in radix tree, keep looking */
|
||||
if (flags & XFS_QMOPT_DQNEXT) {
|
||||
if (XFS_IS_DQUOT_UNINITIALIZED(dqp)) {
|
||||
xfs_dqunlock(dqp);
|
||||
mutex_unlock(&qi->qi_tree_lock);
|
||||
error = xfs_dq_get_next_id(mp, type, &id, eof);
|
||||
if (error)
|
||||
return error;
|
||||
goto restart;
|
||||
}
|
||||
}
|
||||
|
||||
dqp->q_nrefs++;
|
||||
mutex_unlock(&qi->qi_tree_lock);
|
||||
|
||||
|
@ -770,6 +851,13 @@ xfs_qm_dqget(
|
|||
if (ip)
|
||||
xfs_ilock(ip, XFS_ILOCK_EXCL);
|
||||
|
||||
/* If we are asked to find next active id, keep looking */
|
||||
if (error == -ENOENT && (flags & XFS_QMOPT_DQNEXT)) {
|
||||
error = xfs_dq_get_next_id(mp, type, &id, eof);
|
||||
if (!error)
|
||||
goto restart;
|
||||
}
|
||||
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
|
@ -820,6 +908,17 @@ xfs_qm_dqget(
|
|||
qi->qi_dquots++;
|
||||
mutex_unlock(&qi->qi_tree_lock);
|
||||
|
||||
/* If we are asked to find next active id, keep looking */
|
||||
if (flags & XFS_QMOPT_DQNEXT) {
|
||||
if (XFS_IS_DQUOT_UNINITIALIZED(dqp)) {
|
||||
xfs_qm_dqput(dqp);
|
||||
error = xfs_dq_get_next_id(mp, type, &id, eof);
|
||||
if (error)
|
||||
return error;
|
||||
goto restart;
|
||||
}
|
||||
}
|
||||
|
||||
dqret:
|
||||
ASSERT((ip == NULL) || xfs_isilocked(ip, XFS_ILOCK_EXCL));
|
||||
trace_xfs_dqget_miss(dqp);
|
||||
|
|
|
@ -1337,31 +1337,31 @@ xfs_find_get_desired_pgoff(
|
|||
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 @@ xfs_seek_hole_data(
|
|||
* 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:
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -560,6 +560,37 @@ xfs_qm_shrink_count(
|
|||
return list_lru_shrink_count(&qi->qi_lru, sc);
|
||||
}
|
||||
|
||||
STATIC void
|
||||
xfs_qm_set_defquota(
|
||||
xfs_mount_t *mp,
|
||||
uint type,
|
||||
xfs_quotainfo_t *qinf)
|
||||
{
|
||||
xfs_dquot_t *dqp;
|
||||
struct xfs_def_quota *defq;
|
||||
int error;
|
||||
|
||||
error = xfs_qm_dqread(mp, 0, type, XFS_QMOPT_DOWARN, &dqp);
|
||||
|
||||
if (!error) {
|
||||
xfs_disk_dquot_t *ddqp = &dqp->q_core;
|
||||
|
||||
defq = xfs_get_defquota(dqp, qinf);
|
||||
|
||||
/*
|
||||
* Timers and warnings have been already set, let's just set the
|
||||
* default limits for this quota type
|
||||
*/
|
||||
defq->bhardlimit = be64_to_cpu(ddqp->d_blk_hardlimit);
|
||||
defq->bsoftlimit = be64_to_cpu(ddqp->d_blk_softlimit);
|
||||
defq->ihardlimit = be64_to_cpu(ddqp->d_ino_hardlimit);
|
||||
defq->isoftlimit = be64_to_cpu(ddqp->d_ino_softlimit);
|
||||
defq->rtbhardlimit = be64_to_cpu(ddqp->d_rtb_hardlimit);
|
||||
defq->rtbsoftlimit = be64_to_cpu(ddqp->d_rtb_softlimit);
|
||||
xfs_qm_dqdestroy(dqp);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This initializes all the quota information that's kept in the
|
||||
* mount structure
|
||||
|
@ -606,19 +637,19 @@ xfs_qm_init_quotainfo(
|
|||
* We try to get the limits from the superuser's limits fields.
|
||||
* This is quite hacky, but it is standard quota practice.
|
||||
*
|
||||
* We look at the USR dquot with id == 0 first, but if user quotas
|
||||
* are not enabled we goto the GRP dquot with id == 0.
|
||||
* We don't really care to keep separate default limits for user
|
||||
* and group quotas, at least not at this point.
|
||||
*
|
||||
* Since we may not have done a quotacheck by this point, just read
|
||||
* the dquot without attaching it to any hashtables or lists.
|
||||
*
|
||||
* Timers and warnings are globally set by the first timer found in
|
||||
* user/group/proj quota types, otherwise a default value is used.
|
||||
* This should be split into different fields per quota type.
|
||||
*/
|
||||
error = xfs_qm_dqread(mp, 0,
|
||||
XFS_IS_UQUOTA_RUNNING(mp) ? XFS_DQ_USER :
|
||||
(XFS_IS_GQUOTA_RUNNING(mp) ? XFS_DQ_GROUP :
|
||||
XFS_DQ_PROJ),
|
||||
XFS_QMOPT_DOWARN, &dqp);
|
||||
|
||||
if (!error) {
|
||||
xfs_disk_dquot_t *ddqp = &dqp->q_core;
|
||||
|
||||
|
@ -639,13 +670,6 @@ xfs_qm_init_quotainfo(
|
|||
be16_to_cpu(ddqp->d_iwarns) : XFS_QM_IWARNLIMIT;
|
||||
qinf->qi_rtbwarnlimit = ddqp->d_rtbwarns ?
|
||||
be16_to_cpu(ddqp->d_rtbwarns) : XFS_QM_RTBWARNLIMIT;
|
||||
qinf->qi_bhardlimit = be64_to_cpu(ddqp->d_blk_hardlimit);
|
||||
qinf->qi_bsoftlimit = be64_to_cpu(ddqp->d_blk_softlimit);
|
||||
qinf->qi_ihardlimit = be64_to_cpu(ddqp->d_ino_hardlimit);
|
||||
qinf->qi_isoftlimit = be64_to_cpu(ddqp->d_ino_softlimit);
|
||||
qinf->qi_rtbhardlimit = be64_to_cpu(ddqp->d_rtb_hardlimit);
|
||||
qinf->qi_rtbsoftlimit = be64_to_cpu(ddqp->d_rtb_softlimit);
|
||||
|
||||
xfs_qm_dqdestroy(dqp);
|
||||
} else {
|
||||
qinf->qi_btimelimit = XFS_QM_BTIMELIMIT;
|
||||
|
@ -656,6 +680,13 @@ xfs_qm_init_quotainfo(
|
|||
qinf->qi_rtbwarnlimit = XFS_QM_RTBWARNLIMIT;
|
||||
}
|
||||
|
||||
if (XFS_IS_UQUOTA_RUNNING(mp))
|
||||
xfs_qm_set_defquota(mp, XFS_DQ_USER, qinf);
|
||||
if (XFS_IS_GQUOTA_RUNNING(mp))
|
||||
xfs_qm_set_defquota(mp, XFS_DQ_GROUP, qinf);
|
||||
if (XFS_IS_PQUOTA_RUNNING(mp))
|
||||
xfs_qm_set_defquota(mp, XFS_DQ_PROJ, qinf);
|
||||
|
||||
qinf->qi_shrinker.count_objects = xfs_qm_shrink_count;
|
||||
qinf->qi_shrinker.scan_objects = xfs_qm_shrink_scan;
|
||||
qinf->qi_shrinker.seeks = DEFAULT_SEEKS;
|
||||
|
|
|
@ -53,6 +53,15 @@ extern struct kmem_zone *xfs_qm_dqtrxzone;
|
|||
*/
|
||||
#define XFS_DQUOT_CLUSTER_SIZE_FSB (xfs_filblks_t)1
|
||||
|
||||
struct xfs_def_quota {
|
||||
xfs_qcnt_t bhardlimit; /* default data blk hard limit */
|
||||
xfs_qcnt_t bsoftlimit; /* default data blk soft limit */
|
||||
xfs_qcnt_t ihardlimit; /* default inode count hard limit */
|
||||
xfs_qcnt_t isoftlimit; /* default inode count soft limit */
|
||||
xfs_qcnt_t rtbhardlimit; /* default realtime blk hard limit */
|
||||
xfs_qcnt_t rtbsoftlimit; /* default realtime blk soft limit */
|
||||
};
|
||||
|
||||
/*
|
||||
* Various quota information for individual filesystems.
|
||||
* The mount structure keeps a pointer to this.
|
||||
|
@ -76,12 +85,9 @@ typedef struct xfs_quotainfo {
|
|||
struct mutex qi_quotaofflock;/* to serialize quotaoff */
|
||||
xfs_filblks_t qi_dqchunklen; /* # BBs in a chunk of dqs */
|
||||
uint qi_dqperchunk; /* # ondisk dqs in above chunk */
|
||||
xfs_qcnt_t qi_bhardlimit; /* default data blk hard limit */
|
||||
xfs_qcnt_t qi_bsoftlimit; /* default data blk soft limit */
|
||||
xfs_qcnt_t qi_ihardlimit; /* default inode count hard limit */
|
||||
xfs_qcnt_t qi_isoftlimit; /* default inode count soft limit */
|
||||
xfs_qcnt_t qi_rtbhardlimit;/* default realtime blk hard limit */
|
||||
xfs_qcnt_t qi_rtbsoftlimit;/* default realtime blk soft limit */
|
||||
struct xfs_def_quota qi_usr_default;
|
||||
struct xfs_def_quota qi_grp_default;
|
||||
struct xfs_def_quota qi_prj_default;
|
||||
struct shrinker qi_shrinker;
|
||||
} xfs_quotainfo_t;
|
||||
|
||||
|
@ -104,15 +110,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);
|
||||
}
|
||||
|
@ -164,11 +170,27 @@ 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 *);
|
||||
extern int xfs_qm_scall_getquota(struct xfs_mount *, xfs_dqid_t *,
|
||||
uint, struct qc_dqblk *, uint);
|
||||
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);
|
||||
extern int xfs_qm_scall_quotaoff(struct xfs_mount *, uint);
|
||||
|
||||
static inline struct xfs_def_quota *
|
||||
xfs_get_defquota(struct xfs_dquot *dqp, struct xfs_quotainfo *qi)
|
||||
{
|
||||
struct xfs_def_quota *defq;
|
||||
|
||||
if (XFS_QM_ISUDQ(dqp))
|
||||
defq = &qi->qi_usr_default;
|
||||
else if (XFS_QM_ISGDQ(dqp))
|
||||
defq = &qi->qi_grp_default;
|
||||
else {
|
||||
ASSERT(XFS_QM_ISPDQ(dqp));
|
||||
defq = &qi->qi_prj_default;
|
||||
}
|
||||
return defq;
|
||||
}
|
||||
|
||||
#endif /* __XFS_QM_H__ */
|
||||
|
|
|
@ -404,6 +404,7 @@ xfs_qm_scall_setqlim(
|
|||
struct xfs_disk_dquot *ddq;
|
||||
struct xfs_dquot *dqp;
|
||||
struct xfs_trans *tp;
|
||||
struct xfs_def_quota *defq;
|
||||
int error;
|
||||
xfs_qcnt_t hard, soft;
|
||||
|
||||
|
@ -431,6 +432,8 @@ xfs_qm_scall_setqlim(
|
|||
ASSERT(error != -ENOENT);
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
defq = xfs_get_defquota(dqp, q);
|
||||
xfs_dqunlock(dqp);
|
||||
|
||||
tp = xfs_trans_alloc(mp, XFS_TRANS_QM_SETQLIM);
|
||||
|
@ -458,8 +461,8 @@ xfs_qm_scall_setqlim(
|
|||
ddq->d_blk_softlimit = cpu_to_be64(soft);
|
||||
xfs_dquot_set_prealloc_limits(dqp);
|
||||
if (id == 0) {
|
||||
q->qi_bhardlimit = hard;
|
||||
q->qi_bsoftlimit = soft;
|
||||
defq->bhardlimit = hard;
|
||||
defq->bsoftlimit = soft;
|
||||
}
|
||||
} else {
|
||||
xfs_debug(mp, "blkhard %Ld < blksoft %Ld", hard, soft);
|
||||
|
@ -474,8 +477,8 @@ xfs_qm_scall_setqlim(
|
|||
ddq->d_rtb_hardlimit = cpu_to_be64(hard);
|
||||
ddq->d_rtb_softlimit = cpu_to_be64(soft);
|
||||
if (id == 0) {
|
||||
q->qi_rtbhardlimit = hard;
|
||||
q->qi_rtbsoftlimit = soft;
|
||||
defq->rtbhardlimit = hard;
|
||||
defq->rtbsoftlimit = soft;
|
||||
}
|
||||
} else {
|
||||
xfs_debug(mp, "rtbhard %Ld < rtbsoft %Ld", hard, soft);
|
||||
|
@ -491,8 +494,8 @@ xfs_qm_scall_setqlim(
|
|||
ddq->d_ino_hardlimit = cpu_to_be64(hard);
|
||||
ddq->d_ino_softlimit = cpu_to_be64(soft);
|
||||
if (id == 0) {
|
||||
q->qi_ihardlimit = hard;
|
||||
q->qi_isoftlimit = soft;
|
||||
defq->ihardlimit = hard;
|
||||
defq->isoftlimit = soft;
|
||||
}
|
||||
} else {
|
||||
xfs_debug(mp, "ihard %Ld < isoft %Ld", hard, soft);
|
||||
|
@ -635,9 +638,10 @@ xfs_qm_log_quotaoff(
|
|||
int
|
||||
xfs_qm_scall_getquota(
|
||||
struct xfs_mount *mp,
|
||||
xfs_dqid_t id,
|
||||
xfs_dqid_t *id,
|
||||
uint type,
|
||||
struct qc_dqblk *dst)
|
||||
struct qc_dqblk *dst,
|
||||
uint dqget_flags)
|
||||
{
|
||||
struct xfs_dquot *dqp;
|
||||
int error;
|
||||
|
@ -647,7 +651,7 @@ xfs_qm_scall_getquota(
|
|||
* 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, dqget_flags, &dqp);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
|
@ -660,6 +664,9 @@ xfs_qm_scall_getquota(
|
|||
goto out_put;
|
||||
}
|
||||
|
||||
/* Fill in the ID we actually read from disk */
|
||||
*id = be32_to_cpu(dqp->q_core.d_id);
|
||||
|
||||
memset(dst, 0, sizeof(*dst));
|
||||
dst->d_spc_hardlimit =
|
||||
XFS_FSB_TO_B(mp, be64_to_cpu(dqp->q_core.d_blk_hardlimit));
|
||||
|
@ -701,7 +708,7 @@ xfs_qm_scall_getquota(
|
|||
if (((XFS_IS_UQUOTA_ENFORCED(mp) && type == XFS_DQ_USER) ||
|
||||
(XFS_IS_GQUOTA_ENFORCED(mp) && type == XFS_DQ_GROUP) ||
|
||||
(XFS_IS_PQUOTA_ENFORCED(mp) && type == XFS_DQ_PROJ)) &&
|
||||
id != 0) {
|
||||
*id != 0) {
|
||||
if ((dst->d_space > dst->d_spc_softlimit) &&
|
||||
(dst->d_spc_softlimit > 0)) {
|
||||
ASSERT(dst->d_spc_timer != 0);
|
||||
|
|
|
@ -231,14 +231,45 @@ xfs_fs_get_dqblk(
|
|||
struct qc_dqblk *qdq)
|
||||
{
|
||||
struct xfs_mount *mp = XFS_M(sb);
|
||||
xfs_dqid_t id;
|
||||
|
||||
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 = from_kqid(&init_user_ns, qid);
|
||||
return xfs_qm_scall_getquota(mp, &id,
|
||||
xfs_quota_type(qid.type), qdq, 0);
|
||||
}
|
||||
|
||||
/* Return quota info for active quota >= this qid */
|
||||
STATIC int
|
||||
xfs_fs_get_nextdqblk(
|
||||
struct super_block *sb,
|
||||
struct kqid *qid,
|
||||
struct qc_dqblk *qdq)
|
||||
{
|
||||
int ret;
|
||||
struct xfs_mount *mp = XFS_M(sb);
|
||||
xfs_dqid_t id;
|
||||
|
||||
if (!XFS_IS_QUOTA_RUNNING(mp))
|
||||
return -ENOSYS;
|
||||
if (!XFS_IS_QUOTA_ON(mp))
|
||||
return -ESRCH;
|
||||
|
||||
id = from_kqid(&init_user_ns, *qid);
|
||||
ret = xfs_qm_scall_getquota(mp, &id,
|
||||
xfs_quota_type(qid->type), qdq,
|
||||
XFS_QMOPT_DQNEXT);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* ID may be different, so convert back what we got */
|
||||
*qid = make_kqid(current_user_ns(), qid->type, id);
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
STATIC int
|
||||
|
@ -267,5 +298,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_nextdqblk = xfs_fs_get_nextdqblk,
|
||||
.set_dqblk = xfs_fs_set_dqblk,
|
||||
};
|
||||
|
|
|
@ -609,17 +609,20 @@ xfs_trans_dqresv(
|
|||
xfs_qcnt_t total_count;
|
||||
xfs_qcnt_t *resbcountp;
|
||||
xfs_quotainfo_t *q = mp->m_quotainfo;
|
||||
struct xfs_def_quota *defq;
|
||||
|
||||
|
||||
xfs_dqlock(dqp);
|
||||
|
||||
defq = xfs_get_defquota(dqp, q);
|
||||
|
||||
if (flags & XFS_TRANS_DQ_RES_BLKS) {
|
||||
hardlimit = be64_to_cpu(dqp->q_core.d_blk_hardlimit);
|
||||
if (!hardlimit)
|
||||
hardlimit = q->qi_bhardlimit;
|
||||
hardlimit = defq->bhardlimit;
|
||||
softlimit = be64_to_cpu(dqp->q_core.d_blk_softlimit);
|
||||
if (!softlimit)
|
||||
softlimit = q->qi_bsoftlimit;
|
||||
softlimit = defq->bsoftlimit;
|
||||
timer = be32_to_cpu(dqp->q_core.d_btimer);
|
||||
warns = be16_to_cpu(dqp->q_core.d_bwarns);
|
||||
warnlimit = dqp->q_mount->m_quotainfo->qi_bwarnlimit;
|
||||
|
@ -628,10 +631,10 @@ xfs_trans_dqresv(
|
|||
ASSERT(flags & XFS_TRANS_DQ_RES_RTBLKS);
|
||||
hardlimit = be64_to_cpu(dqp->q_core.d_rtb_hardlimit);
|
||||
if (!hardlimit)
|
||||
hardlimit = q->qi_rtbhardlimit;
|
||||
hardlimit = defq->rtbhardlimit;
|
||||
softlimit = be64_to_cpu(dqp->q_core.d_rtb_softlimit);
|
||||
if (!softlimit)
|
||||
softlimit = q->qi_rtbsoftlimit;
|
||||
softlimit = defq->rtbsoftlimit;
|
||||
timer = be32_to_cpu(dqp->q_core.d_rtbtimer);
|
||||
warns = be16_to_cpu(dqp->q_core.d_rtbwarns);
|
||||
warnlimit = dqp->q_mount->m_quotainfo->qi_rtbwarnlimit;
|
||||
|
@ -672,10 +675,10 @@ xfs_trans_dqresv(
|
|||
warnlimit = dqp->q_mount->m_quotainfo->qi_iwarnlimit;
|
||||
hardlimit = be64_to_cpu(dqp->q_core.d_ino_hardlimit);
|
||||
if (!hardlimit)
|
||||
hardlimit = q->qi_ihardlimit;
|
||||
hardlimit = defq->ihardlimit;
|
||||
softlimit = be64_to_cpu(dqp->q_core.d_ino_softlimit);
|
||||
if (!softlimit)
|
||||
softlimit = q->qi_isoftlimit;
|
||||
softlimit = defq->isoftlimit;
|
||||
|
||||
if (hardlimit && total_count > hardlimit) {
|
||||
xfs_quota_warn(mp, dqp, QUOTA_NL_IHARDWARN);
|
||||
|
|
|
@ -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_nextdqblk)(struct super_block *, struct kqid *,
|
||||
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);
|
||||
|
|
|
@ -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_XGETNEXTQUOTA XQM_CMD(9) /* get disk limits and usage >= ID */
|
||||
|
||||
/*
|
||||
* fs_disk_quota structure:
|
||||
|
|
|
@ -71,6 +71,7 @@
|
|||
#define Q_SETINFO 0x800006 /* set information about quota files */
|
||||
#define Q_GETQUOTA 0x800007 /* get user quota structure */
|
||||
#define Q_SETQUOTA 0x800008 /* set user quota structure */
|
||||
#define Q_GETNEXTQUOTA 0x800009 /* get disk limits and usage >= ID */
|
||||
|
||||
/* Quota format type IDs */
|
||||
#define QFMT_VFS_OLD 1
|
||||
|
@ -119,6 +120,19 @@ struct if_dqblk {
|
|||
__u32 dqb_valid;
|
||||
};
|
||||
|
||||
struct if_nextdqblk {
|
||||
__u64 dqb_bhardlimit;
|
||||
__u64 dqb_bsoftlimit;
|
||||
__u64 dqb_curspace;
|
||||
__u64 dqb_ihardlimit;
|
||||
__u64 dqb_isoftlimit;
|
||||
__u64 dqb_curinodes;
|
||||
__u64 dqb_btime;
|
||||
__u64 dqb_itime;
|
||||
__u32 dqb_valid;
|
||||
__u32 dqb_id;
|
||||
};
|
||||
|
||||
/*
|
||||
* Structure used for setting quota information about file via quotactl
|
||||
* Following flags are used to specify which fields are valid
|
||||
|
|
Loading…
Reference in New Issue