[Cluster-devel] [PATCH 0/8 v6] quota: Unify VFS and XFS quota interfaces

2015-03-04 Thread Jan Kara
  Hello,

  these are outstanding patches in my series unifying VFS and XFS quota
interfaces so that XFS quotactls work for filesystems with VFS quotas and vice
versa.  This is useful so that userspace doesn't have to care that much about
which filesystem it is using at least when using basic quota functionality. In
particular we should be able to reuse project quota tests in xfstests for ext4.

The patches are based on top of Linus' tree from today which already contains
initial part of the original series.  The patch series can also be pulled from
'quota_interface' branch of my tree [1].

Since all the patches (except one quota patch) have Reviewed-by tags, I'll
push the patches to my tree in a few days and will send them to Linus for the
next merge window unless someone objects.

Honza

[1] git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs.git



[Cluster-devel] [PATCH 8/8] quota: Hook up Q_XSETQLIM for id 0 to -set_info

2015-03-04 Thread Jan Kara
Setting timers or warning counts for id 0 via Q_XSETQLIM is used to
actually set time limits and warning limits for all users. Hook up
-set_info to this so that VFS quota time limits get set the same
way as XFS ones.

When doing this Q_XSETQLIM for XFS is effectively split into two
independent transactions - one for setting timers and warning limits and
one for setting space and inode limits. Although this is inefficient, it
is rare enough that it does not matter.

Reviewed-by: Christoph Hellwig h...@lst.de
Signed-off-by: Jan Kara j...@suse.cz
---
 fs/quota/quota.c | 39 +++
 1 file changed, 39 insertions(+)

diff --git a/fs/quota/quota.c b/fs/quota/quota.c
index 741d5a178268..86ded7375c21 100644
--- a/fs/quota/quota.c
+++ b/fs/quota/quota.c
@@ -517,6 +517,30 @@ static void copy_from_xfs_dqblk(struct qc_dqblk *dst, 
struct fs_disk_quota *src)
dst-d_fieldmask |= QC_RT_SPACE;
 }
 
