2015-07-15 12:42:26

by Jan Kara

[permalink] [raw]
Subject: [PATCH 0/6] quota: Propagate errors when creating quota entry

Hello,

this patch set makes quota code report errors when quota entry creation fails (upto
now such errors were silently ignored). Filesystems can then properly handle the errors
and report them to userspace. Patch set also includes patches to all filesystems to
properly handle the errors. Review by respective fs maintainers is welcome.

If noone objects, I will queue these patches in my tree for the next merge window.

Honza


2015-07-15 12:42:28

by Jan Kara

[permalink] [raw]
Subject: [PATCH 2/6] ext2: Handle error from dquot_initalize()

dquot_initialize() can now return error. Handle it where possible.

Signed-off-by: Jan Kara <[email protected]>
---
fs/ext2/ialloc.c | 5 ++++-
fs/ext2/inode.c | 7 +++++--
fs/ext2/namei.c | 46 ++++++++++++++++++++++++++++++++++------------
3 files changed, 43 insertions(+), 15 deletions(-)

diff --git a/fs/ext2/ialloc.c b/fs/ext2/ialloc.c
index 5c04a0ddea80..efe5fb21c533 100644
--- a/fs/ext2/ialloc.c
+++ b/fs/ext2/ialloc.c
@@ -577,7 +577,10 @@ got:
goto fail;
}

- dquot_initialize(inode);
+ err = dquot_initialize(inode);
+ if (err)
+ goto fail_drop;
+
err = dquot_alloc_inode(inode);
if (err)
goto fail_drop;
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
index 5c09776d347f..a3a404c5df2e 100644
--- a/fs/ext2/inode.c
+++ b/fs/ext2/inode.c
@@ -1552,8 +1552,11 @@ int ext2_setattr(struct dentry *dentry, struct iattr *iattr)
if (error)
return error;

