Commit abb7c742 authored by Al Viro's avatar Al Viro
Browse files

sysv: fix handling of delete_entry and set_link failures



similar to minixfs series - make sysv_set_link() report failures,
lift dir_put_page() into the callers of sysv_set_link() and
sysv_delete_entry(), make sysv_rename() handle failures in both.

Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 83005276
Loading
Loading
Loading
Loading
+10 −6
Original line number Diff line number Diff line
@@ -249,10 +249,12 @@ int sysv_delete_entry(struct sysv_dir_entry *de, struct page *page)

	lock_page(page);
	err = sysv_prepare_chunk(page, pos, SYSV_DIRSIZE);
	BUG_ON(err);
	if (err) {
		unlock_page(page);
		return err;
	}
	de->inode = 0;
	dir_commit_chunk(page, pos, SYSV_DIRSIZE);
	dir_put_page(page, de);
	inode->i_ctime = inode->i_mtime = current_time(inode);
	mark_inode_dirty(inode);
	return sysv_handle_dirsync(inode);
@@ -335,7 +337,7 @@ int sysv_empty_dir(struct inode * inode)
}

/* Releases the page */
void sysv_set_link(struct sysv_dir_entry *de, struct page *page,
int sysv_set_link(struct sysv_dir_entry *de, struct page *page,
	struct inode *inode)
{
	struct inode *dir = page->mapping->host;
@@ -344,13 +346,15 @@ void sysv_set_link(struct sysv_dir_entry *de, struct page *page,

	lock_page(page);
	err = sysv_prepare_chunk(page, pos, SYSV_DIRSIZE);
	BUG_ON(err);
	if (err) {
		unlock_page(page);
		return err;
	}
	de->inode = cpu_to_fs16(SYSV_SB(inode->i_sb), inode->i_ino);
	dir_commit_chunk(page, pos, SYSV_DIRSIZE);
	dir_put_page(page, de);
	dir->i_mtime = dir->i_ctime = current_time(dir);
	mark_inode_dirty(dir);
	sysv_handle_dirsync(inode);
	return sysv_handle_dirsync(inode);
}

/*
+19 −14
Original line number Diff line number Diff line
@@ -153,19 +153,18 @@ static int sysv_unlink(struct inode * dir, struct dentry * dentry)
	struct inode * inode = d_inode(dentry);
	struct page * page;
	struct sysv_dir_entry * de;
	int err = -ENOENT;
	int err;

	de = sysv_find_entry(dentry, &page);
	if (!de)
		goto out;
		return -ENOENT;

	err = sysv_delete_entry(de, page);
	if (err)
		goto out;

	if (!err) {
		inode->i_ctime = dir->i_ctime;
		inode_dec_link_count(inode);
out:
	}
	dir_put_page(page, de);
	return err;
}

@@ -227,7 +226,10 @@ static int sysv_rename(struct user_namespace *mnt_userns, struct inode *old_dir,
		new_de = sysv_find_entry(new_dentry, &new_page);
		if (!new_de)
			goto out_dir;
		sysv_set_link(new_de, new_page, old_inode);
		err = sysv_set_link(new_de, new_page, old_inode);
		dir_put_page(new_page, new_de);
		if (err)
			goto out_dir;
		new_inode->i_ctime = current_time(new_inode);
		if (dir_de)
			drop_nlink(new_inode);
@@ -240,14 +242,17 @@ static int sysv_rename(struct user_namespace *mnt_userns, struct inode *old_dir,
			inode_inc_link_count(new_dir);
	}

	sysv_delete_entry(old_de, old_page);
	err = sysv_delete_entry(old_de, old_page);
	if (err)
		goto out_dir;

	mark_inode_dirty(old_inode);

	if (dir_de) {
		sysv_set_link(dir_de, dir_page, new_dir);
		err = sysv_set_link(dir_de, dir_page, new_dir);
		if (!err)
			inode_dec_link_count(old_dir);
	}
	return 0;

out_dir:
	if (dir_de)
+1 −1
Original line number Diff line number Diff line
@@ -154,7 +154,7 @@ extern int sysv_add_link(struct dentry *, struct inode *);
extern int sysv_delete_entry(struct sysv_dir_entry *, struct page *);
extern int sysv_make_empty(struct inode *, struct inode *);
extern int sysv_empty_dir(struct inode *);
extern void sysv_set_link(struct sysv_dir_entry *, struct page *,
extern int sysv_set_link(struct sysv_dir_entry *, struct page *,
			struct inode *);
extern struct sysv_dir_entry *sysv_dotdot(struct inode *, struct page **);
extern ino_t sysv_inode_by_name(struct dentry *);