+static void copy_qcinfo_from_xfs_dqblk(struct qc_info *dst,
+  struct fs_disk_quota *src)
+{
+   memset(dst, 0, sizeof(*dst));
+   dst-i_spc_timelimit = src-d_btimer;
+   dst-i_ino_timelimit = src-d_itimer;
+   dst-i_rt_spc_timelimit = src-d_rtbtimer;
+   dst-i_ino_warnlimit = src-d_iwarns;
+   dst-i_spc_warnlimit = src-d_bwarns;
+   dst-i_rt_spc_warnlimit = src-d_rtbwarns;
+   if (src-d_fieldmask  FS_DQ_BWARNS)
+   dst-i_fieldmask |= QC_SPC_WARNS;
+   if (src-d_fieldmask  FS_DQ_IWARNS)
+   dst-i_fieldmask |= QC_INO_WARNS;
+   if (src-d_fieldmask  FS_DQ_RTBWARNS)
+   dst-i_fieldmask |= QC_RT_SPC_WARNS;
+   if (src-d_fieldmask  FS_DQ_BTIMER)
+   dst-i_fieldmask |= QC_SPC_TIMER;
+   if (src-d_fieldmask  FS_DQ_ITIMER)
+   dst-i_fieldmask |= QC_INO_TIMER;
+   if (src-d_fieldmask  FS_DQ_RTBTIMER)
+   dst-i_fieldmask |= QC_RT_SPC_TIMER;
+}
+
 static int quota_setxquota(struct super_block *sb, int type, qid_t id,
   void __user *addr)
 {
@@ -531,6 +555,21 @@ static int quota_setxquota(struct super_block *sb, int 
type, qid_t id,
qid = make_kqid(current_user_ns(), type, id);
if (!qid_valid(qid))
return -EINVAL;
+   /* Are we actually setting timer / warning limits for all users? */
+   if (from_kqid(init_user_ns, qid) == 0 
+   fdq.d_fieldmask  (FS_DQ_WARNS_MASK | FS_DQ_TIMER_MASK)) {
+   struct qc_info qinfo;
+   int ret;
+
+   if (!sb-s_qcop-set_info)
+   return -EINVAL;
+   copy_qcinfo_from_xfs_dqblk(qinfo, fdq);
+   ret = sb-s_qcop-set_info(sb, type, qinfo);
+   if (ret)
+   return ret;
+   /* These are already done */
+   fdq.d_fieldmask = ~(FS_DQ_WARNS_MASK | FS_DQ_TIMER_MASK);
+   }
copy_from_xfs_dqblk(qdq, fdq);
return sb-s_qcop-set_dqblk(sb, qid, qdq);
 }
-- 
2.1.4



[Cluster-devel] [PATCH 3/8] xfs: Convert to using -get_state callback

2015-03-04 Thread Jan Kara
Convert xfs to use -get_state callback instead of -get_xstate and
-get_xstatev.

Reviewed-by: Christoph Hellwig h...@lst.de
Signed-off-by: Jan Kara j...@suse.cz
---
 fs/xfs/xfs_qm.h  |   4 --
 fs/xfs/xfs_qm_syscalls.c | 176 ---
 fs/xfs/xfs_quotaops.c|  96 +++---
 3 files changed, 71 insertions(+), 205 deletions(-)

diff --git a/fs/xfs/xfs_qm.h b/fs/xfs/xfs_qm.h
index 0d4d3590cf85..996a04064894 100644
--- a/fs/xfs/xfs_qm.h
+++ b/fs/xfs/xfs_qm.h
@@ -168,10 +168,6 @@ extern int xfs_qm_scall_getquota(struct xfs_mount 
*, xfs_dqid_t,
uint, struct qc_dqblk *);
 extern int xfs_qm_scall_setqlim(struct xfs_mount *, xfs_dqid_t, 
uint,
struct qc_dqblk *);
-extern int xfs_qm_scall_getqstat(struct xfs_mount *,
-   struct fs_quota_stat *);
-extern int xfs_qm_scall_getqstatv(struct xfs_mount *,
-   struct fs_quota_statv *);
 extern int xfs_qm_scall_quotaon(struct xfs_mount *, uint);
 extern int xfs_qm_scall_quotaoff(struct xfs_mount *, uint);
 
diff --git a/fs/xfs/xfs_qm_syscalls.c b/fs/xfs/xfs_qm_syscalls.c
index 9b965db45800..9a25c9275fb3 100644
--- a/fs/xfs/xfs_qm_syscalls.c
+++ b/fs/xfs/xfs_qm_syscalls.c
@@ -38,7 +38,6 @@
 STATIC int xfs_qm_log_quotaoff(xfs_mount_t *, xfs_qoff_logitem_t **, uint);
 STATIC int xfs_qm_log_quotaoff_end(xfs_mount_t *, xfs_qoff_logitem_t *,
uint);
-STATIC uintxfs_qm_export_flags(uint);
 
 /*
  * Turn off quota accounting and/or enforcement for all udquots and/or
@@ -389,159 +388,6 @@ xfs_qm_scall_quotaon(
return 0;
 }
 
-
-/*
- * Return quota status information, such as uquota-off, enforcements, etc.
- * for Q_XGETQSTAT command.
- */
-int
-xfs_qm_scall_getqstat(
-   struct xfs_mount*mp,
-   struct fs_quota_stat*out)
-{
-   struct xfs_quotainfo*q = mp-m_quotainfo;
-   struct xfs_inode*uip = NULL;
-   struct xfs_inode*gip = NULL;
-   struct xfs_inode*pip = NULL;
-   booltempuqip = false;
-   booltempgqip = false;
-   booltemppqip = false;
-
-   memset(out, 0, sizeof(fs_quota_stat_t));
-
-   out-qs_version = FS_QSTAT_VERSION;
-   out-qs_flags = (__uint16_t) xfs_qm_export_flags(mp-m_qflags 
-   (XFS_ALL_QUOTA_ACCT|
-XFS_ALL_QUOTA_ENFD));
-   uip = q-qi_uquotaip;
-   gip = q-qi_gquotaip;
-   pip = q-qi_pquotaip;
-   if (!uip  mp-m_sb.sb_uquotino != NULLFSINO) {
-   if (xfs_iget(mp, NULL, mp-m_sb.sb_uquotino,
-   0, 0, uip) == 0)
-   tempuqip = true;
-   }
-   if (!gip  mp-m_sb.sb_gquotino != NULLFSINO) {
-   if (xfs_iget(mp, NULL, mp-m_sb.sb_gquotino,
-   0, 0, gip) == 0)
-   tempgqip = true;
-   }
-   /*
-* Q_XGETQSTAT doesn't have room for both group and project quotas.
-* So, allow the project quota values to be copied out only if
-* there is no group quota information available.
-*/
-   if (!gip) {
-   if (!pip  mp-m_sb.sb_pquotino != NULLFSINO) {
-   if (xfs_iget(mp, NULL, mp-m_sb.sb_pquotino,
-   0, 0, pip) == 0)
-   temppqip = true;
-   }
-   } else
-   pip = NULL;
-   if (uip) {
-   out-qs_uquota.qfs_ino = mp-m_sb.sb_uquotino;
-   out-qs_uquota.qfs_nblks = uip-i_d.di_nblocks;
-   out-qs_uquota.qfs_nextents = uip-i_d.di_nextents;
-   if (tempuqip)
-   IRELE(uip);
-   }
-
-   if (gip) {
-   out-qs_gquota.qfs_ino = mp-m_sb.sb_gquotino;
-   out-qs_gquota.qfs_nblks = gip-i_d.di_nblocks;
-   out-qs_gquota.qfs_nextents = gip-i_d.di_nextents;
-   if (tempgqip)
-   IRELE(gip);
-   }
-   if (pip) {
-   out-qs_gquota.qfs_ino = mp-m_sb.sb_gquotino;
-   out-qs_gquota.qfs_nblks = pip-i_d.di_nblocks;
-   out-qs_gquota.qfs_nextents = pip-i_d.di_nextents;
-   if (temppqip)
-   IRELE(pip);
-   }
-   out-qs_incoredqs = q-qi_dquots;
-   out-qs_btimelimit = q-qi_btimelimit;
-   out-qs_itimelimit = q-qi_itimelimit;
-   out-qs_rtbtimelimit = q-qi_rtbtimelimit;
-   out-qs_bwarnlimit = q-qi_bwarnlimit;
-   out-qs_iwarnlimit = q-qi_iwarnlimit;
-
-   return 0;
-}
-
-/*
- * Return quota status information, such as uquota-off, 

[Cluster-devel] [PATCH 4/8] gfs2: Convert to using -get_state callback

2015-03-04 Thread Jan Kara
Convert gfs2 to use -get_state callback instead of -get_xstate.

Acked-by: Bob Peterson rpete...@redhat.com
Signed-off-by: Jan Kara j...@suse.cz
---
 fs/gfs2/quota.c | 28 +++-
 1 file changed, 15 insertions(+), 13 deletions(-)

diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c
index 3aa17d4d1cfc..fa54cbf4c866 100644
--- a/fs/gfs2/quota.c
+++ b/fs/gfs2/quota.c
@@ -1468,32 +1468,34 @@ int gfs2_quotad(void *data)
return 0;
 }
 
-static int gfs2_quota_get_xstate(struct super_block *sb,
-struct fs_quota_stat *fqs)
+static int gfs2_quota_get_state(struct super_block *sb, struct qc_state *state)
 {
struct gfs2_sbd *sdp = sb-s_fs_info;
 
-   memset(fqs, 0, sizeof(struct fs_quota_stat));
-   fqs-qs_version = FS_QSTAT_VERSION;
+   memset(state, 0, sizeof(*state));
 
switch (sdp-sd_args.ar_quota) {
case GFS2_QUOTA_ON:
-   fqs-qs_flags |= (FS_QUOTA_UDQ_ENFD | FS_QUOTA_GDQ_ENFD);
+   state-s_state[USRQUOTA].flags |= QCI_LIMITS_ENFORCED;
+   state-s_state[GRPQUOTA].flags |= QCI_LIMITS_ENFORCED;
/*FALLTHRU*/
case GFS2_QUOTA_ACCOUNT:
-   fqs-qs_flags |= (FS_QUOTA_UDQ_ACCT | FS_QUOTA_GDQ_ACCT);
+   state-s_state[USRQUOTA].flags |= QCI_ACCT_ENABLED |
+ QCI_SYSFILE;
+   state-s_state[GRPQUOTA].flags |= QCI_ACCT_ENABLED |
+ QCI_SYSFILE;
break;
case GFS2_QUOTA_OFF:
break;
}
-
if (sdp-sd_quota_inode) {
-   fqs-qs_uquota.qfs_ino = GFS2_I(sdp-sd_quota_inode)-i_no_addr;
-   fqs-qs_uquota.qfs_nblks = sdp-sd_quota_inode-i_blocks;
+   state-s_state[USRQUOTA].ino =
+   GFS2_I(sdp-sd_quota_inode)-i_no_addr;
+   state-s_state[USRQUOTA].blocks = sdp-sd_quota_inode-i_blocks;
}
-   fqs-qs_uquota.qfs_nextents = 1; /* unsupported */
-   fqs-qs_gquota = fqs-qs_uquota; /* its the same inode in both cases */
-   fqs-qs_incoredqs = list_lru_count(gfs2_qd_lru);
+   state-s_state[USRQUOTA].nextents = 1;  /* unsupported */
+   state-s_state[GRPQUOTA] = state-s_state[USRQUOTA];
+   state-s_incoredqs = list_lru_count(gfs2_qd_lru);
return 0;
 }
 