- if (is_quota_modification(inode, iattr))
- dquot_initialize(inode);
+ if (is_quota_modification(inode, iattr)) {
+ error = dquot_initialize(inode);
+ if (error)
+ return error;
+ }
if ((iattr->ia_valid & ATTR_UID && !uid_eq(iattr->ia_uid, inode->i_uid)) ||
(iattr->ia_valid & ATTR_GID && !gid_eq(iattr->ia_gid, inode->i_gid))) {
error = dquot_transfer(inode, iattr);
diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c
index 13ec54a99c96..b4841e3066a5 100644
--- a/fs/ext2/namei.c
+++ b/fs/ext2/namei.c
@@ -96,8 +96,11 @@ struct dentry *ext2_get_parent(struct dentry *child)
static int ext2_create (struct inode * dir, struct dentry * dentry, umode_t mode, bool excl)
{
struct inode *inode;
+ int err;

- dquot_initialize(dir);
+ err = dquot_initialize(dir);
+ if (err)
+ return err;

inode = ext2_new_inode(dir, mode, &dentry->d_name);
if (IS_ERR(inode))
@@ -143,7 +146,9 @@ static int ext2_mknod (struct inode * dir, struct dentry *dentry, umode_t mode,
if (!new_valid_dev(rdev))
return -EINVAL;

- dquot_initialize(dir);
+ err = dquot_initialize(dir);
+ if (err)
+ return err;

inode = ext2_new_inode (dir, mode, &dentry->d_name);
err = PTR_ERR(inode);
@@ -169,7 +174,9 @@ static int ext2_symlink (struct inode * dir, struct dentry * dentry,
if (l > sb->s_blocksize)
goto out;

- dquot_initialize(dir);
+ err = dquot_initialize(dir);
+ if (err)
+ goto out;

inode = ext2_new_inode (dir, S_IFLNK | S_IRWXUGO, &dentry->d_name);
err = PTR_ERR(inode);
@@ -212,7 +219,9 @@ static int ext2_link (struct dentry * old_dentry, struct inode * dir,
struct inode *inode = d_inode(old_dentry);
int err;

- dquot_initialize(dir);
+ err = dquot_initialize(dir);
+ if (err)
+ return err;

inode->i_ctime = CURRENT_TIME_SEC;
inode_inc_link_count(inode);
@@ -233,7 +242,9 @@ static int ext2_mkdir(struct inode * dir, struct dentry * dentry, umode_t mode)
struct inode * inode;
int err;

- dquot_initialize(dir);
+ err = dquot_initialize(dir);
+ if (err)
+ return err;

inode_inc_link_count(dir);

@@ -279,13 +290,17 @@ static int ext2_unlink(struct inode * dir, struct dentry *dentry)
struct inode * inode = d_inode(dentry);
struct ext2_dir_entry_2 * de;
struct page * page;
- int err = -ENOENT;
+ int err;

- dquot_initialize(dir);
+ err = dquot_initialize(dir);
+ if (err)
+ goto out;

de = ext2_find_entry (dir, &dentry->d_name, &page);
- if (!de)
+ if (!de) {
+ err = -ENOENT;
goto out;
+ }

err = ext2_delete_entry (de, page);
if (err)
@@ -323,14 +338,21 @@ static int ext2_rename (struct inode * old_dir, struct dentry * old_dentry,
struct ext2_dir_entry_2 * dir_de = NULL;
struct page * old_page;
struct ext2_dir_entry_2 * old_de;
- int err = -ENOENT;
+ int err;
+
+ err = dquot_initialize(old_dir);
+ if (err)
+ goto out;

- dquot_initialize(old_dir);
- dquot_initialize(new_dir);
+ err = dquot_initialize(new_dir);
+ if (err)
+ goto out;

old_de = ext2_find_entry (old_dir, &old_dentry->d_name, &old_page);
- if (!old_de)
+ if (!old_de) {
+ err = -ENOENT;
goto out;
+ }

if (S_ISDIR(old_inode->i_mode)) {
err = -EIO;
--
2.1.4


2015-07-15 12:42:32

by Jan Kara

[permalink] [raw]
Subject: [PATCH 6/6] reiserfs: Handle error from dquot_initialize()

dquot_initialize() can now return error. Handle it where possible.

Signed-off-by: Jan Kara <[email protected]>
---
fs/reiserfs/inode.c | 7 ++++--
fs/reiserfs/namei.c | 63 ++++++++++++++++++++++++++++++++++++++++-------------
2 files changed, 53 insertions(+), 17 deletions(-)

diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c
index f6f2fbad9777..3d8e7e671d5b 100644
--- a/fs/reiserfs/inode.c
+++ b/fs/reiserfs/inode.c
@@ -3319,8 +3319,11 @@ int reiserfs_setattr(struct dentry *dentry, struct iattr *attr)
/* must be turned off for recursive notify_change calls */
ia_valid = attr->ia_valid &= ~(ATTR_KILL_SUID|ATTR_KILL_SGID);

- if (is_quota_modification(inode, attr))
- dquot_initialize(inode);
+ if (is_quota_modification(inode, attr)) {
+ error = dquot_initialize(inode);
+ if (error)
+ return error;
+ }
reiserfs_write_lock(inode->i_sb);
if (attr->ia_valid & ATTR_SIZE) {
/*
diff --git a/fs/reiserfs/namei.c b/fs/reiserfs/namei.c
index b55a074653d7..5f1c9c29eb8c 100644
--- a/fs/reiserfs/namei.c
+++ b/fs/reiserfs/namei.c
@@ -613,8 +613,7 @@ static int new_inode_init(struct inode *inode, struct inode *dir, umode_t mode)
* we have to set uid and gid here
*/
inode_init_owner(inode, dir, mode);
- dquot_initialize(inode);
- return 0;
+ return dquot_initialize(inode);
}

static int reiserfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
@@ -633,12 +632,18 @@ static int reiserfs_create(struct inode *dir, struct dentry *dentry, umode_t mod
struct reiserfs_transaction_handle th;
struct reiserfs_security_handle security;

- dquot_initialize(dir);
+ retval = dquot_initialize(dir);
+ if (retval)
+ return retval;

if (!(inode = new_inode(dir->i_sb))) {
return -ENOMEM;
}
- new_inode_init(inode, dir, mode);
+ retval = new_inode_init(inode, dir, mode);
+ if (retval) {
+ drop_new_inode(inode);
+ return retval;
+ }

jbegin_count += reiserfs_cache_default_acl(dir);
retval = reiserfs_security_init(dir, inode, &dentry->d_name, &security);
@@ -710,12 +715,18 @@ static int reiserfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode
if (!new_valid_dev(rdev))
return -EINVAL;

- dquot_initialize(dir);
+ retval = dquot_initialize(dir);
+ if (retval)
+ return retval;

if (!(inode = new_inode(dir->i_sb))) {
return -ENOMEM;
}
- new_inode_init(inode, dir, mode);
+ retval = new_inode_init(inode, dir, mode);
+ if (retval) {
+ drop_new_inode(inode);
+ return retval;
+ }

jbegin_count += reiserfs_cache_default_acl(dir);
retval = reiserfs_security_init(dir, inode, &dentry->d_name, &security);
@@ -787,7 +798,9 @@ static int reiserfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode
2 * (REISERFS_QUOTA_INIT_BLOCKS(dir->i_sb) +
REISERFS_QUOTA_TRANS_BLOCKS(dir->i_sb));

- dquot_initialize(dir);
+ retval = dquot_initialize(dir);
+ if (retval)
+ return retval;

#ifdef DISPLACE_NEW_PACKING_LOCALITIES
/*
@@ -800,7 +813,11 @@ static int reiserfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode
if (!(inode = new_inode(dir->i_sb))) {
return -ENOMEM;
}
- new_inode_init(inode, dir, mode);
+ retval = new_inode_init(inode, dir, mode);
+ if (retval) {
+ drop_new_inode(inode);
+ return retval;
+ }

jbegin_count += reiserfs_cache_default_acl(dir);
retval = reiserfs_security_init(dir, inode, &dentry->d_name, &security);
@@ -899,7 +916,9 @@ static int reiserfs_rmdir(struct inode *dir, struct dentry *dentry)
JOURNAL_PER_BALANCE_CNT * 2 + 2 +
4 * REISERFS_QUOTA_TRANS_BLOCKS(dir->i_sb);

- dquot_initialize(dir);
+ retval = dquot_initialize(dir);
+ if (retval)
+ return retval;

reiserfs_write_lock(dir->i_sb);
retval = journal_begin(&th, dir->i_sb, jbegin_count);
@@ -985,7 +1004,9 @@ static int reiserfs_unlink(struct inode *dir, struct dentry *dentry)
int jbegin_count;
unsigned long savelink;

- dquot_initialize(dir);
+ retval = dquot_initialize(dir);
+ if (retval)
+ return retval;

inode = d_inode(dentry);

@@ -1095,12 +1116,18 @@ static int reiserfs_symlink(struct inode *parent_dir,
2 * (REISERFS_QUOTA_INIT_BLOCKS(parent_dir->i_sb) +
REISERFS_QUOTA_TRANS_BLOCKS(parent_dir->i_sb));

- dquot_initialize(parent_dir);
+ retval = dquot_initialize(parent_dir);
+ if (retval)
+ return retval;

if (!(inode = new_inode(parent_dir->i_sb))) {
return -ENOMEM;
}
- new_inode_init(inode, parent_dir, mode);
+ retval = new_inode_init(inode, parent_dir, mode);
+ if (retval) {
+ drop_new_inode(inode);
+ return retval;
+ }

retval = reiserfs_security_init(parent_dir, inode, &dentry->d_name,
&security);
@@ -1184,7 +1211,9 @@ static int reiserfs_link(struct dentry *old_dentry, struct inode *dir,
JOURNAL_PER_BALANCE_CNT * 3 +
2 * REISERFS_QUOTA_TRANS_BLOCKS(dir->i_sb);

- dquot_initialize(dir);
+ retval = dquot_initialize(dir);
+ if (retval)
+ return retval;

reiserfs_write_lock(dir->i_sb);
if (inode->i_nlink >= REISERFS_LINK_MAX) {
@@ -1308,8 +1337,12 @@ static int reiserfs_rename(struct inode *old_dir, struct dentry *old_dentry,
JOURNAL_PER_BALANCE_CNT * 3 + 5 +
4 * REISERFS_QUOTA_TRANS_BLOCKS(old_dir->i_sb);

- dquot_initialize(old_dir);
- dquot_initialize(new_dir);
+ retval = dquot_initialize(old_dir);
+ if (retval)
+ return retval;
+ retval = dquot_initialize(new_dir);
+ if (retval)
+ return retval;

old_inode = d_inode(old_dentry);
new_dentry_inode = d_inode(new_dentry);
--
2.1.4


2015-07-15 12:42:31

by Jan Kara

[permalink] [raw]
Subject: [PATCH 5/6] jfs: Handle error from dquot_initialize()

dquot_initialize() can now return error. Handle it where possible.

Signed-off-by: Jan Kara <[email protected]>
---
fs/jfs/file.c | 7 +++++--
fs/jfs/jfs_inode.c | 4 +++-
fs/jfs/namei.c | 53 +++++++++++++++++++++++++++++++++++++++--------------
3 files changed, 47 insertions(+), 17 deletions(-)

diff --git a/fs/jfs/file.c b/fs/jfs/file.c
index e98d39d75cf4..34ad63ea0280 100644
--- a/fs/jfs/file.c
+++ b/fs/jfs/file.c
@@ -107,8 +107,11 @@ int jfs_setattr(struct dentry *dentry, struct iattr *iattr)
if (rc)
return rc;

- if (is_quota_modification(inode, iattr))
- dquot_initialize(inode);
+ if (is_quota_modification(inode, iattr)) {
+ rc = dquot_initialize(inode);
+ if (rc)
+ return rc;
+ }
if ((iattr->ia_valid & ATTR_UID && !uid_eq(iattr->ia_uid, inode->i_uid)) ||
(iattr->ia_valid & ATTR_GID && !gid_eq(iattr->ia_gid, inode->i_gid))) {
rc = dquot_transfer(inode, iattr);
diff --git a/fs/jfs/jfs_inode.c b/fs/jfs/jfs_inode.c
index 6b0f816201a2..cf7936fe2e68 100644
--- a/fs/jfs/jfs_inode.c
+++ b/fs/jfs/jfs_inode.c
@@ -109,7 +109,9 @@ struct inode *ialloc(struct inode *parent, umode_t mode)
/*
* Allocate inode to quota.
*/
- dquot_initialize(inode);
+ rc = dquot_initialize(inode);
+ if (rc)
+ goto fail_drop;
rc = dquot_alloc_inode(inode);
if (rc)
goto fail_drop;
diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c
index e33be921aa41..fb28ce85aa52 100644
--- a/fs/jfs/namei.c
+++ b/fs/jfs/namei.c
@@ -86,7 +86,9 @@ static int jfs_create(struct inode *dip, struct dentry *dentry, umode_t mode,

jfs_info("jfs_create: dip:0x%p name:%pd", dip, dentry);

- dquot_initialize(dip);
+ rc = dquot_initialize(dip);
+ if (rc)
+ goto out1;

/*
* search parent directory for entry/freespace
@@ -218,7 +220,9 @@ static int jfs_mkdir(struct inode *dip, struct dentry *dentry, umode_t mode)

jfs_info("jfs_mkdir: dip:0x%p name:%pd", dip, dentry);

- dquot_initialize(dip);
+ rc = dquot_initialize(dip);
+ if (rc)
+ goto out1;

/*
* search parent directory for entry/freespace
@@ -355,8 +359,12 @@ static int jfs_rmdir(struct inode *dip, struct dentry *dentry)
jfs_info("jfs_rmdir: dip:0x%p name:%pd", dip, dentry);

/* Init inode for quota operations. */
- dquot_initialize(dip);
- dquot_initialize(ip);
+ rc = dquot_initialize(dip);
+ if (rc)
+ goto out;
+ rc = dquot_initialize(ip);
+ if (rc)
+ goto out;

/* directory must be empty to be removed */
if (!dtEmpty(ip)) {
@@ -483,8 +491,12 @@ static int jfs_unlink(struct inode *dip, struct dentry *dentry)
jfs_info("jfs_unlink: dip:0x%p name:%pd", dip, dentry);

/* Init inode for quota operations. */
- dquot_initialize(dip);
- dquot_initialize(ip);
+ rc = dquot_initialize(dip);
+ if (rc)
+ goto out;
+ rc = dquot_initialize(ip);
+ if (rc)
+ goto out;

if ((rc = get_UCSname(&dname, dentry)))
goto out;
@@ -799,7 +811,9 @@ static int jfs_link(struct dentry *old_dentry,

jfs_info("jfs_link: %pd %pd", old_dentry, dentry);

- dquot_initialize(dir);
+ rc = dquot_initialize(dir);
+ if (rc)
+ goto out;

tid = txBegin(ip->i_sb, 0);

@@ -810,7 +824,7 @@ static int jfs_link(struct dentry *old_dentry,
* scan parent directory for entry/freespace
*/
if ((rc = get_UCSname(&dname, dentry)))
- goto out;
+ goto out_tx;

if ((rc = dtSearch(dir, &dname, &ino, &btstack, JFS_CREATE)))
goto free_dname;
@@ -842,12 +856,13 @@ static int jfs_link(struct dentry *old_dentry,
free_dname:
free_UCSname(&dname);

- out:
+ out_tx:
txEnd(tid);

mutex_unlock(&JFS_IP(ip)->commit_mutex);
mutex_unlock(&JFS_IP(dir)->commit_mutex);

+ out:
jfs_info("jfs_link: rc:%d", rc);
return rc;
}
@@ -891,7 +906,9 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry,

jfs_info("jfs_symlink: dip:0x%p name:%s", dip, name);

- dquot_initialize(dip);
+ rc = dquot_initialize(dip);
+ if (rc)
+ goto out1;

ssize = strlen(name) + 1;

@@ -1082,8 +1099,12 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,

jfs_info("jfs_rename: %pd %pd", old_dentry, new_dentry);

- dquot_initialize(old_dir);
- dquot_initialize(new_dir);
+ rc = dquot_initialize(old_dir);
+ if (rc)
+ goto out1;
+ rc = dquot_initialize(new_dir);
+ if (rc)
+ goto out1;

old_ip = d_inode(old_dentry);
new_ip = d_inode(new_dentry);
@@ -1130,7 +1151,9 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
} else if (new_ip) {
IWRITE_LOCK(new_ip, RDWRLOCK_NORMAL);
/* Init inode for quota operations. */
- dquot_initialize(new_ip);
+ rc = dquot_initialize(new_ip);
+ if (rc)
+ goto out3;
}

/*
@@ -1354,7 +1377,9 @@ static int jfs_mknod(struct inode *dir, struct dentry *dentry,

jfs_info("jfs_mknod: %pd", dentry);

- dquot_initialize(dir);
+ rc = dquot_initialize(dir);
+ if (rc)
+ goto out;

if ((rc = get_UCSname(&dname, dentry)))
goto out;
--
2.1.4


2015-07-15 12:42:27

by Jan Kara

[permalink] [raw]
Subject: [PATCH 1/6] quota: Propagate error from ->acquire_dquot()

From: Jan Kara <[email protected]>

Currently when some error happened in ->acquire_dquot(), dqget() just
returned NULL. That was indistinguishable from a case when e.g. someone
run quotaoff and so was generally silently ignored. However
->acquire_dquot() can fail because of ENOSPC or EIO in which case user
should better know. So propagate error up from ->acquire_dquot properly.

Signed-off-by: Jan Kara <[email protected]>
---
fs/ocfs2/file.c | 8 ++---
fs/ocfs2/quota_local.c | 4 +--
fs/quota/dquot.c | 88 ++++++++++++++++++++++++++++++++++--------------
include/linux/quotaops.h | 2 +-
4 files changed, 70 insertions(+), 32 deletions(-)

diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c
index 719f7f4c7a37..4d9e8275ed99 100644
--- a/fs/ocfs2/file.c
+++ b/fs/ocfs2/file.c
@@ -1209,8 +1209,8 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)
&& OCFS2_HAS_RO_COMPAT_FEATURE(sb,
OCFS2_FEATURE_RO_COMPAT_USRQUOTA)) {
transfer_to[USRQUOTA] = dqget(sb, make_kqid_uid(attr->ia_uid));
- if (!transfer_to[USRQUOTA]) {
- status = -ESRCH;
+ if (IS_ERR(transfer_to[USRQUOTA])) {
+ status = PTR_ERR(transfer_to[USRQUOTA]);
goto bail_unlock;
}
}
@@ -1218,8 +1218,8 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)
&& OCFS2_HAS_RO_COMPAT_FEATURE(sb,
OCFS2_FEATURE_RO_COMPAT_GRPQUOTA)) {
transfer_to[GRPQUOTA] = dqget(sb, make_kqid_gid(attr->ia_gid));
- if (!transfer_to[GRPQUOTA]) {
- status = -ESRCH;
+ if (IS_ERR(transfer_to[GRPQUOTA])) {
+ status = PTR_ERR(transfer_to[GRPQUOTA]);
goto bail_unlock;
}
}
diff --git a/fs/ocfs2/quota_local.c b/fs/ocfs2/quota_local.c
index 3d0b63d34225..bb07004df72a 100644
--- a/fs/ocfs2/quota_local.c
+++ b/fs/ocfs2/quota_local.c
@@ -499,8 +499,8 @@ static int ocfs2_recover_local_quota_file(struct inode *lqinode,
dquot = dqget(sb,
make_kqid(&init_user_ns, type,
le64_to_cpu(dqblk->dqb_id)));
- if (!dquot) {
- status = -EIO;
+ if (IS_ERR(dquot)) {
+ status = PTR_ERR(dquot);
mlog(ML_ERROR, "Failed to get quota structure "
"for id %u, type %d. Cannot finish quota "
"file recovery.\n",
diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c
index 20d1f74561cf..e9354c2ae0b0 100644
--- a/fs/quota/dquot.c
+++ b/fs/quota/dquot.c
@@ -247,7 +247,7 @@ struct dqstats dqstats;
EXPORT_SYMBOL(dqstats);

static qsize_t inode_get_rsv_space(struct inode *inode);
-static void __dquot_initialize(struct inode *inode, int type);
+static int __dquot_initialize(struct inode *inode, int type);

static inline unsigned int
hashfn(const struct super_block *sb, struct kqid qid)
@@ -832,16 +832,17 @@ static struct dquot *get_empty_dquot(struct super_block *sb, int type)
struct dquot *dqget(struct super_block *sb, struct kqid qid)
{
unsigned int hashent = hashfn(sb, qid);
- struct dquot *dquot = NULL, *empty = NULL;
+ struct dquot *dquot, *empty = NULL;

if (!sb_has_quota_active(sb, qid.type))
- return NULL;
+ return ERR_PTR(-ESRCH);
we_slept:
spin_lock(&dq_list_lock);
spin_lock(&dq_state_lock);
if (!sb_has_quota_active(sb, qid.type)) {
spin_unlock(&dq_state_lock);
spin_unlock(&dq_list_lock);
+ dquot = ERR_PTR(-ESRCH);
goto out;
}
spin_unlock(&dq_state_lock);
@@ -876,11 +877,15 @@ we_slept:
* already finished or it will be canceled due to dq_count > 1 test */
wait_on_dquot(dquot);
/* Read the dquot / allocate space in quota file */
- if (!test_bit(DQ_ACTIVE_B, &dquot->dq_flags) &&
- sb->dq_op->acquire_dquot(dquot) < 0) {
- dqput(dquot);
- dquot = NULL;
- goto out;
+ if (!test_bit(DQ_ACTIVE_B, &dquot->dq_flags)) {
+ int err;
+
+ err = sb->dq_op->acquire_dquot(dquot);
+ if (err < 0) {
+ dqput(dquot);
+ dquot = ERR_PTR(err);
+ goto out;
+ }
}
#ifdef CONFIG_QUOTA_DEBUG
BUG_ON(!dquot->dq_sb); /* Has somebody invalidated entry under us? */
@@ -1390,15 +1395,16 @@ static int dquot_active(const struct inode *inode)
* 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)
{
int cnt, init_needed = 0;
struct dquot **dquots, *got[MAXQUOTAS];
struct super_block *sb = inode->i_sb;
qsize_t rsv;
+ int ret = 0;

if (!dquot_active(inode))
- return;
+ return 0;

dquots = i_dquot(inode);

@@ -1407,6 +1413,7 @@ static void __dquot_initialize(struct inode *inode, int type)
struct kqid qid;
kprojid_t projid;
int rc;
+ struct dquot *dquot;

got[cnt] = NULL;
if (type != -1 && cnt != type)
@@ -1438,16 +1445,25 @@ static void __dquot_initialize(struct inode *inode, int type)
qid = make_kqid_projid(projid);
break;
}
- got[cnt] = dqget(sb, qid);
+ dquot = dqget(sb, qid);
+ if (IS_ERR(dquot)) {
+ /* We raced with somebody turning quotas off... */
+ if (PTR_ERR(dquot) != -ESRCH) {
+ ret = PTR_ERR(dquot);
+ goto out_put;
+ }
+ dquot = NULL;
+ }
+ got[cnt] = dquot;
}

/* All required i_dquot has been initialized */
if (!init_needed)
- return;
+ return 0;

spin_lock(&dq_data_lock);
if (IS_NOQUOTA(inode))
- goto out_err;
+ goto out_lock;
for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
if (type != -1 && cnt != type)
continue;
@@ -1469,15 +1485,18 @@ static void __dquot_initialize(struct inode *inode, int type)
dquot_resv_space(dquots[cnt], rsv);
}
}
-out_err:
+out_lock:
spin_unlock(&dq_data_lock);
+out_put:
/* Drop unused references */
dqput_all(got);
+
+ return ret;
}

-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);

@@ -1961,18 +1980,37 @@ EXPORT_SYMBOL(__dquot_transfer);
int dquot_transfer(struct inode *inode, struct iattr *iattr)
{
struct dquot *transfer_to[MAXQUOTAS] = {};
+ struct dquot *dquot;
struct super_block *sb = inode->i_sb;
int ret;

if (!dquot_active(inode))
return 0;

- if (iattr->ia_valid & ATTR_UID && !uid_eq(iattr->ia_uid, inode->i_uid))
- transfer_to[USRQUOTA] = dqget(sb, make_kqid_uid(iattr->ia_uid));
- if (iattr->ia_valid & ATTR_GID && !gid_eq(iattr->ia_gid, inode->i_gid))
- transfer_to[GRPQUOTA] = dqget(sb, make_kqid_gid(iattr->ia_gid));
-
+ if (iattr->ia_valid & ATTR_UID && !uid_eq(iattr->ia_uid, inode->i_uid)){
+ dquot = dqget(sb, make_kqid_uid(iattr->ia_uid));
+ if (IS_ERR(dquot)) {
+ if (PTR_ERR(dquot) != -ESRCH) {
+ ret = PTR_ERR(dquot);
+ goto out_put;
+ }
+ dquot = NULL;
+ }
+ transfer_to[USRQUOTA] = dquot;;
+ }
+ if (iattr->ia_valid & ATTR_GID && !gid_eq(iattr->ia_gid, inode->i_gid)){
+ dquot = dqget(sb, make_kqid_gid(iattr->ia_gid));
+ if (IS_ERR(dquot)) {
+ if (PTR_ERR(dquot) != -ESRCH) {
+ ret = PTR_ERR(dquot);
+ goto out_put;
+ }
+ dquot = NULL;
+ }
+ transfer_to[GRPQUOTA] = dquot;
+ }
ret = __dquot_transfer(inode, transfer_to);
+out_put:
dqput_all(transfer_to);
return ret;
}
@@ -2518,8 +2556,8 @@ int dquot_get_dqblk(struct super_block *sb, struct kqid qid,
struct dquot *dquot;

dquot = dqget(sb, qid);
- if (!dquot)
- return -ESRCH;
+ if (IS_ERR(dquot))
+ return PTR_ERR(dquot);
do_get_dqblk(dquot, di);
dqput(dquot);

@@ -2631,8 +2669,8 @@ int dquot_set_dqblk(struct super_block *sb, struct kqid qid,
int rc;

dquot = dqget(sb, qid);
- if (!dquot) {
- rc = -ESRCH;
+ if (IS_ERR(dquot)) {
+ rc = PTR_ERR(dquot);
goto out;
}
rc = do_set_dqblk(dquot, di);
diff --git a/include/linux/quotaops.h b/include/linux/quotaops.h
index 77ca6601ff25..06c9ea8971fb 100644
--- a/include/linux/quotaops.h
+++ b/include/linux/quotaops.h
@@ -43,7 +43,7 @@ void inode_claim_rsv_space(struct inode *inode, qsize_t number);
void inode_sub_rsv_space(struct inode *inode, qsize_t number);
void inode_reclaim_rsv_space(struct inode *inode, qsize_t number);

-void dquot_initialize(struct inode *inode);
+int dquot_initialize(struct inode *inode);
void dquot_drop(struct inode *inode);
struct dquot *dqget(struct super_block *sb, struct kqid qid);
static inline struct dquot *dqgrab(struct dquot *dquot)
--
2.1.4


2015-07-15 12:42:30

by Jan Kara

[permalink] [raw]
Subject: [PATCH 4/6] ocfs2: Handle error from dquot_initialize()

dquot_initialize() can now return error. Handle it where possible.

Signed-off-by: Jan Kara <[email protected]>
---
fs/ocfs2/file.c | 14 ++++++++----
fs/ocfs2/namei.c | 59 +++++++++++++++++++++++++++++++++++++------------
fs/ocfs2/refcounttree.c | 5 +++--
3 files changed, 58 insertions(+), 20 deletions(-)

diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c
index 4d9e8275ed99..7210583b472f 100644
--- a/fs/ocfs2/file.c
+++ b/fs/ocfs2/file.c
@@ -105,8 +105,11 @@ static int ocfs2_file_open(struct inode *inode, struct file *file)
file->f_path.dentry->d_name.len,
file->f_path.dentry->d_name.name, mode);

- if (file->f_mode & FMODE_WRITE)
- dquot_initialize(inode);
+ if (file->f_mode & FMODE_WRITE) {
+ status = dquot_initialize(inode);
+ if (status)
+ goto leave;
+ }

spin_lock(&oi->ip_lock);

@@ -1155,8 +1158,11 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)
if (status)
return status;

- if (is_quota_modification(inode, attr))
- dquot_initialize(inode);
+ if (is_quota_modification(inode, attr)) {
+ status = dquot_initialize(inode);
+ if (status)
+ return status;
+ }
size_change = S_ISREG(inode->i_mode) && attr->ia_valid & ATTR_SIZE;
if (size_change) {
status = ocfs2_rw_lock(inode, 1);
diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c
index 6e6abb93fda5..948681e37cfd 100644
--- a/fs/ocfs2/namei.c
+++ b/fs/ocfs2/namei.c
@@ -200,11 +200,12 @@ bail:
static struct inode *ocfs2_get_init_inode(struct inode *dir, umode_t mode)
{
struct inode *inode;
+ int status;

inode = new_inode(dir->i_sb);
if (!inode) {
mlog(ML_ERROR, "new_inode failed!\n");
- return NULL;
+ return ERR_PTR(-ENOMEM);
}

/* populate as many fields early on as possible - many of
@@ -213,7 +214,10 @@ static struct inode *ocfs2_get_init_inode(struct inode *dir, umode_t mode)
if (S_ISDIR(mode))
set_nlink(inode, 2);
inode_init_owner(inode, dir, mode);
- dquot_initialize(inode);
+ status = dquot_initialize(inode);
+ if (status)
+ return ERR_PTR(status);
+
return inode;
}

@@ -264,7 +268,11 @@ static int ocfs2_mknod(struct inode *dir,
(unsigned long long)OCFS2_I(dir)->ip_blkno,
(unsigned long)dev, mode);

- dquot_initialize(dir);
+ status = dquot_initialize(dir);
+ if (status) {
+ mlog_errno(status);
+ return status;
+ }

/* get our super block */
osb = OCFS2_SB(dir->i_sb);
@@ -311,8 +319,9 @@ static int ocfs2_mknod(struct inode *dir,
}

inode = ocfs2_get_init_inode(dir, mode);
- if (!inode) {
- status = -ENOMEM;
+ if (IS_ERR(inode)) {
+ status = PTR_ERR(inode);
+ inode = NULL;
mlog_errno(status);
goto leave;
}
@@ -708,7 +717,11 @@ static int ocfs2_link(struct dentry *old_dentry,
if (S_ISDIR(inode->i_mode))
return -EPERM;

- dquot_initialize(dir);
+ err = dquot_initialize(dir);
+ if (err) {
+ mlog_errno(err);
+ return err;
+ }

err = ocfs2_double_lock(osb, &old_dir_bh, old_dir,
&parent_fe_bh, dir, 0);
@@ -896,7 +909,11 @@ static int ocfs2_unlink(struct inode *dir,
(unsigned long long)OCFS2_I(dir)->ip_blkno,
(unsigned long long)OCFS2_I(inode)->ip_blkno);

- dquot_initialize(dir);
+ status = dquot_initialize(dir);
+ if (status) {
+ mlog_errno(status);
+ return status;
+ }

BUG_ON(d_inode(dentry->d_parent) != dir);

@@ -1230,8 +1247,16 @@ static int ocfs2_rename(struct inode *old_dir,
old_dentry->d_name.len, old_dentry->d_name.name,
new_dentry->d_name.len, new_dentry->d_name.name);

- dquot_initialize(old_dir);
- dquot_initialize(new_dir);
+ status = dquot_initialize(old_dir);
+ if (status) {
+ mlog_errno(status);
+ goto bail;
+ }
+ status = dquot_initialize(new_dir);
+ if (status) {
+ mlog_errno(status);
+ goto bail;
+ }

osb = OCFS2_SB(old_dir->i_sb);

@@ -1786,7 +1811,11 @@ static int ocfs2_symlink(struct inode *dir,
trace_ocfs2_symlink_begin(dir, dentry, symname,
dentry->d_name.len, dentry->d_name.name);

- dquot_initialize(dir);
+ status = dquot_initialize(dir);
+ if (status) {
+ mlog_errno(status);
+ goto bail;
+ }

sb = dir->i_sb;
osb = OCFS2_SB(sb);
@@ -1831,8 +1860,9 @@ static int ocfs2_symlink(struct inode *dir,
}

inode = ocfs2_get_init_inode(dir, S_IFLNK | S_IRWXUGO);
- if (!inode) {
- status = -ENOMEM;
+ if (IS_ERR(inode)) {
+ status = PTR_ERR(inode);
+ inode = NULL;
mlog_errno(status);
goto bail;
}
@@ -2485,8 +2515,9 @@ int ocfs2_create_inode_in_orphan(struct inode *dir,
}

inode = ocfs2_get_init_inode(dir, mode);
- if (!inode) {
- status = -ENOMEM;
+ if (IS_ERR(inode)) {
+ status = PTR_ERR(inode);
+ inode = NULL;
mlog_errno(status);
goto leave;
}
diff --git a/fs/ocfs2/refcounttree.c b/fs/ocfs2/refcounttree.c
index b69dd14c0b9b..7dc818b87cd8 100644
--- a/fs/ocfs2/refcounttree.c
+++ b/fs/ocfs2/refcounttree.c
@@ -4419,8 +4419,9 @@ static int ocfs2_vfs_reflink(struct dentry *old_dentry, struct inode *dir,
}

mutex_lock(&inode->i_mutex);
- dquot_initialize(dir);
- error = ocfs2_reflink(old_dentry, dir, new_dentry, preserve);
+ error = dquot_initialize(dir);
+ if (!error)
+ error = ocfs2_reflink(old_dentry, dir, new_dentry, preserve);
mutex_unlock(&inode->i_mutex);
if (!error)
fsnotify_create(dir, new_dentry);
--
2.1.4


2015-07-15 12:42:29

by Jan Kara

[permalink] [raw]
Subject: [PATCH 3/6] ext4: Handle error from dquot_initialize()

dquot_initialize() can now return error. Handle it where possible.

Signed-off-by: Jan Kara <[email protected]>
---
fs/ext4/ialloc.c | 6 ++++--
fs/ext4/inode.c | 7 +++++--
fs/ext4/namei.c | 63 ++++++++++++++++++++++++++++++++++++++++++--------------
3 files changed, 56 insertions(+), 20 deletions(-)

diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c
index 173c1ae21395..619bfc1fda8c 100644
--- a/fs/ext4/ialloc.c
+++ b/fs/ext4/ialloc.c
@@ -721,7 +721,7 @@ struct inode *__ext4_new_inode(handle_t *handle, struct inode *dir,
struct ext4_group_desc *gdp = NULL;
struct ext4_inode_info *ei;
struct ext4_sb_info *sbi;
- int ret2, err = 0;
+ int ret2, err;
struct inode *ret;
ext4_group_t i;
ext4_group_t flex_group;
@@ -769,7 +769,9 @@ struct inode *__ext4_new_inode(handle_t *handle, struct inode *dir,
inode->i_gid = dir->i_gid;
} else
inode_init_owner(inode, dir, mode);
- dquot_initialize(inode);
+ err = dquot_initialize(inode);
+ if (err)
+ goto out;

if (!goal)
goal = sbi->s_inode_goal;
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index cecf9aa10811..fed7ee7ea6e8 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -4661,8 +4661,11 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr)
if (error)
return error;

- if (is_quota_modification(inode, attr))
- dquot_initialize(inode);
+ if (is_quota_modification(inode, attr)) {
+ error = dquot_initialize(inode);
+ if (error)
+ return error;
+ }
if ((ia_valid & ATTR_UID && !uid_eq(attr->ia_uid, inode->i_uid)) ||
(ia_valid & ATTR_GID && !gid_eq(attr->ia_gid, inode->i_gid))) {
handle_t *handle;
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index 011dcfb5cce3..d3ff83742a33 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -2436,7 +2436,9 @@ static int ext4_create(struct inode *dir, struct dentry *dentry, umode_t mode,
struct inode *inode;
int err, credits, retries = 0;

- dquot_initialize(dir);
+ err = dquot_initialize(dir);
+ if (err)
+ return err;

credits = (EXT4_DATA_TRANS_BLOCKS(dir->i_sb) +
EXT4_INDEX_EXTRA_TRANS_BLOCKS + 3);
@@ -2470,7 +2472,9 @@ static int ext4_mknod(struct inode *dir, struct dentry *dentry,
if (!new_valid_dev(rdev))
return -EINVAL;

- dquot_initialize(dir);
+ err = dquot_initialize(dir);
+ if (err)
+ return err;

credits = (EXT4_DATA_TRANS_BLOCKS(dir->i_sb) +
EXT4_INDEX_EXTRA_TRANS_BLOCKS + 3);
@@ -2499,7 +2503,9 @@ static int ext4_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode)
struct inode *inode;
int err, retries = 0;

- dquot_initialize(dir);
+ err = dquot_initialize(dir);
+ if (err)
+ return err;

retry:
inode = ext4_new_inode_start_handle(dir, mode,
@@ -2612,7 +2618,9 @@ static int ext4_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
if (EXT4_DIR_LINK_MAX(dir))
return -EMLINK;

- dquot_initialize(dir);
+ err = dquot_initialize(dir);
+ if (err)
+ return err;

credits = (EXT4_DATA_TRANS_BLOCKS(dir->i_sb) +
EXT4_INDEX_EXTRA_TRANS_BLOCKS + 3);
@@ -2910,8 +2918,12 @@ static int ext4_rmdir(struct inode *dir, struct dentry *dentry)

/* Initialize quotas before so that eventual writes go in
* separate transaction */
- dquot_initialize(dir);
- dquot_initialize(d_inode(dentry));
+ retval = dquot_initialize(dir);
+ if (retval)
+ return retval;
+ retval = dquot_initialize(d_inode(dentry));
+ if (retval)
+ return retval;

retval = -ENOENT;
bh = ext4_find_entry(dir, &dentry->d_name, &de, NULL);
@@ -2980,8 +2992,12 @@ static int ext4_unlink(struct inode *dir, struct dentry *dentry)
trace_ext4_unlink_enter(dir, dentry);
/* Initialize quotas before so that eventual writes go
* in separate transaction */
- dquot_initialize(dir);
- dquot_initialize(d_inode(dentry));
+ retval = dquot_initialize(dir);
+ if (retval)
+ return retval;
+ retval = dquot_initialize(d_inode(dentry));
+ if (retval)
+ return retval;

retval = -ENOENT;
bh = ext4_find_entry(dir, &dentry->d_name, &de, NULL);
@@ -3066,7 +3082,9 @@ static int ext4_symlink(struct inode *dir,
goto err_free_sd;
}

- dquot_initialize(dir);
+ err = dquot_initialize(dir);
+ if (err)
+ return err;

if ((disk_link.len > EXT4_N_BLOCKS * 4)) {
/*
@@ -3197,7 +3215,9 @@ static int ext4_link(struct dentry *old_dentry,
if (ext4_encrypted_inode(dir) &&
!ext4_is_child_context_consistent_with_parent(dir, inode))
return -EPERM;
- dquot_initialize(dir);
+ err = dquot_initialize(dir);
+ if (err)
+ return err;

retry:
handle = ext4_journal_start(dir, EXT4_HT_DIR,
@@ -3476,13 +3496,20 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
int credits;
u8 old_file_type;

- dquot_initialize(old.dir);
- dquot_initialize(new.dir);
+ retval = dquot_initialize(old.dir);
+ if (retval)
+ return retval;
+ retval = dquot_initialize(new.dir);
+ if (retval)
+ return retval;

/* Initialize quotas before so that eventual writes go
* in separate transaction */
- if (new.inode)
- dquot_initialize(new.inode);
+ if (new.inode) {
+ retval = dquot_initialize(new.inode);
+ if (retval)
+ return retval;
+ }

old.bh = ext4_find_entry(old.dir, &old.dentry->d_name, &old.de, NULL);
if (IS_ERR(old.bh))
@@ -3678,8 +3705,12 @@ static int ext4_cross_rename(struct inode *old_dir, struct dentry *old_dentry,
new.inode)))
return -EPERM;

- dquot_initialize(old.dir);
- dquot_initialize(new.dir);
+ retval = dquot_initialize(old.dir);
+ if (retval)
+ return retval;
+ retval = dquot_initialize(new.dir);
+ if (retval)
+ return retval;

old.bh = ext4_find_entry(old.dir, &old.dentry->d_name,
&old.de, &old.inlined);
--
2.1.4


2015-07-15 14:20:26

by Theodore Ts'o

[permalink] [raw]
Subject: Re: [PATCH 3/6] ext4: Handle error from dquot_initialize()

On Wed, Jul 15, 2015 at 02:42:29PM +0200, Jan Kara wrote:
> dquot_initialize() can now return error. Handle it where possible.
>
> Signed-off-by: Jan Kara <[email protected]>

Thanks!!

Acked-by: Theodore Ts'o <[email protected]>

- Ted

2015-07-15 17:23:20

by Dave Kleikamp

[permalink] [raw]
Subject: Re: [PATCH 5/6] jfs: Handle error from dquot_initialize()

On 07/15/2015 07:42 AM, Jan Kara wrote:
> dquot_initialize() can now return error. Handle it where possible.

Looks good to me.

> Signed-off-by: Jan Kara <[email protected]>
Reviewed-by: Dave Kleikamp <[email protected]>

> ---
> fs/jfs/file.c | 7 +++++--
> fs/jfs/jfs_inode.c | 4 +++-
> fs/jfs/namei.c | 53 +++++++++++++++++++++++++++++++++++++++--------------
> 3 files changed, 47 insertions(+), 17 deletions(-)
>
> diff --git a/fs/jfs/file.c b/fs/jfs/file.c
> index e98d39d75cf4..34ad63ea0280 100644
> --- a/fs/jfs/file.c
> +++ b/fs/jfs/file.c
> @@ -107,8 +107,11 @@ int jfs_setattr(struct dentry *dentry, struct iattr *iattr)
> if (rc)
> return rc;
>
> - if (is_quota_modification(inode, iattr))
> - dquot_initialize(inode);
> + if (is_quota_modification(inode, iattr)) {
> + rc = dquot_initialize(inode);
> + if (rc)
> + return rc;
> + }
> if ((iattr->ia_valid & ATTR_UID && !uid_eq(iattr->ia_uid, inode->i_uid)) ||
> (iattr->ia_valid & ATTR_GID && !gid_eq(iattr->ia_gid, inode->i_gid))) {
> rc = dquot_transfer(inode, iattr);
> diff --git a/fs/jfs/jfs_inode.c b/fs/jfs/jfs_inode.c
> index 6b0f816201a2..cf7936fe2e68 100644
> --- a/fs/jfs/jfs_inode.c
> +++ b/fs/jfs/jfs_inode.c
> @@ -109,7 +109,9 @@ struct inode *ialloc(struct inode *parent, umode_t mode)
> /*
> * Allocate inode to quota.
> */
> - dquot_initialize(inode);
> + rc = dquot_initialize(inode);
> + if (rc)
> + goto fail_drop;
> rc = dquot_alloc_inode(inode);
> if (rc)
> goto fail_drop;
> diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c
> index e33be921aa41..fb28ce85aa52 100644
> --- a/fs/jfs/namei.c
> +++ b/fs/jfs/namei.c
> @@ -86,7 +86,9 @@ static int jfs_create(struct inode *dip, struct dentry *dentry, umode_t mode,
>
> jfs_info("jfs_create: dip:0x%p name:%pd", dip, dentry);
>
> - dquot_initialize(dip);
> + rc = dquot_initialize(dip);
> + if (rc)
> + goto out1;
>
> /*
> * search parent directory for entry/freespace
> @@ -218,7 +220,9 @@ static int jfs_mkdir(struct inode *dip, struct dentry *dentry, umode_t mode)
>
> jfs_info("jfs_mkdir: dip:0x%p name:%pd", dip, dentry);
>
> - dquot_initialize(dip);
> + rc = dquot_initialize(dip);
> + if (rc)
> + goto out1;
>
> /*
> * search parent directory for entry/freespace
> @@ -355,8 +359,12 @@ static int jfs_rmdir(struct inode *dip, struct dentry *dentry)
> jfs_info("jfs_rmdir: dip:0x%p name:%pd", dip, dentry);
>
> /* Init inode for quota operations. */
> - dquot_initialize(dip);
> - dquot_initialize(ip);
> + rc = dquot_initialize(dip);
> + if (rc)
> + goto out;
> + rc = dquot_initialize(ip);
> + if (rc)
> + goto out;
>
> /* directory must be empty to be removed */
> if (!dtEmpty(ip)) {
> @@ -483,8 +491,12 @@ static int jfs_unlink(struct inode *dip, struct dentry *dentry)
> jfs_info("jfs_unlink: dip:0x%p name:%pd", dip, dentry);
>
> /* Init inode for quota operations. */
> - dquot_initialize(dip);
> - dquot_initialize(ip);
> + rc = dquot_initialize(dip);
> + if (rc)
> + goto out;
> + rc = dquot_initialize(ip);
> + if (rc)
> + goto out;
>
> if ((rc = get_UCSname(&dname, dentry)))
> goto out;
> @@ -799,7 +811,9 @@ static int jfs_link(struct dentry *old_dentry,
>
> jfs_info("jfs_link: %pd %pd", old_dentry, dentry);
>
> - dquot_initialize(dir);
> + rc = dquot_initialize(dir);
> + if (rc)
> + goto out;
>
> tid = txBegin(ip->i_sb, 0);
>
> @@ -810,7 +824,7 @@ static int jfs_link(struct dentry *old_dentry,
> * scan parent directory for entry/freespace
> */
> if ((rc = get_UCSname(&dname, dentry)))
> - goto out;
> + goto out_tx;
>
> if ((rc = dtSearch(dir, &dname, &ino, &btstack, JFS_CREATE)))
> goto free_dname;
> @@ -842,12 +856,13 @@ static int jfs_link(struct dentry *old_dentry,
> free_dname:
> free_UCSname(&dname);
>
> - out:
> + out_tx:
> txEnd(tid);
>
> mutex_unlock(&JFS_IP(ip)->commit_mutex);
> mutex_unlock(&JFS_IP(dir)->commit_mutex);
>
> + out:
> jfs_info("jfs_link: rc:%d", rc);
> return rc;
> }
> @@ -891,7 +906,9 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry,
>
> jfs_info("jfs_symlink: dip:0x%p name:%s", dip, name);
>
> - dquot_initialize(dip);
> + rc = dquot_initialize(dip);
> + if (rc)
> + goto out1;
>
> ssize = strlen(name) + 1;
>
> @@ -1082,8 +1099,12 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
>
> jfs_info("jfs_rename: %pd %pd", old_dentry, new_dentry);
>
> - dquot_initialize(old_dir);
> - dquot_initialize(new_dir);
> + rc = dquot_initialize(old_dir);
> + if (rc)
> + goto out1;
> + rc = dquot_initialize(new_dir);
> + if (rc)
> + goto out1;
>
> old_ip = d_inode(old_dentry);
> new_ip = d_inode(new_dentry);
> @@ -1130,7 +1151,9 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
> } else if (new_ip) {
> IWRITE_LOCK(new_ip, RDWRLOCK_NORMAL);
> /* Init inode for quota operations. */
> - dquot_initialize(new_ip);
> + rc = dquot_initialize(new_ip);
> + if (rc)
> + goto out3;
> }
>
> /*
> @@ -1354,7 +1377,9 @@ static int jfs_mknod(struct inode *dir, struct dentry *dentry,
>
> jfs_info("jfs_mknod: %pd", dentry);
>
> - dquot_initialize(dir);
> + rc = dquot_initialize(dir);
> + if (rc)
> + goto out;
>
> if ((rc = get_UCSname(&dname, dentry)))
> goto out;
>

2015-07-15 17:35:58

by Dave Kleikamp

[permalink] [raw]
Subject: Re: [PATCH 5/6] jfs: Handle error from dquot_initialize()

On 07/15/2015 12:23 PM, Dave Kleikamp wrote:
> On 07/15/2015 07:42 AM, Jan Kara wrote:
>> dquot_initialize() can now return error. Handle it where possible.
>
> Looks good to me.

No, I take that back. Reviewing this I found an existing problem with
the error paths in jfs_rename, and your patch adds to the problem. See
below.

>
>> Signed-off-by: Jan Kara <[email protected]>
> Reviewed-by: Dave Kleikamp <[email protected]>
>
>> ---
>> fs/jfs/file.c | 7 +++++--
>> fs/jfs/jfs_inode.c | 4 +++-
>> fs/jfs/namei.c | 53 +++++++++++++++++++++++++++++++++++++++--------------
>> 3 files changed, 47 insertions(+), 17 deletions(-)
>>
>> diff --git a/fs/jfs/file.c b/fs/jfs/file.c
>> index e98d39d75cf4..34ad63ea0280 100644
>> --- a/fs/jfs/file.c
>> +++ b/fs/jfs/file.c
>> @@ -107,8 +107,11 @@ int jfs_setattr(struct dentry *dentry, struct iattr *iattr)
>> if (rc)
>> return rc;
>>
>> - if (is_quota_modification(inode, iattr))
>> - dquot_initialize(inode);
>> + if (is_quota_modification(inode, iattr)) {
>> + rc = dquot_initialize(inode);
>> + if (rc)
>> + return rc;
>> + }
>> if ((iattr->ia_valid & ATTR_UID && !uid_eq(iattr->ia_uid, inode->i_uid)) ||
>> (iattr->ia_valid & ATTR_GID && !gid_eq(iattr->ia_gid, inode->i_gid))) {
>> rc = dquot_transfer(inode, iattr);
>> diff --git a/fs/jfs/jfs_inode.c b/fs/jfs/jfs_inode.c
>> index 6b0f816201a2..cf7936fe2e68 100644
>> --- a/fs/jfs/jfs_inode.c
>> +++ b/fs/jfs/jfs_inode.c
>> @@ -109,7 +109,9 @@ struct inode *ialloc(struct inode *parent, umode_t mode)
>> /*
>> * Allocate inode to quota.
>> */
>> - dquot_initialize(inode);
>> + rc = dquot_initialize(inode);
>> + if (rc)
>> + goto fail_drop;
>> rc = dquot_alloc_inode(inode);
>> if (rc)
>> goto fail_drop;
>> diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c
>> index e33be921aa41..fb28ce85aa52 100644
>> --- a/fs/jfs/namei.c
>> +++ b/fs/jfs/namei.c
>> @@ -86,7 +86,9 @@ static int jfs_create(struct inode *dip, struct dentry *dentry, umode_t mode,
>>
>> jfs_info("jfs_create: dip:0x%p name:%pd", dip, dentry);
>>
>> - dquot_initialize(dip);
>> + rc = dquot_initialize(dip);
>> + if (rc)
>> + goto out1;
>>
>> /*
>> * search parent directory for entry/freespace
>> @@ -218,7 +220,9 @@ static int jfs_mkdir(struct inode *dip, struct dentry *dentry, umode_t mode)
>>
>> jfs_info("jfs_mkdir: dip:0x%p name:%pd", dip, dentry);
>>
>> - dquot_initialize(dip);
>> + rc = dquot_initialize(dip);
>> + if (rc)
>> + goto out1;
>>
>> /*
>> * search parent directory for entry/freespace
>> @@ -355,8 +359,12 @@ static int jfs_rmdir(struct inode *dip, struct dentry *dentry)
>> jfs_info("jfs_rmdir: dip:0x%p name:%pd", dip, dentry);
>>
>> /* Init inode for quota operations. */
>> - dquot_initialize(dip);
>> - dquot_initialize(ip);
>> + rc = dquot_initialize(dip);
>> + if (rc)
>> + goto out;
>> + rc = dquot_initialize(ip);
>> + if (rc)
>> + goto out;
>>
>> /* directory must be empty to be removed */
>> if (!dtEmpty(ip)) {
>> @@ -483,8 +491,12 @@ static int jfs_unlink(struct inode *dip, struct dentry *dentry)
>> jfs_info("jfs_unlink: dip:0x%p name:%pd", dip, dentry);
>>
>> /* Init inode for quota operations. */
>> - dquot_initialize(dip);
>> - dquot_initialize(ip);
>> + rc = dquot_initialize(dip);
>> + if (rc)
>> + goto out;
>> + rc = dquot_initialize(ip);
>> + if (rc)
>> + goto out;
>>
>> if ((rc = get_UCSname(&dname, dentry)))
>> goto out;
>> @@ -799,7 +811,9 @@ static int jfs_link(struct dentry *old_dentry,
>>
>> jfs_info("jfs_link: %pd %pd", old_dentry, dentry);
>>
>> - dquot_initialize(dir);
>> + rc = dquot_initialize(dir);
>> + if (rc)
>> + goto out;
>>
>> tid = txBegin(ip->i_sb, 0);
>>
>> @@ -810,7 +824,7 @@ static int jfs_link(struct dentry *old_dentry,
>> * scan parent directory for entry/freespace
>> */
>> if ((rc = get_UCSname(&dname, dentry)))
>> - goto out;
>> + goto out_tx;
>>
>> if ((rc = dtSearch(dir, &dname, &ino, &btstack, JFS_CREATE)))
>> goto free_dname;
>> @@ -842,12 +856,13 @@ static int jfs_link(struct dentry *old_dentry,
>> free_dname:
>> free_UCSname(&dname);
>>
>> - out:
>> + out_tx:
>> txEnd(tid);
>>
>> mutex_unlock(&JFS_IP(ip)->commit_mutex);
>> mutex_unlock(&JFS_IP(dir)->commit_mutex);
>>
>> + out:
>> jfs_info("jfs_link: rc:%d", rc);
>> return rc;
>> }
>> @@ -891,7 +906,9 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry,
>>
>> jfs_info("jfs_symlink: dip:0x%p name:%s", dip, name);
>>
>> - dquot_initialize(dip);
>> + rc = dquot_initialize(dip);
>> + if (rc)
>> + goto out1;
>>
>> ssize = strlen(name) + 1;
>>
>> @@ -1082,8 +1099,12 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
>>
>> jfs_info("jfs_rename: %pd %pd", old_dentry, new_dentry);
>>
>> - dquot_initialize(old_dir);
>> - dquot_initialize(new_dir);
>> + rc = dquot_initialize(old_dir);
>> + if (rc)
>> + goto out1;
>> + rc = dquot_initialize(new_dir);
>> + if (rc)
>> + goto out1;

out1: conditionally calls IWRITE_UNLOCK after checking new_ip, which
would here be uninitialized. That IWRITE_UNLOCK needs to be in another
place anyway. I'll send a patch that fixes that and then adjust your
patch on top of that.

>>
>> old_ip = d_inode(old_dentry);
>> new_ip = d_inode(new_dentry);
>> @@ -1130,7 +1151,9 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
>> } else if (new_ip) {
>> IWRITE_LOCK(new_ip, RDWRLOCK_NORMAL);
>> /* Init inode for quota operations. */
>> - dquot_initialize(new_ip);
>> + rc = dquot_initialize(new_ip);
>> + if (rc)
>> + goto out3;
>> }
>>
>> /*
>> @@ -1354,7 +1377,9 @@ static int jfs_mknod(struct inode *dir, struct dentry *dentry,
>>
>> jfs_info("jfs_mknod: %pd", dentry);
>>
>> - dquot_initialize(dir);
>> + rc = dquot_initialize(dir);
>> + if (rc)
>> + goto out;
>>
>> if ((rc = get_UCSname(&dname, dentry)))
>> goto out;
>>

2015-07-15 18:52:39

by Dave Kleikamp

[permalink] [raw]
Subject: [PATCH] jfs: clean up jfs_rename and fix out of order unlock

Subject: [PATCH] jfs: clean up jfs_rename and fix out of order unlock

[ Jan, I'll push this right away. You can carry it along until it
gets merged. I want this pushed to stable as well.]

The end of jfs_rename(), which is also used by the error paths,
included a call to IWRITE_UNLOCK(new_ip) after labels out1, out2
and out3. If we come in through these labels, IWRITE_LOCK() has not
been called yet.

In moving that call to the correct spot, I also moved some
exceptional truncate code earlier as well, since the early error
paths don't need to deal with it, and I renamed out4: to out_tx: so
a future patch by Jan Kara doesn't need to deal with renumbering or
confusing out-of-order labels.

Signed-off-by: Dave Kleikamp <[email protected]>
---
fs/jfs/namei.c | 27 +++++++++++++--------------
1 file changed, 13 insertions(+), 14 deletions(-)

diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c
index e33be92..a5ac97b 100644
--- a/fs/jfs/namei.c
+++ b/fs/jfs/namei.c
@@ -1160,7 +1160,7 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
rc = dtModify(tid, new_dir, &new_dname, &ino,
old_ip->i_ino, JFS_RENAME);
if (rc)
- goto out4;
+ goto out_tx;
drop_nlink(new_ip);
if (S_ISDIR(new_ip->i_mode)) {
drop_nlink(new_ip);
@@ -1185,7 +1185,7 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
if ((new_size = commitZeroLink(tid, new_ip)) < 0) {
txAbort(tid, 1); /* Marks FS Dirty */
rc = new_size;
- goto out4;
+ goto out_tx;
}
tblk = tid_to_tblock(tid);
tblk->xflag |= COMMIT_DELETE;
@@ -1203,7 +1203,7 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
if (rc) {
jfs_err("jfs_rename didn't expect dtSearch to fail "
"w/rc = %d", rc);
- goto out4;
+ goto out_tx;
}

ino = old_ip->i_ino;
@@ -1211,7 +1211,7 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
if (rc) {
if (rc == -EIO)
jfs_err("jfs_rename: dtInsert returned -EIO");
- goto out4;
+ goto out_tx;
}
if (S_ISDIR(old_ip->i_mode))
inc_nlink(new_dir);
@@ -1226,7 +1226,7 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
jfs_err("jfs_rename did not expect dtDelete to return rc = %d",
rc);
txAbort(tid, 1); /* Marks Filesystem dirty */
- goto out4;
+ goto out_tx;
}
if (S_ISDIR(old_ip->i_mode)) {
drop_nlink(old_dir);
@@ -1285,7 +1285,7 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,

rc = txCommit(tid, ipcount, iplist, commit_flag);

- out4:
+ out_tx:
txEnd(tid);
if (new_ip)
mutex_unlock(&JFS_IP(new_ip)->commit_mutex);
@@ -1308,13 +1308,6 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
}
if (new_ip && (new_ip->i_nlink == 0))
set_cflag(COMMIT_Nolink, new_ip);
- out3:
- free_UCSname(&new_dname);
- out2:
- free_UCSname(&old_dname);
- out1:
- if (new_ip && !S_ISDIR(new_ip->i_mode))
- IWRITE_UNLOCK(new_ip);
/*
* Truncating the directory index table is not guaranteed. It
* may need to be done iteratively
@@ -1325,7 +1318,13 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,

clear_cflag(COMMIT_Stale, old_dir);
}
-
+ if (new_ip && !S_ISDIR(new_ip->i_mode))
+ IWRITE_UNLOCK(new_ip);
+ out3:
+ free_UCSname(&new_dname);
+ out2:
+ free_UCSname(&old_dname);
+ out1:
jfs_info("jfs_rename: returning %d", rc);
return rc;
}
--
2.4.5


2015-07-15 18:53:19

by Dave Kleikamp

[permalink] [raw]
Subject: [PATCH] dquot_initialize() can now return error. Handle it where possible

Slightly modified by Dave Kleikamp due to needed jfs_rename() error path fix.

Signed-off-by: Jan Kara <[email protected]>
Reviewed-by: Dave Kleikamp <[email protected]>
---
fs/jfs/file.c | 7 +++++--
fs/jfs/jfs_inode.c | 4 +++-
fs/jfs/namei.c | 54 ++++++++++++++++++++++++++++++++++++++++--------------
3 files changed, 48 insertions(+), 17 deletions(-)

diff --git a/fs/jfs/file.c b/fs/jfs/file.c
index e98d39d..34ad63ea0 100644
--- a/fs/jfs/file.c
+++ b/fs/jfs/file.c
@@ -107,8 +107,11 @@ int jfs_setattr(struct dentry *dentry, struct iattr *iattr)
if (rc)
return rc;

- if (is_quota_modification(inode, iattr))
- dquot_initialize(inode);
+ if (is_quota_modification(inode, iattr)) {
+ rc = dquot_initialize(inode);
+ if (rc)
+ return rc;
+ }
if ((iattr->ia_valid & ATTR_UID && !uid_eq(iattr->ia_uid, inode->i_uid)) ||
(iattr->ia_valid & ATTR_GID && !gid_eq(iattr->ia_gid, inode->i_gid))) {
rc = dquot_transfer(inode, iattr);
diff --git a/fs/jfs/jfs_inode.c b/fs/jfs/jfs_inode.c
index 6b0f816..cf7936f 100644
--- a/fs/jfs/jfs_inode.c
+++ b/fs/jfs/jfs_inode.c
@@ -109,7 +109,9 @@ struct inode *ialloc(struct inode *parent, umode_t mode)
/*
* Allocate inode to quota.
*/
- dquot_initialize(inode);
+ rc = dquot_initialize(inode);
+ if (rc)
+ goto fail_drop;
rc = dquot_alloc_inode(inode);
if (rc)
goto fail_drop;
diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c
index a5ac97b..35976bd 100644
--- a/fs/jfs/namei.c
+++ b/fs/jfs/namei.c
@@ -86,7 +86,9 @@ static int jfs_create(struct inode *dip, struct dentry *dentry, umode_t mode,

jfs_info("jfs_create: dip:0x%p name:%pd", dip, dentry);

- dquot_initialize(dip);
+ rc = dquot_initialize(dip);
+ if (rc)
+ goto out1;

/*
* search parent directory for entry/freespace
@@ -218,7 +220,9 @@ static int jfs_mkdir(struct inode *dip, struct dentry *dentry, umode_t mode)

jfs_info("jfs_mkdir: dip:0x%p name:%pd", dip, dentry);

- dquot_initialize(dip);
+ rc = dquot_initialize(dip);
+ if (rc)
+ goto out1;

/*
* search parent directory for entry/freespace
@@ -355,8 +359,12 @@ static int jfs_rmdir(struct inode *dip, struct dentry *dentry)
jfs_info("jfs_rmdir: dip:0x%p name:%pd", dip, dentry);

/* Init inode for quota operations. */
- dquot_initialize(dip);
- dquot_initialize(ip);
+ rc = dquot_initialize(dip);
+ if (rc)
+ goto out;
+ rc = dquot_initialize(ip);
+ if (rc)
+ goto out;

/* directory must be empty to be removed */
if (!dtEmpty(ip)) {
@@ -483,8 +491,12 @@ static int jfs_unlink(struct inode *dip, struct dentry *dentry)
jfs_info("jfs_unlink: dip:0x%p name:%pd", dip, dentry);

/* Init inode for quota operations. */
- dquot_initialize(dip);
- dquot_initialize(ip);
+ rc = dquot_initialize(dip);
+ if (rc)
+ goto out;
+ rc = dquot_initialize(ip);
+ if (rc)
+ goto out;

if ((rc = get_UCSname(&dname, dentry)))
goto out;
@@ -799,7 +811,9 @@ static int jfs_link(struct dentry *old_dentry,

jfs_info("jfs_link: %pd %pd", old_dentry, dentry);

- dquot_initialize(dir);
+ rc = dquot_initialize(dir);
+ if (rc)
+ goto out;

tid = txBegin(ip->i_sb, 0);

@@ -810,7 +824,7 @@ static int jfs_link(struct dentry *old_dentry,
* scan parent directory for entry/freespace
*/
if ((rc = get_UCSname(&dname, dentry)))
- goto out;
+ goto out_tx;

if ((rc = dtSearch(dir, &dname, &ino, &btstack, JFS_CREATE)))
goto free_dname;
@@ -842,12 +856,13 @@ static int jfs_link(struct dentry *old_dentry,
free_dname:
free_UCSname(&dname);

- out:
+ out_tx:
txEnd(tid);

mutex_unlock(&JFS_IP(ip)->commit_mutex);
mutex_unlock(&JFS_IP(dir)->commit_mutex);

+ out:
jfs_info("jfs_link: rc:%d", rc);
return rc;
}
@@ -891,7 +906,9 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry,

jfs_info("jfs_symlink: dip:0x%p name:%s", dip, name);

- dquot_initialize(dip);
+ rc = dquot_initialize(dip);
+ if (rc)
+ goto out1;

ssize = strlen(name) + 1;

@@ -1082,8 +1099,12 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,

jfs_info("jfs_rename: %pd %pd", old_dentry, new_dentry);

- dquot_initialize(old_dir);
- dquot_initialize(new_dir);
+ rc = dquot_initialize(old_dir);
+ if (rc)
+ goto out1;
+ rc = dquot_initialize(new_dir);
+ if (rc)
+ goto out1;

old_ip = d_inode(old_dentry);
new_ip = d_inode(new_dentry);
@@ -1130,7 +1151,9 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
} else if (new_ip) {
IWRITE_LOCK(new_ip, RDWRLOCK_NORMAL);
/* Init inode for quota operations. */
- dquot_initialize(new_ip);
+ rc = dquot_initialize(new_ip);
+ if (rc)
+ goto out_unlock;
}

/*
@@ -1318,6 +1341,7 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,

clear_cflag(COMMIT_Stale, old_dir);
}
+ out_unlock:
if (new_ip && !S_ISDIR(new_ip->i_mode))
IWRITE_UNLOCK(new_ip);
out3:
@@ -1353,7 +1377,9 @@ static int jfs_mknod(struct inode *dir, struct dentry *dentry,

jfs_info("jfs_mknod: %pd", dentry);

- dquot_initialize(dir);
+ rc = dquot_initialize(dir);
+ if (rc)
+ goto out;

if ((rc = get_UCSname(&dname, dentry)))
goto out;
--
2.4.5


2015-07-16 02:35:16

by Junxiao Bi

[permalink] [raw]
Subject: Re: [Ocfs2-devel] [PATCH 4/6] ocfs2: Handle error from dquot_initialize()

On 07/15/2015 08:42 PM, Jan Kara wrote:
> dquot_initialize() can now return error. Handle it where possible.
>
> Signed-off-by: Jan Kara <[email protected]>

Looks good.

Reviewed-by: Junxiao Bi <[email protected]>

> ---
> fs/ocfs2/file.c | 14 ++++++++----
> fs/ocfs2/namei.c | 59 +++++++++++++++++++++++++++++++++++++------------
> fs/ocfs2/refcounttree.c | 5 +++--
> 3 files changed, 58 insertions(+), 20 deletions(-)
>
> diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c
> index 4d9e8275ed99..7210583b472f 100644
> --- a/fs/ocfs2/file.c
> +++ b/fs/ocfs2/file.c
> @@ -105,8 +105,11 @@ static int ocfs2_file_open(struct inode *inode, struct file *file)
> file->f_path.dentry->d_name.len,
> file->f_path.dentry->d_name.name, mode);
>
> - if (file->f_mode & FMODE_WRITE)
> - dquot_initialize(inode);
> + if (file->f_mode & FMODE_WRITE) {
> + status = dquot_initialize(inode);
> + if (status)
> + goto leave;
> + }
>
> spin_lock(&oi->ip_lock);
>
> @@ -1155,8 +1158,11 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)
> if (status)
> return status;
>
> - if (is_quota_modification(inode, attr))
> - dquot_initialize(inode);
> + if (is_quota_modification(inode, attr)) {
> + status = dquot_initialize(inode);
> + if (status)
> + return status;
> + }
> size_change = S_ISREG(inode->i_mode) && attr->ia_valid & ATTR_SIZE;
> if (size_change) {
> status = ocfs2_rw_lock(inode, 1);
> diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c
> index 6e6abb93fda5..948681e37cfd 100644
> --- a/fs/ocfs2/namei.c
> +++ b/fs/ocfs2/namei.c
> @@ -200,11 +200,12 @@ bail:
> static struct inode *ocfs2_get_init_inode(struct inode *dir, umode_t mode)
> {
> struct inode *inode;
> + int status;
>
> inode = new_inode(dir->i_sb);
> if (!inode) {
> mlog(ML_ERROR, "new_inode failed!\n");
> - return NULL;
> + return ERR_PTR(-ENOMEM);
> }
>
> /* populate as many fields early on as possible - many of
> @@ -213,7 +214,10 @@ static struct inode *ocfs2_get_init_inode(struct inode *dir, umode_t mode)
> if (S_ISDIR(mode))
> set_nlink(inode, 2);
> inode_init_owner(inode, dir, mode);
> - dquot_initialize(inode);
> + status = dquot_initialize(inode);
> + if (status)
> + return ERR_PTR(status);
> +
> return inode;
> }
>
> @@ -264,7 +268,11 @@ static int ocfs2_mknod(struct inode *dir,
> (unsigned long long)OCFS2_I(dir)->ip_blkno,
> (unsigned long)dev, mode);
>
> - dquot_initialize(dir);
> + status = dquot_initialize(dir);
> + if (status) {
> + mlog_errno(status);
> + return status;
> + }
>
> /* get our super block */
> osb = OCFS2_SB(dir->i_sb);
> @@ -311,8 +319,9 @@ static int ocfs2_mknod(struct inode *dir,
> }
>
> inode = ocfs2_get_init_inode(dir, mode);
> - if (!inode) {
> - status = -ENOMEM;
> + if (IS_ERR(inode)) {
> + status = PTR_ERR(inode);
> + inode = NULL;
> mlog_errno(status);
> goto leave;
> }
> @@ -708,7 +717,11 @@ static int ocfs2_link(struct dentry *old_dentry,
> if (S_ISDIR(inode->i_mode))
> return -EPERM;
>
> - dquot_initialize(dir);
> + err = dquot_initialize(dir);
> + if (err) {
> + mlog_errno(err);
> + return err;
> + }
>
> err = ocfs2_double_lock(osb, &old_dir_bh, old_dir,
> &parent_fe_bh, dir, 0);
> @@ -896,7 +909,11 @@ static int ocfs2_unlink(struct inode *dir,
> (unsigned long long)OCFS2_I(dir)->ip_blkno,
> (unsigned long long)OCFS2_I(inode)->ip_blkno);
>
> - dquot_initialize(dir);
> + status = dquot_initialize(dir);
> + if (status) {
> + mlog_errno(status);
> + return status;
> + }
>
> BUG_ON(d_inode(dentry->d_parent) != dir);
>
> @@ -1230,8 +1247,16 @@ static int ocfs2_rename(struct inode *old_dir,
> old_dentry->d_name.len, old_dentry->d_name.name,
> new_dentry->d_name.len, new_dentry->d_name.name);
>
> - dquot_initialize(old_dir);
> - dquot_initialize(new_dir);
> + status = dquot_initialize(old_dir);
> + if (status) {
> + mlog_errno(status);
> + goto bail;
> + }
> + status = dquot_initialize(new_dir);
> + if (status) {
> + mlog_errno(status);
> + goto bail;
> + }
>
> osb = OCFS2_SB(old_dir->i_sb);
>
> @@ -1786,7 +1811,11 @@ static int ocfs2_symlink(struct inode *dir,
> trace_ocfs2_symlink_begin(dir, dentry, symname,
> dentry->d_name.len, dentry->d_name.name);
>
> - dquot_initialize(dir);
> + status = dquot_initialize(dir);
> + if (status) {
> + mlog_errno(status);
> + goto bail;
> + }
>
> sb = dir->i_sb;
> osb = OCFS2_SB(sb);
> @@ -1831,8 +1860,9 @@ static int ocfs2_symlink(struct inode *dir,
> }
>
> inode = ocfs2_get_init_inode(dir, S_IFLNK | S_IRWXUGO);
> - if (!inode) {
> - status = -ENOMEM;
> + if (IS_ERR(inode)) {
> + status = PTR_ERR(inode);
> + inode = NULL;
> mlog_errno(status);
> goto bail;
> }
> @@ -2485,8 +2515,9 @@ int ocfs2_create_inode_in_orphan(struct inode *dir,
> }
>
> inode = ocfs2_get_init_inode(dir, mode);
> - if (!inode) {
> - status = -ENOMEM;
> + if (IS_ERR(inode)) {
> + status = PTR_ERR(inode);
> + inode = NULL;
> mlog_errno(status);
> goto leave;
> }
> diff --git a/fs/ocfs2/refcounttree.c b/fs/ocfs2/refcounttree.c
> index b69dd14c0b9b..7dc818b87cd8 100644
> --- a/fs/ocfs2/refcounttree.c
> +++ b/fs/ocfs2/refcounttree.c
> @@ -4419,8 +4419,9 @@ static int ocfs2_vfs_reflink(struct dentry *old_dentry, struct inode *dir,
> }
>
> mutex_lock(&inode->i_mutex);
> - dquot_initialize(dir);
> - error = ocfs2_reflink(old_dentry, dir, new_dentry, preserve);
> + error = dquot_initialize(dir);
> + if (!error)
> + error = ocfs2_reflink(old_dentry, dir, new_dentry, preserve);
> mutex_unlock(&inode->i_mutex);
> if (!error)
> fsnotify_create(dir, new_dentry);
>


2015-07-16 10:02:24

by Jan Kara

[permalink] [raw]
Subject: Re: [PATCH] dquot_initialize() can now return error. Handle it where possible

On Wed 15-07-15 13:53:19, Dave Kleikamp wrote:
> Slightly modified by Dave Kleikamp due to needed jfs_rename() error path fix.
>
> Signed-off-by: Jan Kara <[email protected]>
> Reviewed-by: Dave Kleikamp <[email protected]>

Thanks! I have picked up both patches for now so that I have the series
consistent. I will wait for a few days before pushing my series to
linux-next so that your patch has time to reach Linus and I don't
create unnecessary conflicts...

Honza

> ---
> fs/jfs/file.c | 7 +++++--
> fs/jfs/jfs_inode.c | 4 +++-
> fs/jfs/namei.c | 54 ++++++++++++++++++++++++++++++++++++++++--------------
> 3 files changed, 48 insertions(+), 17 deletions(-)
>
> diff --git a/fs/jfs/file.c b/fs/jfs/file.c
> index e98d39d..34ad63ea0 100644
> --- a/fs/jfs/file.c
> +++ b/fs/jfs/file.c
> @@ -107,8 +107,11 @@ int jfs_setattr(struct dentry *dentry, struct iattr *iattr)
> if (rc)
> return rc;
>
> - if (is_quota_modification(inode, iattr))
> - dquot_initialize(inode);
> + if (is_quota_modification(inode, iattr)) {
> + rc = dquot_initialize(inode);
> + if (rc)
> + return rc;
> + }
> if ((iattr->ia_valid & ATTR_UID && !uid_eq(iattr->ia_uid, inode->i_uid)) ||
> (iattr->ia_valid & ATTR_GID && !gid_eq(iattr->ia_gid, inode->i_gid))) {
> rc = dquot_transfer(inode, iattr);
> diff --git a/fs/jfs/jfs_inode.c b/fs/jfs/jfs_inode.c
> index 6b0f816..cf7936f 100644
> --- a/fs/jfs/jfs_inode.c
> +++ b/fs/jfs/jfs_inode.c
> @@ -109,7 +109,9 @@ struct inode *ialloc(struct inode *parent, umode_t mode)
> /*
> * Allocate inode to quota.
> */
> - dquot_initialize(inode);
> + rc = dquot_initialize(inode);
> + if (rc)
> + goto fail_drop;
> rc = dquot_alloc_inode(inode);
> if (rc)
> goto fail_drop;
> diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c
> index a5ac97b..35976bd 100644
> --- a/fs/jfs/namei.c
> +++ b/fs/jfs/namei.c
> @@ -86,7 +86,9 @@ static int jfs_create(struct inode *dip, struct dentry *dentry, umode_t mode,
>
> jfs_info("jfs_create: dip:0x%p name:%pd", dip, dentry);
>
> - dquot_initialize(dip);
> + rc = dquot_initialize(dip);
> + if (rc)
> + goto out1;
>
> /*
> * search parent directory for entry/freespace
> @@ -218,7 +220,9 @@ static int jfs_mkdir(struct inode *dip, struct dentry *dentry, umode_t mode)
>
> jfs_info("jfs_mkdir: dip:0x%p name:%pd", dip, dentry);
>
> - dquot_initialize(dip);
> + rc = dquot_initialize(dip);
> + if (rc)
> + goto out1;
>
> /*
> * search parent directory for entry/freespace
> @@ -355,8 +359,12 @@ static int jfs_rmdir(struct inode *dip, struct dentry *dentry)
> jfs_info("jfs_rmdir: dip:0x%p name:%pd", dip, dentry);
>
> /* Init inode for quota operations. */
> - dquot_initialize(dip);
> - dquot_initialize(ip);
> + rc = dquot_initialize(dip);
> + if (rc)
> + goto out;
> + rc = dquot_initialize(ip);
> + if (rc)
> + goto out;
>
> /* directory must be empty to be removed */
> if (!dtEmpty(ip)) {
> @@ -483,8 +491,12 @@ static int jfs_unlink(struct inode *dip, struct dentry *dentry)
> jfs_info("jfs_unlink: dip:0x%p name:%pd", dip, dentry);
>
> /* Init inode for quota operations. */
> - dquot_initialize(dip);
> - dquot_initialize(ip);
> + rc = dquot_initialize(dip);
> + if (rc)
> + goto out;
> + rc = dquot_initialize(ip);
> + if (rc)
> + goto out;
>
> if ((rc = get_UCSname(&dname, dentry)))
> goto out;
> @@ -799,7 +811,9 @@ static int jfs_link(struct dentry *old_dentry,
>
> jfs_info("jfs_link: %pd %pd", old_dentry, dentry);
>
> - dquot_initialize(dir);
> + rc = dquot_initialize(dir);
> + if (rc)
> + goto out;
>
> tid = txBegin(ip->i_sb, 0);
>
> @@ -810,7 +824,7 @@ static int jfs_link(struct dentry *old_dentry,
> * scan parent directory for entry/freespace
> */
> if ((rc = get_UCSname(&dname, dentry)))
> - goto out;
> + goto out_tx;
>
> if ((rc = dtSearch(dir, &dname, &ino, &btstack, JFS_CREATE)))
> goto free_dname;
> @@ -842,12 +856,13 @@ static int jfs_link(struct dentry *old_dentry,
> free_dname:
> free_UCSname(&dname);
>
> - out:
> + out_tx:
> txEnd(tid);
>
> mutex_unlock(&JFS_IP(ip)->commit_mutex);
> mutex_unlock(&JFS_IP(dir)->commit_mutex);
>
> + out:
> jfs_info("jfs_link: rc:%d", rc);
> return rc;
> }
> @@ -891,7 +906,9 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry,
>
> jfs_info("jfs_symlink: dip:0x%p name:%s", dip, name);
>
> - dquot_initialize(dip);
> + rc = dquot_initialize(dip);
> + if (rc)
> + goto out1;
>
> ssize = strlen(name) + 1;
>
> @@ -1082,8 +1099,12 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
>
> jfs_info("jfs_rename: %pd %pd", old_dentry, new_dentry);
>
> - dquot_initialize(old_dir);
> - dquot_initialize(new_dir);
> + rc = dquot_initialize(old_dir);
> + if (rc)
> + goto out1;
> + rc = dquot_initialize(new_dir);
> + if (rc)
> + goto out1;
>
> old_ip = d_inode(old_dentry);
> new_ip = d_inode(new_dentry);
> @@ -1130,7 +1151,9 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
> } else if (new_ip) {
> IWRITE_LOCK(new_ip, RDWRLOCK_NORMAL);
> /* Init inode for quota operations. */
> - dquot_initialize(new_ip);
> + rc = dquot_initialize(new_ip);
> + if (rc)
> + goto out_unlock;
> }
>
> /*
> @@ -1318,6 +1341,7 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
>
> clear_cflag(COMMIT_Stale, old_dir);
> }
> + out_unlock:
> if (new_ip && !S_ISDIR(new_ip->i_mode))
> IWRITE_UNLOCK(new_ip);
> out3:
> @@ -1353,7 +1377,9 @@ static int jfs_mknod(struct inode *dir, struct dentry *dentry,
>
> jfs_info("jfs_mknod: %pd", dentry);
>
> - dquot_initialize(dir);
> + rc = dquot_initialize(dir);
> + if (rc)
> + goto out;
>
> if ((rc = get_UCSname(&dname, dentry)))
> goto out;
> --
> 2.4.5
>
>
--
Jan Kara <[email protected]>
SUSE Labs, CR