Unverified Commit 8618a4f6 authored by openeuler-ci-bot's avatar openeuler-ci-bot Committed by Gitee
Browse files

!3815 JFFS2: Fix the race issues caused by the GC of jffs2

Merge Pull Request from: @ci-robot 
 
PR sync from: ZhaoLong Wang <wangzhaolong1@huawei.com>
https://mailweb.openeuler.org/hyperkitty/list/kernel@openeuler.org/message/7IBH7AGPZWJIKL4DOMLPPL5YTQ7T7PCG/ 
Hou Tao (4):
  jffs2: protect no-raw-node-ref check of inocache by
    erase_completion_lock
  jffs2: handle INO_STATE_CLEARING in jffs2_do_read_inode()
  jffs2: make the overwritten xattr invisible after remount
  jffs2: reset pino_nlink to 0 when inode creation failed


-- 
2.39.2
 
https://gitee.com/openeuler/kernel/issues/I8TYET 
 
Link:https://gitee.com/openeuler/kernel/pulls/3815

 

Reviewed-by: default avatarHou Tao <houtao1@huawei.com>
Signed-off-by: default avatarZheng Zengkai <zhengzengkai@huawei.com>
parents 4047698b 70ac77a3
Loading
Loading
Loading
Loading
+24 −4
Original line number Diff line number Diff line
@@ -159,6 +159,26 @@ static int jffs2_readdir(struct file *file, struct dir_context *ctx)

/***********************************************************************/

static void jffs2_iget_failed(struct jffs2_sb_info *c, struct inode *inode)
{
	struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);

	/*
	 * Reset pino_nlink to zero, so jffs2_do_clear_inode() will mark
	 * all flash nodes used by the inode as obsolete and GC procedure
	 * will reclaim these flash nodes, else these flash spaces will be
	 * unreclaimable forever.
	 *
	 * Update pino_nlink under inocache_lock, because no proceses could
	 * get the inode due to I_NEW flag, and only GC procedure may try to
	 * read pino_nlink under inocache_lock.
	 */
	spin_lock(&c->inocache_lock);
	f->inocache->pino_nlink = 0;
	spin_unlock(&c->inocache_lock);

	iget_failed(inode);
}

static int jffs2_create(struct mnt_idmap *idmap, struct inode *dir_i,
			struct dentry *dentry, umode_t mode, bool excl)
@@ -217,7 +237,7 @@ static int jffs2_create(struct mnt_idmap *idmap, struct inode *dir_i,
	return 0;

 fail:
	iget_failed(inode);
	jffs2_iget_failed(c, inode);
	jffs2_free_raw_inode(ri);
	return ret;
}
@@ -439,7 +459,7 @@ static int jffs2_symlink (struct mnt_idmap *idmap, struct inode *dir_i,
	return 0;

 fail:
	iget_failed(inode);
	jffs2_iget_failed(c, inode);
	return ret;
}

@@ -585,7 +605,7 @@ static int jffs2_mkdir (struct mnt_idmap *idmap, struct inode *dir_i,
	return 0;

 fail:
	iget_failed(inode);
	jffs2_iget_failed(c, inode);
	return ret;
}

@@ -762,7 +782,7 @@ static int jffs2_mknod (struct mnt_idmap *idmap, struct inode *dir_i,
	return 0;

 fail:
	iget_failed(inode);
	jffs2_iget_failed(c, inode);
	return ret;
}

+7 −0
Original line number Diff line number Diff line
@@ -469,6 +469,13 @@ void jffs2_del_ino_cache(struct jffs2_sb_info *c, struct jffs2_inode_cache *old)
	while ((*prev) && (*prev)->ino < old->ino) {
		prev = &(*prev)->next;
	}

	/*
	 * It's possible that we can not find the inocache in
	 * hash table because it had been removed by
	 * jffs2_remove_node_refs_from_ino_list(), but it's still not freed,
	 * so we need go forward and free it.
	 */
	if ((*prev) == old) {
		*prev = old->next;
	}
+10 −1
Original line number Diff line number Diff line
@@ -1344,6 +1344,7 @@ int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f,

		case INO_STATE_CHECKING:
		case INO_STATE_GC:
		case INO_STATE_CLEARING:
			/* If it's in either of these states, we need
			   to wait for whoever's got it to finish and
			   put it back. */