@@ -1638,7 +1640,7 @@ out_put:
 
 const struct quotactl_ops gfs2_quotactl_ops = {
.quota_sync = gfs2_quota_sync,
-   .get_xstate = gfs2_quota_get_xstate,
+   .get_state  = gfs2_quota_get_state,
.get_dqblk  = gfs2_get_dqblk,
.set_dqblk  = gfs2_set_dqblk,
 };
-- 
2.1.4



[Cluster-devel] [PATCH 2/8] quota: Wire up Q_GETXSTATE and Q_GETXSTATV calls to work with -get_state

2015-03-04 Thread Jan Kara
Add appropriate conversion functions so that filesystems supporting
-get_state() method can be queried using Q_GETXSTATE and Q_GETXSTATV
calls.

Reviewed-by: Christoph Hellwig h...@lst.de
Signed-off-by: Jan Kara j...@suse.cz
---
 fs/quota/quota.c | 138 +--
 1 file changed, 134 insertions(+), 4 deletions(-)

diff --git a/fs/quota/quota.c b/fs/quota/quota.c
index 00d50fca1005..83939ff4c444 100644
--- a/fs/quota/quota.c
+++ b/fs/quota/quota.c
@@ -269,25 +269,152 @@ static int quota_disable(struct super_block *sb, void 
__user *addr)
return sb-s_qcop-quota_disable(sb, flags);
 }
 
