* [PATCH 1/3] jbd2: optimize jbd2_journal_force_commit V3
@ 2013-06-10 16:40 Dmitry Monakhov
2013-06-10 16:41 ` [PATCH 2/3] ext4: fix data integrity for ext4_sync_fs Dmitry Monakhov
` (2 more replies)
0 siblings, 3 replies; 7+ messages in thread
From: Dmitry Monakhov @ 2013-06-10 16:40 UTC (permalink / raw)
To: linux-ext4; +Cc: tytso, jack, Dmitry Monakhov
Current implementation of jbd2_journal_force_commit() is suboptimal because
result in empty and useless commits. But callers just want to force and wait
any unfinished commits. We already has jbd2_journal_force_commit_nested()
which does exactly what we want, except we are guaranteed that we do not hold
journal transaction open.
Changes since V3 to V2
- API changes according to Jan's comments
- make __jbd2_journal_force_commit() static
Changes since V2 to V1
- Fix incorrect return value according to Jan's comments.
Signed-off-by: Dmitry Monakhov <dmonakhov@openvz.org>
---
fs/jbd2/journal.c | 63 ++++++++++++++++++++++++++++++++++++++-----------
fs/jbd2/transaction.c | 23 ------------------
include/linux/jbd2.h | 2 +-
3 files changed, 50 insertions(+), 38 deletions(-)
diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c
index 70990d6..8771fe5 100644
--- a/fs/jbd2/journal.c
+++ b/fs/jbd2/journal.c
@@ -529,20 +529,18 @@ int jbd2_log_start_commit(journal_t *journal, tid_t tid)
}
/*
- * Force and wait upon a commit if the calling process is not within
- * transaction. This is used for forcing out undo-protected data which contains
- * bitmaps, when the fs is running out of space.
- *
- * We can only force the running transaction if we don't have an active handle;
- * otherwise, we will deadlock.
- *
- * Returns true if a transaction was started.
+ * Force and wait any uncommitted transactions. We can only force the running
+ * transaction if we don't have an active handle, otherwise, we will deadlock.
+ * Returns: <0 in case of error,
+ * 0 if nothing to commit,
+ * 1 if transaction was successfully committed.
*/
-int jbd2_journal_force_commit_nested(journal_t *journal)
+static int __jbd2_journal_force_commit(journal_t *journal)
{
transaction_t *transaction = NULL;
tid_t tid;
- int need_to_start = 0;
+ int need_to_start = 0, ret = 0;
+
read_lock(&journal->j_state_lock);
if (journal->j_running_transaction && !current->journal_info) {
@@ -553,16 +551,53 @@ int jbd2_journal_force_commit_nested(journal_t *journal)
transaction = journal->j_committing_transaction;
if (!transaction) {
+ /* Nothing to commit */
read_unlock(&journal->j_state_lock);
- return 0; /* Nothing to retry */
+ return 0;
}
-
tid = transaction->t_tid;
read_unlock(&journal->j_state_lock);
if (need_to_start)
jbd2_log_start_commit(journal, tid);
- jbd2_log_wait_commit(journal, tid);
- return 1;
+ ret = jbd2_log_wait_commit(journal, tid);
+ if (!ret)
+ ret = 1;
+
+ return ret;
+}
+
+/**
+ * Force and wait upon a commit if the calling process is not within
+ * transaction. This is used for forcing out undo-protected data which contains
+ * bitmaps, when the fs is running out of space.
+ *
+ * @journal: journal to force
+ * Returns true if progress was made.
+ */
+int jbd2_journal_force_commit_nested(journal_t *journal)
+{
+ int ret;
+
+ ret = __jbd2_journal_force_commit(journal);
+ return ret > 0;
+}
+
+/**
+ * int journal_force_commit() - force any uncommitted transactions
+ * @journal: journal to force
+ *
+ * Caller want unconditional commit. We can only force the running transaction
+ * if we don't have an active handle, otherwise, we will deadlock.
+ */
+int jbd2_journal_force_commit(journal_t *journal)
+{
+ int ret;
+
+ J_ASSERT(!current->journal_info);
+ ret = __jbd2_journal_force_commit(journal);
+ if (ret > 0)
+ ret = 0;
+ return ret;
}
/*
diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c
index f33342a..dd422e6 100644
--- a/fs/jbd2/transaction.c
+++ b/fs/jbd2/transaction.c
@@ -1661,29 +1661,6 @@ int jbd2_journal_stop(handle_t *handle)
return err;
}
-/**
- * int jbd2_journal_force_commit() - force any uncommitted transactions
- * @journal: journal to force
- *
- * For synchronous operations: force any uncommitted transactions
- * to disk. May seem kludgy, but it reuses all the handle batching
- * code in a very simple manner.
- */
-int jbd2_journal_force_commit(journal_t *journal)
-{
- handle_t *handle;
- int ret;
-
- handle = jbd2_journal_start(journal, 1);
- if (IS_ERR(handle)) {
- ret = PTR_ERR(handle);
- } else {
- handle->h_sync = 1;
- ret = jbd2_journal_stop(handle);
- }
- return ret;
-}
-
/*
*
* List management code snippets: various functions for manipulating the
diff --git a/include/linux/jbd2.h b/include/linux/jbd2.h
index fb91c8d..c3645b9 100644
--- a/include/linux/jbd2.h
+++ b/include/linux/jbd2.h
@@ -1160,6 +1160,7 @@ extern void jbd2_journal_ack_err (journal_t *);
extern int jbd2_journal_clear_err (journal_t *);
extern int jbd2_journal_bmap(journal_t *, unsigned long, unsigned long long *);
extern int jbd2_journal_force_commit(journal_t *);
+extern int jbd2_journal_force_commit_nested(journal_t *);
extern int jbd2_journal_file_inode(handle_t *handle, struct jbd2_inode *inode);
extern int jbd2_journal_begin_ordered_truncate(journal_t *journal,
struct jbd2_inode *inode, loff_t new_size);
@@ -1235,7 +1236,6 @@ extern void jbd2_clear_buffer_revoked_flags(journal_t *journal);
int jbd2_log_start_commit(journal_t *journal, tid_t tid);
int __jbd2_log_start_commit(journal_t *journal, tid_t tid);
int jbd2_journal_start_commit(journal_t *journal, tid_t *tid);
-int jbd2_journal_force_commit_nested(journal_t *journal);
int jbd2_log_wait_commit(journal_t *journal, tid_t tid);
int jbd2_complete_transaction(journal_t *journal, tid_t tid);
int jbd2_log_do_checkpoint(journal_t *journal);
--
1.7.1
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH 2/3] ext4: fix data integrity for ext4_sync_fs
2013-06-10 16:40 [PATCH 1/3] jbd2: optimize jbd2_journal_force_commit V3 Dmitry Monakhov
@ 2013-06-10 16:41 ` Dmitry Monakhov
2013-06-13 2:32 ` Theodore Ts'o
2013-06-10 16:41 ` [PATCH 3/3] ext4: Fix fsync error handling after filesystem abort Dmitry Monakhov
2013-06-13 0:42 ` [PATCH 1/3] jbd2: optimize jbd2_journal_force_commit V3 Theodore Ts'o
2 siblings, 1 reply; 7+ messages in thread
From: Dmitry Monakhov @ 2013-06-10 16:41 UTC (permalink / raw)
To: linux-ext4; +Cc: tytso, jack, Dmitry Monakhov
Inode's data or non journaled quota may be written w/o jounral so we _must_
send a barrier at the end of ext4_sync_fs. But it can be skipped if journal
commit will do it for us.
Also fix data integrity for nojournal mode.
changes from v2:
fix jbd2_get_latest_transaction() return correct transaction
changes from v1:
skip barrier for async mode
Signed-off-by: Dmitry Monakhov <dmonakhov@openvz.org>
---
fs/ext4/super.c | 36 +++++++++++++++++++++++++++++++++++-
include/linux/jbd2.h | 13 +++++++++++++
2 files changed, 48 insertions(+), 1 deletions(-)
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 7c8e171..0f77c2e 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -69,6 +69,7 @@ static void ext4_mark_recovery_complete(struct super_block *sb,
static void ext4_clear_journal_err(struct super_block *sb,
struct ext4_super_block *es);
static int ext4_sync_fs(struct super_block *sb, int wait);
+static int ext4_sync_fs_nojournal(struct super_block *sb, int wait);
static int ext4_remount(struct super_block *sb, int *flags, char *data);
static int ext4_statfs(struct dentry *dentry, struct kstatfs *buf);
static int ext4_unfreeze(struct super_block *sb);
@@ -1097,6 +1098,7 @@ static const struct super_operations ext4_nojournal_sops = {
.dirty_inode = ext4_dirty_inode,
.drop_inode = ext4_drop_inode,
.evict_inode = ext4_evict_inode,
+ .sync_fs = ext4_sync_fs_nojournal,
.put_super = ext4_put_super,
.statfs = ext4_statfs,
.remount_fs = ext4_remount,
@@ -4553,6 +4555,7 @@ static int ext4_sync_fs(struct super_block *sb, int wait)
{
int ret = 0;
tid_t target;
+ bool needs_barrier = false;
struct ext4_sb_info *sbi = EXT4_SB(sb);
trace_ext4_sync_fs(sb, wait);
@@ -4563,10 +4566,41 @@ static int ext4_sync_fs(struct super_block *sb, int wait)
* no dirty dquots
*/
dquot_writeback_dquots(sb, -1);
+ /*
+ * Data writeback is possible w/o journal transaction, so barrier must
+ * being sent at the end of the function. But we can skip it if
+ * transaction_commit will do it for us.
+ */
+ target = jbd2_get_latest_transaction(sbi->s_journal);
+ if (wait && sbi->s_journal->j_flags & JBD2_BARRIER &&
+ !jbd2_trans_will_send_data_barrier(sbi->s_journal, target))
+ needs_barrier = true;
+
if (jbd2_journal_start_commit(sbi->s_journal, &target)) {
if (wait)
- jbd2_log_wait_commit(sbi->s_journal, target);
+ ret = jbd2_log_wait_commit(sbi->s_journal, target);
+ }
+ if (needs_barrier) {
+ int err;
+ err = blkdev_issue_flush(sb->s_bdev, GFP_KERNEL, NULL);
+ if (!ret)
+ ret = err;
}
+
+ return ret;
+}
+
+static int ext4_sync_fs_nojournal(struct super_block *sb, int wait)
+{
+ int ret = 0;
+
+ trace_ext4_sync_fs(sb, wait);
+ flush_workqueue(EXT4_SB(sb)->rsv_conversion_wq);
+ flush_workqueue(EXT4_SB(sb)->unrsv_conversion_wq);
+ dquot_writeback_dquots(sb, -1);
+ if (wait && test_opt(sb, BARRIER))
+ ret = blkdev_issue_flush(sb->s_bdev, GFP_KERNEL, NULL);
+
return ret;
}
diff --git a/include/linux/jbd2.h b/include/linux/jbd2.h
index c3645b9..a79783f 100644
--- a/include/linux/jbd2.h
+++ b/include/linux/jbd2.h
@@ -1374,6 +1374,19 @@ static inline u32 jbd2_chksum(journal_t *journal, u32 crc,
return *(u32 *)desc.ctx;
}
+/* Return most recent uncommitted transaction */
+static inline tid_t jbd2_get_latest_transaction(journal_t *journal)
+{
+ tid_t tid;
+
+ read_lock(&journal->j_state_lock);
+ tid = journal->j_commit_request;
+ if (journal->j_running_transaction)
+ tid = journal->j_running_transaction->t_tid;
+ read_unlock(&journal->j_state_lock);
+ return tid;
+}
+
#ifdef __KERNEL__
#define buffer_trace_init(bh) do {} while (0)
--
1.7.1
^ permalink raw reply related [flat|nested] 7+ messages in thread* Re: [PATCH 2/3] ext4: fix data integrity for ext4_sync_fs
2013-06-10 16:41 ` [PATCH 2/3] ext4: fix data integrity for ext4_sync_fs Dmitry Monakhov
@ 2013-06-13 2:32 ` Theodore Ts'o
0 siblings, 0 replies; 7+ messages in thread
From: Theodore Ts'o @ 2013-06-13 2:32 UTC (permalink / raw)
To: Dmitry Monakhov; +Cc: linux-ext4, jack
On Mon, Jun 10, 2013 at 08:41:00PM +0400, Dmitry Monakhov wrote:
> Inode's data or non journaled quota may be written w/o jounral so we _must_
> send a barrier at the end of ext4_sync_fs. But it can be skipped if journal
> commit will do it for us.
>
> Also fix data integrity for nojournal mode.
> changes from v2:
> fix jbd2_get_latest_transaction() return correct transaction
> changes from v1:
> skip barrier for async mode
>
> Signed-off-by: Dmitry Monakhov <dmonakhov@openvz.org>
Applied, thanks.
- Ted
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH 3/3] ext4: Fix fsync error handling after filesystem abort.
2013-06-10 16:40 [PATCH 1/3] jbd2: optimize jbd2_journal_force_commit V3 Dmitry Monakhov
2013-06-10 16:41 ` [PATCH 2/3] ext4: fix data integrity for ext4_sync_fs Dmitry Monakhov
@ 2013-06-10 16:41 ` Dmitry Monakhov
2013-06-10 21:22 ` Darrick J. Wong
2013-06-13 2:39 ` Theodore Ts'o
2013-06-13 0:42 ` [PATCH 1/3] jbd2: optimize jbd2_journal_force_commit V3 Theodore Ts'o
2 siblings, 2 replies; 7+ messages in thread
From: Dmitry Monakhov @ 2013-06-10 16:41 UTC (permalink / raw)
To: linux-ext4; +Cc: tytso, jack, Dmitry Monakhov
If filesystem was aborted after inode's write back is complete
but before its metadata was updated we may return success
results in data loss.
In order to handle fs abort correctly we have to check
fs state once we discover that it is in MS_RDONLY state
Test case: http://patchwork.ozlabs.org/patch/244297
Changes from V2:
- more spelling fixes
Changes from V1:
- fix spelling
Reviewed-by: Jan Kara <jack@suse.cz>
Signed-off-by: Dmitry Monakhov <dmonakhov@openvz.org>
---
fs/ext4/fsync.c | 7 ++++++-
fs/ext4/super.c | 12 +++++++++++-
2 files changed, 17 insertions(+), 2 deletions(-)
diff --git a/fs/ext4/fsync.c b/fs/ext4/fsync.c
index fc938eb..a8bc47f 100644
--- a/fs/ext4/fsync.c
+++ b/fs/ext4/fsync.c
@@ -98,8 +98,13 @@ int ext4_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
trace_ext4_sync_file_enter(file, datasync);
- if (inode->i_sb->s_flags & MS_RDONLY)
+ if (inode->i_sb->s_flags & MS_RDONLY) {
+ /* Make sure that we read updated s_mount_flags value */
+ smp_rmb();
+ if (EXT4_SB(inode->i_sb)->s_mount_flags & EXT4_MF_FS_ABORTED)
+ ret = -EROFS;
goto out;
+ }
if (!journal) {
ret = generic_file_fsync(file, start, end, datasync);
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 0f77c2e..f23daaa 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -399,6 +399,11 @@ static void ext4_handle_error(struct super_block *sb)
}
if (test_opt(sb, ERRORS_RO)) {
ext4_msg(sb, KERN_CRIT, "Remounting filesystem read-only");
+ /*
+ * Make shure updated value of ->s_mount_flags will be visible
+ * before ->s_flags update
+ */
+ smp_wmb();
sb->s_flags |= MS_RDONLY;
}
if (test_opt(sb, ERRORS_PANIC))
@@ -571,8 +576,13 @@ void __ext4_abort(struct super_block *sb, const char *function,
if ((sb->s_flags & MS_RDONLY) == 0) {
ext4_msg(sb, KERN_CRIT, "Remounting filesystem read-only");
- sb->s_flags |= MS_RDONLY;
EXT4_SB(sb)->s_mount_flags |= EXT4_MF_FS_ABORTED;
+ /*
+ * Make shure updated value of ->s_mount_flags will be visiable
+ * before ->s_flags update
+ */
+ smp_wmb();
+ sb->s_flags |= MS_RDONLY;
if (EXT4_SB(sb)->s_journal)
jbd2_journal_abort(EXT4_SB(sb)->s_journal, -EIO);
save_error_info(sb, function, line);
--
1.7.1
^ permalink raw reply related [flat|nested] 7+ messages in thread* Re: [PATCH 3/3] ext4: Fix fsync error handling after filesystem abort.
2013-06-10 16:41 ` [PATCH 3/3] ext4: Fix fsync error handling after filesystem abort Dmitry Monakhov
@ 2013-06-10 21:22 ` Darrick J. Wong
2013-06-13 2:39 ` Theodore Ts'o
1 sibling, 0 replies; 7+ messages in thread
From: Darrick J. Wong @ 2013-06-10 21:22 UTC (permalink / raw)
To: Dmitry Monakhov; +Cc: linux-ext4, tytso, jack
On Mon, Jun 10, 2013 at 08:41:01PM +0400, Dmitry Monakhov wrote:
> If filesystem was aborted after inode's write back is complete
> but before its metadata was updated we may return success
> results in data loss.
> In order to handle fs abort correctly we have to check
> fs state once we discover that it is in MS_RDONLY state
>
> Test case: http://patchwork.ozlabs.org/patch/244297
>
> Changes from V2:
> - more spelling fixes
>
> Changes from V1:
> - fix spelling
>
> Reviewed-by: Jan Kara <jack@suse.cz>
> Signed-off-by: Dmitry Monakhov <dmonakhov@openvz.org>
> ---
> fs/ext4/fsync.c | 7 ++++++-
> fs/ext4/super.c | 12 +++++++++++-
> 2 files changed, 17 insertions(+), 2 deletions(-)
>
> diff --git a/fs/ext4/fsync.c b/fs/ext4/fsync.c
> index fc938eb..a8bc47f 100644
> --- a/fs/ext4/fsync.c
> +++ b/fs/ext4/fsync.c
> @@ -98,8 +98,13 @@ int ext4_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
>
> trace_ext4_sync_file_enter(file, datasync);
>
> - if (inode->i_sb->s_flags & MS_RDONLY)
> + if (inode->i_sb->s_flags & MS_RDONLY) {
> + /* Make sure that we read updated s_mount_flags value */
> + smp_rmb();
> + if (EXT4_SB(inode->i_sb)->s_mount_flags & EXT4_MF_FS_ABORTED)
> + ret = -EROFS;
> goto out;
> + }
>
> if (!journal) {
> ret = generic_file_fsync(file, start, end, datasync);
> diff --git a/fs/ext4/super.c b/fs/ext4/super.c
> index 0f77c2e..f23daaa 100644
> --- a/fs/ext4/super.c
> +++ b/fs/ext4/super.c
> @@ -399,6 +399,11 @@ static void ext4_handle_error(struct super_block *sb)
> }
> if (test_opt(sb, ERRORS_RO)) {
> ext4_msg(sb, KERN_CRIT, "Remounting filesystem read-only");
> + /*
> + * Make shure updated value of ->s_mount_flags will be visible
> + * before ->s_flags update
> + */
> + smp_wmb();
> sb->s_flags |= MS_RDONLY;
> }
> if (test_opt(sb, ERRORS_PANIC))
> @@ -571,8 +576,13 @@ void __ext4_abort(struct super_block *sb, const char *function,
>
> if ((sb->s_flags & MS_RDONLY) == 0) {
> ext4_msg(sb, KERN_CRIT, "Remounting filesystem read-only");
> - sb->s_flags |= MS_RDONLY;
> EXT4_SB(sb)->s_mount_flags |= EXT4_MF_FS_ABORTED;
> + /*
> + * Make shure updated value of ->s_mount_flags will be visiable
I think you meant 'sure' and 'visible' here and in the previous hunk.
--D
> + * before ->s_flags update
> + */
> + smp_wmb();
> + sb->s_flags |= MS_RDONLY;
> if (EXT4_SB(sb)->s_journal)
> jbd2_journal_abort(EXT4_SB(sb)->s_journal, -EIO);
> save_error_info(sb, function, line);
> --
> 1.7.1
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 7+ messages in thread* Re: [PATCH 3/3] ext4: Fix fsync error handling after filesystem abort.
2013-06-10 16:41 ` [PATCH 3/3] ext4: Fix fsync error handling after filesystem abort Dmitry Monakhov
2013-06-10 21:22 ` Darrick J. Wong
@ 2013-06-13 2:39 ` Theodore Ts'o
1 sibling, 0 replies; 7+ messages in thread
From: Theodore Ts'o @ 2013-06-13 2:39 UTC (permalink / raw)
To: Dmitry Monakhov; +Cc: linux-ext4, jack
On Mon, Jun 10, 2013 at 08:41:01PM +0400, Dmitry Monakhov wrote:
> If filesystem was aborted after inode's write back is complete
> but before its metadata was updated we may return success
> results in data loss.
> In order to handle fs abort correctly we have to check
> fs state once we discover that it is in MS_RDONLY state
>
> Test case: http://patchwork.ozlabs.org/patch/244297
>
> Changes from V2:
> - more spelling fixes
>
> Changes from V1:
> - fix spelling
>
> Reviewed-by: Jan Kara <jack@suse.cz>
> Signed-off-by: Dmitry Monakhov <dmonakhov@openvz.org>
Thanks, applied with Darrick's further suggested spelling fixes.
- Ted
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 1/3] jbd2: optimize jbd2_journal_force_commit V3
2013-06-10 16:40 [PATCH 1/3] jbd2: optimize jbd2_journal_force_commit V3 Dmitry Monakhov
2013-06-10 16:41 ` [PATCH 2/3] ext4: fix data integrity for ext4_sync_fs Dmitry Monakhov
2013-06-10 16:41 ` [PATCH 3/3] ext4: Fix fsync error handling after filesystem abort Dmitry Monakhov
@ 2013-06-13 0:42 ` Theodore Ts'o
2 siblings, 0 replies; 7+ messages in thread
From: Theodore Ts'o @ 2013-06-13 0:42 UTC (permalink / raw)
To: Dmitry Monakhov; +Cc: linux-ext4, jack
On Mon, Jun 10, 2013 at 08:40:59PM +0400, Dmitry Monakhov wrote:
> Current implementation of jbd2_journal_force_commit() is suboptimal because
> result in empty and useless commits. But callers just want to force and wait
> any unfinished commits. We already has jbd2_journal_force_commit_nested()
> which does exactly what we want, except we are guaranteed that we do not hold
> journal transaction open.
>
> Changes since V3 to V2
> - API changes according to Jan's comments
> - make __jbd2_journal_force_commit() static
>
> Changes since V2 to V1
> - Fix incorrect return value according to Jan's comments.
>
> Signed-off-by: Dmitry Monakhov <dmonakhov@openvz.org>
Applied, thanks.
- Ted
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2013-06-13 2:39 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-06-10 16:40 [PATCH 1/3] jbd2: optimize jbd2_journal_force_commit V3 Dmitry Monakhov
2013-06-10 16:41 ` [PATCH 2/3] ext4: fix data integrity for ext4_sync_fs Dmitry Monakhov
2013-06-13 2:32 ` Theodore Ts'o
2013-06-10 16:41 ` [PATCH 3/3] ext4: Fix fsync error handling after filesystem abort Dmitry Monakhov
2013-06-10 21:22 ` Darrick J. Wong
2013-06-13 2:39 ` Theodore Ts'o
2013-06-13 0:42 ` [PATCH 1/3] jbd2: optimize jbd2_journal_force_commit V3 Theodore Ts'o
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).