@@ -1438,8 +1439,16 @@ void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f)
	}

	if (f->inocache && f->inocache->state != INO_STATE_CHECKING) {
		jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT);
		bool need_del = false;

		spin_lock(&c->erase_completion_lock);
		if (f->inocache->nodes == (void *)f->inocache)
			need_del = true;
		jffs2_set_inocache_state(c, f->inocache,
					 INO_STATE_CHECKEDABSENT);
		spin_unlock(&c->erase_completion_lock);

		if (need_del)
			jffs2_del_ino_cache(c, f->inocache);
	}

+49 −6
Original line number Diff line number Diff line
@@ -573,6 +573,15 @@ static struct jffs2_xattr_ref *create_xattr_ref(struct jffs2_sb_info *c, struct
	return ref; /* success */
}

static void move_xattr_ref_to_dead_list(struct jffs2_sb_info *c,
		struct jffs2_xattr_ref *ref)
{
	spin_lock(&c->erase_completion_lock);
	ref->next = c->xref_dead_list;
	c->xref_dead_list = ref;
	spin_unlock(&c->erase_completion_lock);
}

static void delete_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref)
{
	/* must be called under down_write(xattr_sem) */
@@ -582,10 +591,7 @@ static void delete_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *re
	ref->xseqno |= XREF_DELETE_MARKER;
	ref->ino = ref->ic->ino;
	ref->xid = ref->xd->xid;
	spin_lock(&c->erase_completion_lock);
	ref->next = c->xref_dead_list;
	c->xref_dead_list = ref;
	spin_unlock(&c->erase_completion_lock);
	move_xattr_ref_to_dead_list(c, ref);

	dbg_xattr("xref(ino=%u, xid=%u, xseqno=%u) was removed.\n",
		  ref->ino, ref->xid, ref->xseqno);
@@ -1094,6 +1100,40 @@ int do_jffs2_getxattr(struct inode *inode, int xprefix, const char *xname,
	return rc;
}

static void do_jffs2_delete_xattr_ref(struct jffs2_sb_info *c,
		struct jffs2_xattr_ref *ref)
{
	uint32_t request, length;
	int err;
	struct jffs2_xattr_datum *xd;

	request = PAD(sizeof(struct jffs2_raw_xref));
	err = jffs2_reserve_space(c, request, &length,
			ALLOC_NORMAL, JFFS2_SUMMARY_XREF_SIZE);
	down_write(&c->xattr_sem);
	if (err) {
		JFFS2_WARNING("jffs2_reserve_space()=%d, request=%u\n",
				err, request);
		delete_xattr_ref(c, ref);
		up_write(&c->xattr_sem);
		return;
	}

	xd = ref->xd;
	ref->ino = ref->ic->ino;
	ref->xid = xd->xid;
	ref->xseqno |= XREF_DELETE_MARKER;
	save_xattr_ref(c, ref);

	move_xattr_ref_to_dead_list(c, ref);
	dbg_xattr("xref(ino=%u, xid=%u, xseqno=%u) was removed.\n",
		  ref->ino, ref->xid, ref->xseqno);
	unrefer_xattr_datum(c, xd);

	up_write(&c->xattr_sem);
	jffs2_complete_reservation(c);
}

int do_jffs2_setxattr(struct inode *inode, int xprefix, const char *xname,
		      const char *buffer, size_t size, int flags)
{
@@ -1101,7 +1141,7 @@ int do_jffs2_setxattr(struct inode *inode, int xprefix, const char *xname,
	struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
	struct jffs2_inode_cache *ic = f->inocache;
	struct jffs2_xattr_datum *xd;
	struct jffs2_xattr_ref *ref, *newref, **pref;
	struct jffs2_xattr_ref *ref, *newref, *oldref, **pref;
	uint32_t length, request;
	int rc;

@@ -1117,6 +1157,7 @@ int do_jffs2_setxattr(struct inode *inode, int xprefix, const char *xname,
		return rc;
	}

	oldref = NULL;
	/* Find existing xattr */
	down_write(&c->xattr_sem);
 retry:
@@ -1200,11 +1241,13 @@ int do_jffs2_setxattr(struct inode *inode, int xprefix, const char *xname,
		rc = PTR_ERR(newref);
		unrefer_xattr_datum(c, xd);
	} else if (ref) {
		delete_xattr_ref(c, ref);
		oldref = ref;
	}
 out:
	up_write(&c->xattr_sem);
	jffs2_complete_reservation(c);
	if (oldref)
		do_jffs2_delete_xattr_ref(c, oldref);
	return rc;
}