+static int quota_state_to_flags(struct qc_state *state)
+{
+   int flags = 0;
+
+   if (state-s_state[USRQUOTA].flags  QCI_ACCT_ENABLED)
+   flags |= FS_QUOTA_UDQ_ACCT;
+   if (state-s_state[USRQUOTA].flags  QCI_LIMITS_ENFORCED)
+   flags |= FS_QUOTA_UDQ_ENFD;
+   if (state-s_state[GRPQUOTA].flags  QCI_ACCT_ENABLED)
+   flags |= FS_QUOTA_GDQ_ACCT;
+   if (state-s_state[GRPQUOTA].flags  QCI_LIMITS_ENFORCED)
+   flags |= FS_QUOTA_GDQ_ENFD;
+   if (state-s_state[PRJQUOTA].flags  QCI_ACCT_ENABLED)
+   flags |= FS_QUOTA_PDQ_ACCT;
+   if (state-s_state[PRJQUOTA].flags  QCI_LIMITS_ENFORCED)
+   flags |= FS_QUOTA_PDQ_ENFD;
+   return flags;
+}
+
+static int quota_getstate(struct super_block *sb, struct fs_quota_stat *fqs)
+{
+   int type;
+   struct qc_state state;
+   int ret;
+
+   ret = sb-s_qcop-get_state(sb, state);
+   if (ret  0)
+   return ret;
+
+   memset(fqs, 0, sizeof(*fqs));
+   fqs-qs_version = FS_QSTAT_VERSION;
+   fqs-qs_flags = quota_state_to_flags(state);
+   /* No quota enabled? */
+   if (!fqs-qs_flags)
+   return -ENOSYS;
+   fqs-qs_incoredqs = state.s_incoredqs;
+   /*
+* GETXSTATE quotactl has space for just one set of time limits so
+* report them for the first enabled quota type
+*/
+   for (type = 0; type  XQM_MAXQUOTAS; type++)
+   if (state.s_state[type].flags  QCI_ACCT_ENABLED)
+   break;
+   BUG_ON(type == XQM_MAXQUOTAS);
+   fqs-qs_btimelimit = state.s_state[type].spc_timelimit;
+   fqs-qs_itimelimit = state.s_state[type].ino_timelimit;
+   fqs-qs_rtbtimelimit = state.s_state[type].rt_spc_timelimit;
+   fqs-qs_bwarnlimit = state.s_state[type].spc_warnlimit;
+   fqs-qs_iwarnlimit = state.s_state[type].ino_warnlimit;
+   if (state.s_state[USRQUOTA].flags  QCI_ACCT_ENABLED) {
+   fqs-qs_uquota.qfs_ino = state.s_state[USRQUOTA].ino;
+   fqs-qs_uquota.qfs_nblks = state.s_state[USRQUOTA].blocks;
+   fqs-qs_uquota.qfs_nextents = state.s_state[USRQUOTA].nextents;
+   }
+   if (state.s_state[GRPQUOTA].flags  QCI_ACCT_ENABLED) {
+   fqs-qs_gquota.qfs_ino = state.s_state[GRPQUOTA].ino;
+   fqs-qs_gquota.qfs_nblks = state.s_state[GRPQUOTA].blocks;
+   fqs-qs_gquota.qfs_nextents = state.s_state[GRPQUOTA].nextents;
+   }
+   if (state.s_state[PRJQUOTA].flags  QCI_ACCT_ENABLED) {
+   /*
+* Q_XGETQSTAT doesn't have room for both group and project
+* quotas.  So, allow the project quota values to be copied out
+* only if there is no group quota information available.
+*/
+   if (!(state.s_state[GRPQUOTA].flags  QCI_ACCT_ENABLED)) {
+   fqs-qs_gquota.qfs_ino = state.s_state[PRJQUOTA].ino;
+   fqs-qs_gquota.qfs_nblks =
+   state.s_state[PRJQUOTA].blocks;
+   fqs-qs_gquota.qfs_nextents =
+   state.s_state[PRJQUOTA].nextents;
+   }
+   }
+   return 0;
+}
+
 static int quota_getxstate(struct super_block *sb, void __user *addr)
 {
struct fs_quota_stat fqs;
int ret;
 
-   if (!sb-s_qcop-get_xstate)
+   if (!sb-s_qcop-get_xstate  !sb-s_qcop-get_state)
return -ENOSYS;
-   ret = sb-s_qcop-get_xstate(sb, fqs);
+   if (sb-s_qcop-get_state)
+   ret = quota_getstate(sb, fqs);
+   else
+   ret = sb-s_qcop-get_xstate(sb, fqs);
if (!ret  copy_to_user(addr, fqs, sizeof(fqs)))
return -EFAULT;
return ret;
 }
 
