Skip to content

Commit 92bd85f

Browse files
committed
Merge branch 'xfs-get-next-dquot-4.6' of git://git.kernel.org/pub/scm/linux/kernel/git/dgc/linux-xfs into for_next
2 parents 388f7b1 + be60794 commit 92bd85f

File tree

13 files changed

+394
-86
lines changed

13 files changed

+394
-86
lines changed

fs/quota/quota.c

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ unsigned int qtype_enforce_flag(int type)
7979
return 0;
8080
}
8181

82-
static int quota_quotaon(struct super_block *sb, int type, int cmd, qid_t id,
82+
static int quota_quotaon(struct super_block *sb, int type, qid_t id,
8383
struct path *path)
8484
{
8585
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,
222222
return 0;
223223
}
224224

225+
/*
226+
* Return quota for next active quota >= this id, if any exists,
227+
* otherwise return -ESRCH via ->get_nextdqblk
228+
*/
229+
static int quota_getnextquota(struct super_block *sb, int type, qid_t id,
230+
void __user *addr)
231+
{
232+
struct kqid qid;
233+
struct qc_dqblk fdq;
234+
struct if_nextdqblk idq;
235+
int ret;
236+
237+
if (!sb->s_qcop->get_nextdqblk)
238+
return -ENOSYS;
239+
qid = make_kqid(current_user_ns(), type, id);
240+
if (!qid_valid(qid))
241+
return -EINVAL;
242+
ret = sb->s_qcop->get_nextdqblk(sb, &qid, &fdq);
243+
if (ret)
244+
return ret;
245+
/* struct if_nextdqblk is a superset of struct if_dqblk */
246+
copy_to_if_dqblk((struct if_dqblk *)&idq, &fdq);
247+
idq.dqb_id = from_kqid(current_user_ns(), qid);
248+
if (copy_to_user(addr, &idq, sizeof(idq)))
249+
return -EFAULT;
250+
return 0;
251+
}
252+
225253
static void copy_from_if_dqblk(struct qc_dqblk *dst, struct if_dqblk *src)
226254
{
227255
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,
625653
return ret;
626654
}
627655

656+
/*
657+
* Return quota for next active quota >= this id, if any exists,
658+
* otherwise return -ESRCH via ->get_nextdqblk.
659+
*/
660+
static int quota_getnextxquota(struct super_block *sb, int type, qid_t id,
661+
void __user *addr)
662+
{
663+
struct fs_disk_quota fdq;
664+
struct qc_dqblk qdq;
665+
struct kqid qid;
666+
qid_t id_out;
667+
int ret;
668+
669+
if (!sb->s_qcop->get_nextdqblk)
670+
return -ENOSYS;
671+
qid = make_kqid(current_user_ns(), type, id);
672+
if (!qid_valid(qid))
673+
return -EINVAL;
674+
ret = sb->s_qcop->get_nextdqblk(sb, &qid, &qdq);
675+
if (ret)
676+
return ret;
677+
id_out = from_kqid(current_user_ns(), qid);
678+
copy_to_xfs_dqblk(&fdq, &qdq, type, id_out);
679+
if (copy_to_user(addr, &fdq, sizeof(fdq)))
680+
return -EFAULT;
681+
return ret;
682+
}
683+
628684
static int quota_rmxquota(struct super_block *sb, void __user *addr)
629685
{
630686
__u32 flags;
@@ -659,7 +715,7 @@ static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id,
659715

660716
switch (cmd) {
661717
case Q_QUOTAON:
662-
return quota_quotaon(sb, type, cmd, id, path);
718+
return quota_quotaon(sb, type, id, path);
663719
case Q_QUOTAOFF:
664720
return quota_quotaoff(sb, type);
665721
case Q_GETFMT:
@@ -670,6 +726,8 @@ static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id,
670726
return quota_setinfo(sb, type, addr);
671727
case Q_GETQUOTA:
672728
return quota_getquota(sb, type, id, addr);
729+
case Q_GETNEXTQUOTA:
730+
return quota_getnextquota(sb, type, id, addr);
673731
case Q_SETQUOTA:
674732
return quota_setquota(sb, type, id, addr);
675733
case Q_SYNC:
@@ -690,6 +748,8 @@ static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id,
690748
return quota_setxquota(sb, type, id, addr);
691749
case Q_XGETQUOTA:
692750
return quota_getxquota(sb, type, id, addr);
751+
case Q_XGETNEXTQUOTA:
752+
return quota_getnextxquota(sb, type, id, addr);
693753
case Q_XQUOTASYNC:
694754
if (sb->s_flags & MS_RDONLY)
695755
return -EROFS;
@@ -708,10 +768,12 @@ static int quotactl_cmd_write(int cmd)
708768
switch (cmd) {
709769
case Q_GETFMT:
710770
case Q_GETINFO:
771+
case Q_GETNEXTQUOTA:
711772
case Q_SYNC:
712773
case Q_XGETQSTAT:
713774
case Q_XGETQSTATV:
714775
case Q_XGETQUOTA:
776+
case Q_XGETNEXTQUOTA:
715777
case Q_XQUOTASYNC:
716778
return 0;
717779
}

fs/xfs/libxfs/xfs_quota_defs.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ typedef __uint16_t xfs_qwarncnt_t;
3737
#define XFS_DQ_PROJ 0x0002 /* project quota */
3838
#define XFS_DQ_GROUP 0x0004 /* a group quota */
3939
#define XFS_DQ_DIRTY 0x0008 /* dquot is dirty */
40-
#define XFS_DQ_FREEING 0x0010 /* dquot is beeing torn down */
40+
#define XFS_DQ_FREEING 0x0010 /* dquot is being torn down */
4141

4242
#define XFS_DQ_ALLTYPES (XFS_DQ_USER|XFS_DQ_PROJ|XFS_DQ_GROUP)
4343

@@ -116,6 +116,7 @@ typedef __uint16_t xfs_qwarncnt_t;
116116
#define XFS_QMOPT_DQREPAIR 0x0001000 /* repair dquot if damaged */
117117
#define XFS_QMOPT_GQUOTA 0x0002000 /* group dquot requested */
118118
#define XFS_QMOPT_ENOSPC 0x0004000 /* enospc instead of edquot (prj) */
119+
#define XFS_QMOPT_DQNEXT 0x0008000 /* return next dquot >= this ID */
119120

120121
/*
121122
* flags to xfs_trans_mod_dquot to indicate which field needs to be

fs/xfs/xfs_dquot.c

Lines changed: 114 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -92,26 +92,28 @@ xfs_qm_adjust_dqlimits(
9292
{
9393
struct xfs_quotainfo *q = mp->m_quotainfo;
9494
struct xfs_disk_dquot *d = &dq->q_core;
95+
struct xfs_def_quota *defq;
9596
int prealloc = 0;
9697

9798
ASSERT(d->d_id);
99+
defq = xfs_get_defquota(dq, q);
98100

99-
if (q->qi_bsoftlimit && !d->d_blk_softlimit) {
100-
d->d_blk_softlimit = cpu_to_be64(q->qi_bsoftlimit);
101+
if (defq->bsoftlimit && !d->d_blk_softlimit) {
102+
d->d_blk_softlimit = cpu_to_be64(defq->bsoftlimit);
101103
prealloc = 1;
102104
}
103-
if (q->qi_bhardlimit && !d->d_blk_hardlimit) {
104-
d->d_blk_hardlimit = cpu_to_be64(q->qi_bhardlimit);
105+
if (defq->bhardlimit && !d->d_blk_hardlimit) {
106+
d->d_blk_hardlimit = cpu_to_be64(defq->bhardlimit);
105107
prealloc = 1;
106108
}
107-
if (q->qi_isoftlimit && !d->d_ino_softlimit)
108-
d->d_ino_softlimit = cpu_to_be64(q->qi_isoftlimit);
109-
if (q->qi_ihardlimit && !d->d_ino_hardlimit)
110-
d->d_ino_hardlimit = cpu_to_be64(q->qi_ihardlimit);
111-
if (q->qi_rtbsoftlimit && !d->d_rtb_softlimit)
112-
d->d_rtb_softlimit = cpu_to_be64(q->qi_rtbsoftlimit);
113-
if (q->qi_rtbhardlimit && !d->d_rtb_hardlimit)
114-
d->d_rtb_hardlimit = cpu_to_be64(q->qi_rtbhardlimit);
109+
if (defq->isoftlimit && !d->d_ino_softlimit)
110+
d->d_ino_softlimit = cpu_to_be64(defq->isoftlimit);
111+
if (defq->ihardlimit && !d->d_ino_hardlimit)
112+
d->d_ino_hardlimit = cpu_to_be64(defq->ihardlimit);
113+
if (defq->rtbsoftlimit && !d->d_rtb_softlimit)
114+
d->d_rtb_softlimit = cpu_to_be64(defq->rtbsoftlimit);
115+
if (defq->rtbhardlimit && !d->d_rtb_hardlimit)
116+
d->d_rtb_hardlimit = cpu_to_be64(defq->rtbhardlimit);
115117

116118
if (prealloc)
117119
xfs_dquot_set_prealloc_limits(dq);
@@ -232,7 +234,8 @@ xfs_qm_init_dquot_blk(
232234
{
233235
struct xfs_quotainfo *q = mp->m_quotainfo;
234236
xfs_dqblk_t *d;
235-
int curid, i;
237+
xfs_dqid_t curid;
238+
int i;
236239

237240
ASSERT(tp);
238241
ASSERT(xfs_buf_islocked(bp));
@@ -243,7 +246,6 @@ xfs_qm_init_dquot_blk(
243246
* ID of the first dquot in the block - id's are zero based.
244247
*/
245248
curid = id - (id % q->qi_dqperchunk);
246-
ASSERT(curid >= 0);
247249
memset(d, 0, BBTOB(q->qi_dqchunklen));
248250
for (i = 0; i < q->qi_dqperchunk; i++, d++, curid++) {
249251
d->dd_diskdq.d_magic = cpu_to_be16(XFS_DQUOT_MAGIC);
@@ -464,12 +466,13 @@ xfs_qm_dqtobp(
464466
struct xfs_bmbt_irec map;
465467
int nmaps = 1, error;
466468
struct xfs_buf *bp;
467-
struct xfs_inode *quotip = xfs_dq_to_quota_inode(dqp);
469+
struct xfs_inode *quotip;
468470
struct xfs_mount *mp = dqp->q_mount;
469471
xfs_dqid_t id = be32_to_cpu(dqp->q_core.d_id);
470472
struct xfs_trans *tp = (tpp ? *tpp : NULL);
471473
uint lock_mode;
472474

475+
quotip = xfs_quota_inode(dqp->q_mount, dqp->dq_flags);
473476
dqp->q_fileoffset = (xfs_fileoff_t)id / mp->m_quotainfo->qi_dqperchunk;
474477

475478
lock_mode = xfs_ilock_data_map_shared(quotip);
@@ -684,6 +687,56 @@ xfs_qm_dqread(
684687
return error;
685688
}
686689

690+
/*
691+
* Advance to the next id in the current chunk, or if at the
692+
* end of the chunk, skip ahead to first id in next allocated chunk
693+
* using the SEEK_DATA interface.
694+
*/
695+
int
696+
xfs_dq_get_next_id(
697+
xfs_mount_t *mp,
698+
uint type,
699+
xfs_dqid_t *id,
700+
loff_t eof)
701+
{
702+
struct xfs_inode *quotip;
703+
xfs_fsblock_t start;
704+
loff_t offset;
705+
uint lock;
706+
xfs_dqid_t next_id;
707+
int error = 0;
708+
709+
/* Simple advance */
710+
next_id = *id + 1;
711+
712+
/* If new ID is within the current chunk, advancing it sufficed */
713+
if (next_id % mp->m_quotainfo->qi_dqperchunk) {
714+
*id = next_id;
715+
return 0;
716+
}
717+
718+
/* Nope, next_id is now past the current chunk, so find the next one */
719+
start = (xfs_fsblock_t)next_id / mp->m_quotainfo->qi_dqperchunk;
720+
721+
quotip = xfs_quota_inode(mp, type);
722+
lock = xfs_ilock_data_map_shared(quotip);
723+
724+
offset = __xfs_seek_hole_data(VFS_I(quotip), XFS_FSB_TO_B(mp, start),
725+
eof, SEEK_DATA);
726+
if (offset < 0)
727+
error = offset;
728+
729+
xfs_iunlock(quotip, lock);
730+
731+
/* -ENXIO is essentially "no more data" */
732+
if (error)
733+
return (error == -ENXIO ? -ENOENT: error);
734+
735+
/* Convert next data offset back to a quota id */
736+
*id = XFS_B_TO_FSB(mp, offset) * mp->m_quotainfo->qi_dqperchunk;
737+
return 0;
738+
}
739+
687740
/*
688741
* Given the file system, inode OR id, and type (UDQUOT/GDQUOT), return a
689742
* a locked dquot, doing an allocation (if requested) as needed.
@@ -704,6 +757,7 @@ xfs_qm_dqget(
704757
struct xfs_quotainfo *qi = mp->m_quotainfo;
705758
struct radix_tree_root *tree = xfs_dquot_tree(qi, type);
706759
struct xfs_dquot *dqp;
760+
loff_t eof = 0;
707761
int error;
708762

709763
ASSERT(XFS_IS_QUOTA_RUNNING(mp));
@@ -731,6 +785,21 @@ xfs_qm_dqget(
731785
}
732786
#endif
733787

788+
/* Get the end of the quota file if we need it */
789+
if (flags & XFS_QMOPT_DQNEXT) {
790+
struct xfs_inode *quotip;
791+
xfs_fileoff_t last;
792+
uint lock_mode;
793+
794+
quotip = xfs_quota_inode(mp, type);
795+
lock_mode = xfs_ilock_data_map_shared(quotip);
796+
error = xfs_bmap_last_offset(quotip, &last, XFS_DATA_FORK);
797+
xfs_iunlock(quotip, lock_mode);
798+
if (error)
799+
return error;
800+
eof = XFS_FSB_TO_B(mp, last);
801+
}
802+
734803
restart:
735804
mutex_lock(&qi->qi_tree_lock);
736805
dqp = radix_tree_lookup(tree, id);
@@ -744,6 +813,18 @@ xfs_qm_dqget(
744813
goto restart;
745814
}
746815

816+
/* uninit / unused quota found in radix tree, keep looking */
817+
if (flags & XFS_QMOPT_DQNEXT) {
818+
if (XFS_IS_DQUOT_UNINITIALIZED(dqp)) {
819+
xfs_dqunlock(dqp);
820+
mutex_unlock(&qi->qi_tree_lock);
821+
error = xfs_dq_get_next_id(mp, type, &id, eof);
822+
if (error)
823+
return error;
824+
goto restart;
825+
}
826+
}
827+
747828
dqp->q_nrefs++;
748829
mutex_unlock(&qi->qi_tree_lock);
749830

@@ -770,6 +851,13 @@ xfs_qm_dqget(
770851
if (ip)
771852
xfs_ilock(ip, XFS_ILOCK_EXCL);
772853

854+
/* If we are asked to find next active id, keep looking */
855+
if (error == -ENOENT && (flags & XFS_QMOPT_DQNEXT)) {
856+
error = xfs_dq_get_next_id(mp, type, &id, eof);
857+
if (!error)
858+
goto restart;
859+
}
860+
773861
if (error)
774862
return error;
775863

@@ -820,6 +908,17 @@ xfs_qm_dqget(
820908
qi->qi_dquots++;
821909
mutex_unlock(&qi->qi_tree_lock);
822910

911+
/* If we are asked to find next active id, keep looking */
912+
if (flags & XFS_QMOPT_DQNEXT) {
913+
if (XFS_IS_DQUOT_UNINITIALIZED(dqp)) {
914+
xfs_qm_dqput(dqp);
915+
error = xfs_dq_get_next_id(mp, type, &id, eof);
916+
if (error)
917+
return error;
918+
goto restart;
919+
}
920+
}
921+
823922
dqret:
824923
ASSERT((ip == NULL) || xfs_isilocked(ip, XFS_ILOCK_EXCL));
825924
trace_xfs_dqget_miss(dqp);

0 commit comments

Comments
 (0)