From: Jan Kara <jack@suse.cz>
To: Dmitry Monakhov <dmonakhov@openvz.org>
Cc: linux-fsdevel@vger.kernel.org, jack@suse.cz, hch@infradead.org
Subject: Re: [PATCH 01/12] quota: Add proper error handling on quota initialization.
Date: Thu, 20 May 2010 20:05:59 +0200 [thread overview]
Message-ID: <20100520180558.GM3395@quack.suse.cz> (raw)
In-Reply-To: <1274248928-5113-2-git-send-email-dmonakhov@openvz.org>
On Wed 19-05-10 10:01:57, Dmitry Monakhov wrote:
> Currently dqget_initialize() is a black-box so IO errors are simply
> ignored. In order to pass to the caller real error codes quota
> interface must being redesigned in following way.
>
> - return real error code from dqget()
> - return real error code from dquot_initialize()
>
> Now filesystem it is filesystem's responsibility to dquot_initialize()
> return value.
>
> Signed-off-by: Dmitry Monakhov <dmonakhov@openvz.org>
...
> diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c
> index 7c624e1..95aa445 100644
> --- a/fs/quota/dquot.c
> +++ b/fs/quota/dquot.c
> @@ -720,7 +720,7 @@ void dqput(struct dquot *dquot)
> {
> int ret;
>
> - if (!dquot)
> + if (!dquot || IS_ERR(dquot))
It is unusual for "put" functions to silently ignore IS_ERR pointer
(while it is common for them to ignore NULL). So I'd prefer to keep the
old test so that the behavior is consistent with the rest of kernel and
make sure no callers of dqput() pass IS_ERR pointer to it...
> @@ -1332,18 +1340,19 @@ static int info_bdq_free(struct dquot *dquot, qsize_t space)
> * It is better to call this function outside of any transaction as it
> * might need a lot of space in journal for dquot structure allocation.
> */
> -static void __dquot_initialize(struct inode *inode, int type)
> +static int __dquot_initialize(struct inode *inode, int type)
> {
> unsigned int id = 0;
> - int cnt;
> + int cnt, err = 0;
> struct dquot *got[MAXQUOTAS];
> struct super_block *sb = inode->i_sb;
> qsize_t rsv;
>
> +repeat:
> /* First test before acquiring mutex - solves deadlocks when we
> * re-enter the quota code and are already holding the mutex */
> if (!sb_any_quota_active(inode->i_sb) || IS_NOQUOTA(inode))
> - return;
> + return 0;
>
> /* First get references to structures we might need. */
> for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
> @@ -1362,35 +1371,50 @@ static void __dquot_initialize(struct inode *inode, int type)
> }
>
> down_write(&sb_dqopt(sb)->dqptr_sem);
> - if (IS_NOQUOTA(inode))
> + if (IS_NOQUOTA(inode)) {
> + err = 0;
> goto out_err;
> + }
> for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
> if (type != -1 && cnt != type)
> continue;
> /* Avoid races with quotaoff() */
> if (!sb_has_quota_active(sb, cnt))
> continue;
> - if (!inode->i_dquot[cnt]) {
> - inode->i_dquot[cnt] = got[cnt];
> - got[cnt] = NULL;
> - /*
> - * Make quota reservation system happy if someone
> - * did a write before quota was turned on
> - */
> - rsv = inode_get_rsv_space(inode);
> - if (unlikely(rsv))
> - dquot_resv_space(inode->i_dquot[cnt], rsv);
> + if (inode->i_dquot[cnt])
> + continue;
> + if (unlikely(IS_ERR(got[cnt]))) {
> + err = PTR_ERR(got[cnt]);
> + /* If dqget() was raced with quotaon() then we have to
> + * repeat lookup. */
If we race with quotaon(), then add_dquot_ref() is responsible for adding
proper dquot reference. Therefore there's no need to retry lookup.
Also I would do all the error checking just after dqget() because there's
not much point in doing it in this loop.
> + if (err == -ESRCH) {
> + err = 0;
> + up_write(&sb_dqopt(sb)->dqptr_sem);
> + dqput_all(got);
> + goto repeat;
> + }
> + goto out_err;
> }
> + inode->i_dquot[cnt] = got[cnt];
> + got[cnt] = NULL;
> + /*
> + * Make quota reservation system happy if someone
> + * did a write before quota was turned on
> + */
> + rsv = inode_get_rsv_space(inode);
> + if (unlikely(rsv))
> + dquot_resv_space(inode->i_dquot[cnt], rsv);
> }
> out_err:
> up_write(&sb_dqopt(sb)->dqptr_sem);
> /* Drop unused references */
> dqput_all(got);
> + return err;
> }
>
> -void dquot_initialize(struct inode *inode)
> +int dquot_initialize(struct inode *inode)
> {
> - __dquot_initialize(inode, -1);
> + return __dquot_initialize(inode, -1);
> }
> EXPORT_SYMBOL(dquot_initialize);
>
...
> @@ -2092,24 +2127,30 @@ static int vfs_load_quota_inode(struct inode *inode, int type, int format_id,
> }
> mutex_unlock(&dqopt->dqio_mutex);
> spin_lock(&dq_state_lock);
> + dqflags = dqopt->flags;
> dqopt->flags |= dquot_state_flag(flags, type);
> spin_unlock(&dq_state_lock);
>
> - add_dquot_ref(sb, type);
> + error = add_dquot_ref(sb, type);
> + if (error)
> + goto out_dquot_init;
This is actually wrong as quota state flags have already been set and
quota for some inodes is already initialized and even may have been already
changed. So I think you have no other option than release dqonoff_mutex and
call dquot_disable (that's the name after Christoph's cleanups) to cleanup
everything...
> mutex_unlock(&dqopt->dqonoff_mutex);
>
> return 0;
> -
> +out_dquot_init:
> + spin_lock(&dq_state_lock);
> + dqopt->flags = dqflags;
> + spin_unlock(&dq_state_lock);
> out_file_init:
> dqopt->files[type] = NULL;
> iput(inode);
> out_lock:
> - if (oldflags != -1) {
> + if (iflags != -1) {
> mutex_lock_nested(&inode->i_mutex, I_MUTEX_QUOTA);
> /* Set the flags back (in the case of accidental quotaon()
> * on a wrong file we don't want to mess up the flags) */
> inode->i_flags &= ~(S_NOATIME | S_NOQUOTA | S_IMMUTABLE);
> - inode->i_flags |= oldflags;
> + inode->i_flags |= iflags;
> mutex_unlock(&inode->i_mutex);
> }
> mutex_unlock(&dqopt->dqonoff_mutex);
Honza
--
Jan Kara <jack@suse.cz>
SUSE Labs, CR
prev parent reply other threads:[~2010-05-20 18:06 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-05-19 6:01 [PATCH 00/12] quota: Redesign IO error handling interface V2 Dmitry Monakhov
2010-05-19 6:01 ` [PATCH 01/12] quota: Add proper error handling on quota initialization Dmitry Monakhov
2010-05-19 6:01 ` [PATCH 02/12] quota: Check what quota is properly initialized for inode before charge Dmitry Monakhov
2010-05-19 6:01 ` [PATCH 03/12] ext3: handle errors in orphan_cleanup Dmitry Monakhov
2010-05-19 6:02 ` [PATCH 04/12] ext4: " Dmitry Monakhov
2010-05-19 6:02 ` [PATCH 05/12] ufs: add error handling for dquot_initialize Dmitry Monakhov
2010-05-19 6:02 ` [PATCH 06/12] udf: " Dmitry Monakhov
2010-05-19 6:02 ` [PATCH 07/12] reiserfs: " Dmitry Monakhov
2010-05-19 6:02 ` [PATCH 08/12] ocfs2: " Dmitry Monakhov
2010-05-19 6:02 ` [PATCH 09/12] jfs: " Dmitry Monakhov
2010-05-19 6:02 ` [PATCH 10/12] ext4: " Dmitry Monakhov
2010-05-19 6:02 ` [PATCH 11/12] ext3: " Dmitry Monakhov
2010-05-19 6:02 ` [PATCH 12/12] ext2: " Dmitry Monakhov
2010-05-20 17:30 ` Jan Kara
2010-05-20 17:32 ` [PATCH 11/12] ext3: " Jan Kara
2010-05-20 17:34 ` [PATCH 06/12] udf: " Jan Kara
2010-05-20 17:33 ` [PATCH 05/12] ufs: " Jan Kara
2010-05-20 17:35 ` [PATCH 03/12] ext3: handle errors in orphan_cleanup Jan Kara
2010-05-20 18:13 ` [PATCH 02/12] quota: Check what quota is properly initialized for inode before charge Jan Kara
2010-05-20 18:05 ` Jan Kara [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20100520180558.GM3395@quack.suse.cz \
--to=jack@suse.cz \
--cc=dmonakhov@openvz.org \
--cc=hch@infradead.org \
--cc=linux-fsdevel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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).