+static int quota_getstatev(struct super_block *sb, struct fs_quota_statv *fqs)
+{
+   int type;
+   struct qc_state state;
+   int ret;
+
+   ret = sb-s_qcop-get_state(sb, state);
+   if (ret  0)
+   return ret;
+
+   memset(fqs, 0, sizeof(*fqs));
+   fqs-qs_version = FS_QSTAT_VERSION;
+   fqs-qs_flags = quota_state_to_flags(state);
+   /* No quota enabled? */
+   if (!fqs-qs_flags)
+   return -ENOSYS;
+   fqs-qs_incoredqs = 

[Cluster-devel] [PATCH] fsck.gfs2: Fetch directory inodes early in pass2()

2015-03-04 Thread Andrew Price
pass2() reads directory inodes twice: once indirectly through
check_dir() and again shortly afterwards to perform other checks on the
inode. To remove the duplicate reads, this patch moves the inode loading
outside of check_dir() and keeps it around for the further checks. In
order to avoid adding a fsck_inode_put() at each return point, and to
remove some levels of nesting, the directory checking has been moved
into a new pass2_check_dir() function which accepts the inode as an
argument. pass2() now fetches the inode, calls pass2_check_dir() and
then puts the inode. The patch also adds failure checking for the
fsck_load_inode() calls.

Resolves: rhbz#1154726

Signed-off-by: Andrew Price anpr...@redhat.com
---
 gfs2/fsck/metawalk.c |  17 ++--
 gfs2/fsck/metawalk.h |   2 +-
 gfs2/fsck/pass2.c| 243 ++-
 3 files changed, 136 insertions(+), 126 deletions(-)

diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c
index 90127d3..6daaf9f 100644
--- a/gfs2/fsck/metawalk.c
+++ b/gfs2/fsck/metawalk.c
@@ -1697,14 +1697,11 @@ int check_linear_dir(struct gfs2_inode *ip, struct 
gfs2_buffer_head *bh,
return error;
 }
 
-int check_dir(struct gfs2_sbd *sdp, uint64_t block, struct metawalk_fxns *pass)
+int check_dir(struct gfs2_sbd *sdp, struct gfs2_inode *ip, struct 
metawalk_fxns *pass)
 {
-   struct gfs2_inode *ip;
int error = 0;
struct alloc_state as;
 
-   ip = fsck_load_inode(sdp, block);
-
astate_save(ip, as);
 
if (ip-i_di.di_flags  GFS2_DIF_EXHASH)
@@ -1718,7 +1715,6 @@ int check_dir(struct gfs2_sbd *sdp, uint64_t block, 
struct metawalk_fxns *pass)
if (astate_changed(ip, as))
reprocess_inode(ip, _(Current));
 
-   fsck_inode_put(ip); /* does a brelse */
return error;
 }
 
@@ -1750,6 +1746,7 @@ int remove_dentry_from_dir(struct gfs2_sbd *sdp, uint64_t 
dir,
   uint64_t dentryblock)
 {
struct metawalk_fxns remove_dentry_fxns = {0};
+   struct gfs2_inode *ip;
uint8_t q;
int error;
 
@@ -1769,10 +1766,16 @@ int remove_dentry_from_dir(struct gfs2_sbd *sdp, 
uint64_t dir,
log_info( _(Parent block is not an inode...ignoring\n));
return 1;
}
+
+   ip = fsck_load_inode(sdp, dir);
+   if (ip == NULL) {
+   stack;
+   return -1;
+   }
/* Need to run check_dir with a private var of dentryblock,
 * and fxns that remove that dentry if found */
-   error = check_dir(sdp, dir, remove_dentry_fxns);
-
+   error = check_dir(sdp, ip, remove_dentry_fxns);
+   fsck_inode_put(ip);
return error;
 }
 
diff --git a/gfs2/fsck/metawalk.h b/gfs2/fsck/metawalk.h
index 057e698..779360e 100644
--- a/gfs2/fsck/metawalk.h
+++ b/gfs2/fsck/metawalk.h
@@ -12,7 +12,7 @@ extern int check_inode_eattr(struct gfs2_inode *ip,
 struct metawalk_fxns *pass);
 extern int check_metatree(struct gfs2_inode *ip, struct metawalk_fxns *pass);
 extern int check_leaf_blks(struct gfs2_inode *ip, struct metawalk_fxns *pass);
-extern int check_dir(struct gfs2_sbd *sdp, uint64_t block,
+extern int check_dir(struct gfs2_sbd *sdp, struct gfs2_inode *ip,
 struct metawalk_fxns *pass);
 extern int check_linear_dir(struct gfs2_inode *ip, struct gfs2_buffer_head *bh,
struct metawalk_fxns *pass);
diff --git a/gfs2/fsck/pass2.c b/gfs2/fsck/pass2.c
index 1d32335..b31fbd4 100644
--- a/gfs2/fsck/pass2.c
+++ b/gfs2/fsck/pass2.c
@@ -1712,7 +1712,7 @@ static int check_system_dir(struct gfs2_inode *sysinode, 
const char *dirname,
if (astate_changed(sysinode, as))
reprocess_inode(sysinode, _(System inode));
}
-   error = check_dir(sysinode-i_sbd, iblock, pass2_fxns);
+   error = check_dir(sysinode-i_sbd, sysinode, pass2_fxns);
if (skip_this_pass || fsck_abort) /* if asked to skip the rest */
return FSCK_OK;
if (error  0) {
@@ -1807,6 +1807,116 @@ static inline int is_system_dir(struct gfs2_sbd *sdp, 
uint64_t block)
return FALSE;
 }
 
+static int pass2_check_dir(struct gfs2_sbd *sdp, struct gfs2_inode *ip)
+{
+   uint64_t dirblk = ip-i_di.di_num.no_addr;
+   struct dir_status ds = {0};
+   struct alloc_state as;
+   int error;
+
+   pass2_fxns.private = ds;
+   if (ds.q == GFS2_BLKST_UNLINKED) {
+   /* First check that the directory's metatree is valid */
+   astate_save(ip, as);
+   error = check_metatree(ip, pass2_fxns);
+   if (error  0) {
+   stack;
+   return error;
+   }
+   if (astate_changed(ip, as))
+   reprocess_inode(ip, current);
+   }
+   error = check_dir(sdp, ip, pass2_fxns);
+   if (skip_this_pass || fsck_abort) /* if asked to skip the rest 

Re: [Cluster-devel] [PATCH v3] fs: record task name which froze superblock

2015-03-04 Thread Alexey Dobriyan
On Mon, Mar 2, 2015 at 7:38 AM, Mateusz Guzik mgu...@redhat.com wrote:

 As explained below, this one task name is already very useful and likely
 covers majority of real life use cases.

 While working in support we were getting a lot of vmcores where hung task
 detector panicked the kernel because a lot of tasks were blocked
 in UN state trying to write to frozen filesystems. I presume OP has
 similar story.

Yes, the intended use case is 1 freezer which hopefully covers
majority of bug reports.

 Some back on forth commuication almost always revealed one process e.g.
 freezing stuff and then blocking itself trying to access it. While we
 could see it blocked, we had no presumptive evidence to pin freezing on
 it. A matching name, while still not 100% conclusive, would be ok enough
 to push the case forward and avoid a rountrip of systemap scripts
 showing freezer process tree.



[Cluster-devel] [PATCH 6/8] quota: Make -set_info use structure with neccesary info to VFS and XFS

2015-03-04 Thread Jan Kara
Change -set_info to take new qc_info structure which contains all the
necessary information both for XFS and VFS. Convert Q_SETINFO handler
to use this structure.

Signed-off-by: Jan Kara j...@suse.cz
---
 fs/quota/dquot.c | 27 ---
 fs/quota/quota.c | 21 -
 include/linux/quota.h| 21 +++--
 include/linux/quotaops.h |  2 +-
 4 files changed, 56 insertions(+), 15 deletions(-)

diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c
index cf4edd87e854..f37b74eab807 100644
--- a/fs/quota/dquot.c
+++ b/fs/quota/dquot.c
@@ -2649,33 +2649,38 @@ int dquot_get_state(struct super_block *sb, struct 
qc_state *state)
 EXPORT_SYMBOL(dquot_get_state);
 
 /* Generic routine for setting common part of quota file information */
-int dquot_set_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii)
+int dquot_set_dqinfo(struct super_block *sb, int type, struct qc_info *ii)
 {
struct mem_dqinfo *mi;
int err = 0;
 
+   if ((ii-i_fieldmask  QC_WARNS_MASK) ||
+   (ii-i_fieldmask  QC_RT_SPC_TIMER))
+   return -EINVAL;
mutex_lock(sb_dqopt(sb)-dqonoff_mutex);
if (!sb_has_quota_active(sb, type)) {
err = -ESRCH;
goto out;
}
mi = sb_dqopt(sb)-info + type;
-   if (ii-dqi_valid  IIF_FLAGS) {
-   if (ii-dqi_flags  ~DQF_SETINFO_MASK ||
-   (ii-dqi_flags  DQF_ROOT_SQUASH 
+   if (ii-i_fieldmask  QC_FLAGS) {
+   if ((ii-i_flags  QCI_ROOT_SQUASH 
 mi-dqi_format-qf_fmt_id != QFMT_VFS_OLD)) {
err = -EINVAL;
goto out;
}
}
spin_lock(dq_data_lock);
-   if (ii-dqi_valid  IIF_BGRACE)
-   mi-dqi_bgrace = ii-dqi_bgrace;
-   if (ii-dqi_valid  IIF_IGRACE)
-   mi-dqi_igrace = ii-dqi_igrace;
-   if (ii-dqi_valid  IIF_FLAGS)
-   mi-dqi_flags = (mi-dqi_flags  ~DQF_SETINFO_MASK) |
-   (ii-dqi_flags  DQF_SETINFO_MASK);
+   if (ii-i_fieldmask  QC_SPC_TIMER)
+   mi-dqi_bgrace = ii-i_spc_timelimit;
+   if (ii-i_fieldmask  QC_INO_TIMER)
+   mi-dqi_igrace = ii-i_ino_timelimit;
+   if (ii-i_fieldmask  QC_FLAGS) {
+   if (ii-i_flags  QCI_ROOT_SQUASH)
+   mi-dqi_flags |= DQF_ROOT_SQUASH;
+   else
+   mi-dqi_flags = ~DQF_ROOT_SQUASH;
+   }
spin_unlock(dq_data_lock);
mark_info_dirty(sb, type);
/* Force write to disk */
diff --git a/fs/quota/quota.c b/fs/quota/quota.c
index 20d11cd21247..741d5a178268 100644
--- a/fs/quota/quota.c
+++ b/fs/quota/quota.c
@@ -149,12 +149,31 @@ static int quota_getinfo(struct super_block *sb, int 
type, void __user *addr)
 static int quota_setinfo(struct super_block *sb, int type, void __user *addr)
 {
struct if_dqinfo info;
+   struct qc_info qinfo;
 
if (copy_from_user(info, addr, sizeof(info)))
return -EFAULT;
if (!sb-s_qcop-set_info)
return -ENOSYS;
-   return sb-s_qcop-set_info(sb, type, info);
+   if (info.dqi_valid  ~(IIF_FLAGS | IIF_BGRACE | IIF_IGRACE))
+   return -EINVAL;
+   memset(qinfo, 0, sizeof(qinfo));
+   if (info.dqi_valid  IIF_FLAGS) {
+   if (info.dqi_flags  ~DQF_SETINFO_MASK)
+   return -EINVAL;
+   if (info.dqi_flags  DQF_ROOT_SQUASH)
+   qinfo.i_flags |= QCI_ROOT_SQUASH;
+   qinfo.i_fieldmask |= QC_FLAGS;
+   }
+   if (info.dqi_valid  IIF_BGRACE) {
+   qinfo.i_spc_timelimit = info.dqi_bgrace;
+   qinfo.i_fieldmask |= QC_SPC_TIMER;
+   }
+   if (info.dqi_valid  IIF_IGRACE) {
+   qinfo.i_ino_timelimit = info.dqi_igrace;
+   qinfo.i_fieldmask |= QC_INO_TIMER;
+   }
+   return sb-s_qcop-set_info(sb, type, qinfo);
 }
 
 static inline qsize_t qbtos(qsize_t blocks)
diff --git a/include/linux/quota.h b/include/linux/quota.h
index a07f2ed25284..3d521199a0bd 100644
--- a/include/linux/quota.h
+++ b/include/linux/quota.h
@@ -344,7 +344,10 @@ struct qc_dqblk {
int d_rt_spc_warns; /* # warnings issued wrt RT space */
 };
 
-/* Field specifiers for -set_dqblk() in struct qc_dqblk */
+/*
+ * Field specifiers for -set_dqblk() in struct qc_dqblk and also for
+ * -set_info() in struct qc_info
+ */
 #defineQC_INO_SOFT (10)
 #defineQC_INO_HARD (11)
 #defineQC_SPC_SOFT (12)
@@ -365,6 +368,7 @@ struct qc_dqblk {
 #defineQC_INO_COUNT(113)
 #defineQC_RT_SPACE (114)
 #define QC_ACCT_MASK (QC_SPACE | QC_INO_COUNT | QC_RT_SPACE)
+#define QC_FLAGS   (115)
 
 #define QCI_SYSFILE(1  0)/* Quota file is hidden from 
userspace */
 #define QCI_ROOT_SQUASH(1  1)/* Root squash 

[Cluster-devel] [PATCH 5/8] quota: Remove -get_xstate and -get_xstatev callbacks

2015-03-04 Thread Jan Kara
These callbacks are now unused. Remove them.

Reviewed-by: Christoph Hellwig h...@lst.de
Signed-off-by: Jan Kara j...@suse.cz
---
 fs/quota/quota.c  | 14 --
 include/linux/quota.h |  2 --
 2 files changed, 4 insertions(+), 12 deletions(-)

diff --git a/fs/quota/quota.c b/fs/quota/quota.c
index 83939ff4c444..20d11cd21247 100644
--- a/fs/quota/quota.c
+++ b/fs/quota/quota.c
@@ -350,12 +350,9 @@ static int quota_getxstate(struct super_block *sb, void 
__user *addr)
struct fs_quota_stat fqs;
int ret;
 
-   if (!sb-s_qcop-get_xstate  !sb-s_qcop-get_state)
+   if (!sb-s_qcop-get_state)
return -ENOSYS;
-   if (sb-s_qcop-get_state)
-   ret = quota_getstate(sb, fqs);
-   else
-   ret = sb-s_qcop-get_xstate(sb, fqs);
+   ret = quota_getstate(sb, fqs);
if (!ret  copy_to_user(addr, fqs, sizeof(fqs)))
return -EFAULT;
return ret;
@@ -414,7 +411,7 @@ static int quota_getxstatev(struct super_block *sb, void 
__user *addr)
struct fs_quota_statv fqs;
int ret;
 
-   if (!sb-s_qcop-get_xstatev  !sb-s_qcop-get_state)
+   if (!sb-s_qcop-get_state)
return -ENOSYS;
 
memset(fqs, 0, sizeof(fqs));
@@ -428,10 +425,7 @@ static int quota_getxstatev(struct super_block *sb, void 
__user *addr)
default:
return -EINVAL;
}
-   if (sb-s_qcop-get_state)
-   ret = quota_getstatev(sb, fqs);
-   else
-   ret = sb-s_qcop-get_xstatev(sb, fqs);
+   ret = quota_getstatev(sb, fqs);
if (!ret  copy_to_user(addr, fqs, sizeof(fqs)))
return -EFAULT;
return ret;
diff --git a/include/linux/quota.h b/include/linux/quota.h
index 6ecac0f3b2ca..a07f2ed25284 100644
--- a/include/linux/quota.h
+++ b/include/linux/quota.h
@@ -408,8 +408,6 @@ struct quotactl_ops {
int (*get_dqblk)(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 (*get_xstate)(struct super_block *, struct fs_quota_stat *);
-   int (*get_xstatev)(struct super_block *, struct fs_quota_statv *);
int (*rm_xquota)(struct super_block *, unsigned int);
 };
 
-- 
2.1.4



[Cluster-devel] [PATCH 7/8] xfs: Add support for Q_SETINFO

2015-03-04 Thread Jan Kara
Add support to XFS so that time limits can be set through Q_SETINFO
quotactl.

Reviewed-by: Christoph Hellwig h...@lst.de
Signed-off-by: Jan Kara j...@suse.cz
---
 fs/xfs/xfs_quotaops.c | 37 +
 1 file changed, 37 insertions(+)

diff --git a/fs/xfs/xfs_quotaops.c b/fs/xfs/xfs_quotaops.c
index 5775acb0589b..7795e0d01382 100644
--- a/fs/xfs/xfs_quotaops.c
+++ b/fs/xfs/xfs_quotaops.c
@@ -111,6 +111,42 @@ xfs_quota_type(int type)
}
 }
 
+#define XFS_QC_SETINFO_MASK (QC_TIMER_MASK | QC_WARNS_MASK)
+
+/*
+ * Adjust quota timers  warnings
+ */
+static int
+xfs_fs_set_info(
+   struct super_block  *sb,
+   int type,
+   struct qc_info  *info)
+{
+   struct xfs_mount *mp = XFS_M(sb);
+   struct qc_dqblk newlim;
+
+   if (sb-s_flags  MS_RDONLY)
+   return -EROFS;
+   if (!XFS_IS_QUOTA_RUNNING(mp))
+   return -ENOSYS;
+   if (!XFS_IS_QUOTA_ON(mp))
+   return -ESRCH;
+   if (info-i_fieldmask  ~XFS_QC_SETINFO_MASK)
+   return -EINVAL;
+   if ((info-i_fieldmask  XFS_QC_SETINFO_MASK) == 0)
+   return 0;
+
+   newlim.d_fieldmask = info-i_fieldmask;
+   newlim.d_spc_timer = info-i_spc_timelimit;
+   newlim.d_ino_timer = info-i_ino_timelimit;
+   newlim.d_rt_spc_timer = info-i_rt_spc_timelimit;
+   newlim.d_ino_warns = info-i_ino_warnlimit;
+   newlim.d_spc_warns = info-i_spc_warnlimit;
+   newlim.d_rt_spc_warns = info-i_rt_spc_warnlimit;
+
+   return xfs_qm_scall_setqlim(mp, 0, xfs_quota_type(type), newlim);
+}
+
 static unsigned int
 xfs_quota_flags(unsigned int uflags)
 {
@@ -226,6 +262,7 @@ xfs_fs_set_dqblk(
 
 const struct quotactl_ops xfs_quotactl_operations = {
.get_state  = xfs_fs_get_quota_state,
+   .set_info   = xfs_fs_set_info,
.quota_enable   = xfs_quota_enable,
.quota_disable  = xfs_quota_disable,
.rm_xquota  = xfs_fs_rm_xquota,
-- 
2.1.4



[Cluster-devel] [PATCH 1/8] quota: Make VFS quotas use new interface for getting quota info

2015-03-04 Thread Jan Kara
Create new internal interface for getting information about quota which
contains everything needed for both VFS quotas and XFS quotas. Make VFS
use this and hook it up to Q_GETINFO.

Reviewed-by: Christoph Hellwig h...@lst.de
Signed-off-by: Jan Kara j...@suse.cz
---
 fs/ext3/super.c  |  2 +-
 fs/ext4/super.c  |  2 +-
 fs/quota/dquot.c | 41 +++--
 fs/quota/quota.c | 25 +
 fs/reiserfs/super.c  |  2 +-
 include/linux/quota.h| 33 -
 include/linux/quotaops.h |  2 +-
 7 files changed, 84 insertions(+), 23 deletions(-)

diff --git a/fs/ext3/super.c b/fs/ext3/super.c
index d4dbf3c259b3..f037b4b27300 100644
--- a/fs/ext3/super.c
+++ b/fs/ext3/super.c
@@ -789,7 +789,7 @@ static const struct quotactl_ops ext3_qctl_operations = {
.quota_on   = ext3_quota_on,
.quota_off  = dquot_quota_off,
.quota_sync = dquot_quota_sync,
-   .get_info   = dquot_get_dqinfo,
+   .get_state  = dquot_get_state,
.set_info   = dquot_set_dqinfo,
.get_dqblk  = dquot_get_dqblk,
.set_dqblk  = dquot_set_dqblk
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index e061e66c8280..d348c7d29d80 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -1076,7 +1076,7 @@ static const struct quotactl_ops ext4_qctl_operations = {
.quota_on   = ext4_quota_on,
.quota_off  = ext4_quota_off,
.quota_sync = dquot_quota_sync,
-   .get_info   = dquot_get_dqinfo,
+   .get_state  = dquot_get_state,
.set_info   = dquot_set_dqinfo,
.get_dqblk  = dquot_get_dqblk,
.set_dqblk  = dquot_set_dqblk
diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c
index 0ccd4ba3a246..cf4edd87e854 100644
--- a/fs/quota/dquot.c
+++ b/fs/quota/dquot.c
@@ -2614,26 +2614,39 @@ out:
 EXPORT_SYMBOL(dquot_set_dqblk);
 
 /* Generic routine for getting common part of quota file information */
-int dquot_get_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii)
+int dquot_get_state(struct super_block *sb, struct qc_state *state)
 {
struct mem_dqinfo *mi;
+   struct qc_type_state *tstate;
+   struct quota_info *dqopt = sb_dqopt(sb);
+   int type;
   
mutex_lock(sb_dqopt(sb)-dqonoff_mutex);
-   if (!sb_has_quota_active(sb, type)) {
-   mutex_unlock(sb_dqopt(sb)-dqonoff_mutex);
-   return -ESRCH;
+   memset(state, 0, sizeof(*state));
+   for (type = 0; type  MAXQUOTAS; type++) {
+   if (!sb_has_quota_active(sb, type))
+   continue;
+   tstate = state-s_state + type;
+   mi = sb_dqopt(sb)-info + type;
+   tstate-flags = QCI_ACCT_ENABLED;
+   spin_lock(dq_data_lock);
+   if (mi-dqi_flags  DQF_SYS_FILE)
+   tstate-flags |= QCI_SYSFILE;
+   if (mi-dqi_flags  DQF_ROOT_SQUASH)
+   tstate-flags |= QCI_ROOT_SQUASH;
+   if (sb_has_quota_limits_enabled(sb, type))
+   tstate-flags |= QCI_LIMITS_ENFORCED;
+   tstate-spc_timelimit = mi-dqi_bgrace;
+   tstate-ino_timelimit = mi-dqi_igrace;
+   tstate-ino = dqopt-files[type]-i_ino;
+   tstate-blocks = dqopt-files[type]-i_blocks;
+   tstate-nextents = 1;   /* We don't know... */
+   spin_unlock(dq_data_lock);
}
-   mi = sb_dqopt(sb)-info + type;
-   spin_lock(dq_data_lock);
-   ii-dqi_bgrace = mi-dqi_bgrace;
-   ii-dqi_igrace = mi-dqi_igrace;
-   ii-dqi_flags = mi-dqi_flags  DQF_GETINFO_MASK;
-   ii-dqi_valid = IIF_ALL;
-   spin_unlock(dq_data_lock);
mutex_unlock(sb_dqopt(sb)-dqonoff_mutex);
return 0;
 }
-EXPORT_SYMBOL(dquot_get_dqinfo);
+EXPORT_SYMBOL(dquot_get_state);
 
 /* Generic routine for setting common part of quota file information */
 int dquot_set_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii)
@@ -2677,7 +2690,7 @@ const struct quotactl_ops dquot_quotactl_ops = {
.quota_on   = dquot_quota_on,
.quota_off  = dquot_quota_off,
.quota_sync = dquot_quota_sync,
-   .get_info   = dquot_get_dqinfo,
+   .get_state  = dquot_get_state,
.set_info   = dquot_set_dqinfo,
.get_dqblk  = dquot_get_dqblk,
.set_dqblk  = dquot_set_dqblk
@@ -2688,7 +2701,7 @@ const struct quotactl_ops dquot_quotactl_sysfile_ops = {
.quota_enable   = dquot_quota_enable,
.quota_disable  = dquot_quota_disable,
.quota_sync = dquot_quota_sync,
-   .get_info   = dquot_get_dqinfo,
+   .get_state  = dquot_get_state,
.set_info   = dquot_set_dqinfo,
.get_dqblk  = dquot_get_dqblk,
.set_dqblk  = dquot_set_dqblk
diff --git a/fs/quota/quota.c b/fs/quota/quota.c
index