Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4d0fb621 authored by Alessio Igor Bogani's avatar Alessio Igor Bogani Committed by Jan Kara
Browse files

udf: Replace bkl with the UDF_I(inode)->i_data_sem for protect udf_inode_info struct



Replace bkl with the UDF_I(inode)->i_data_sem rw semaphore in
udf_release_file(), udf_symlink(), udf_symlink_filler(), udf_get_block(),
udf_block_map(), and udf_setattr(). The rule now is that any operation
on regular file's or symlink's extents (or generally allocation information
including goal block) needs to hold i_data_sem.

This work was supported by a hardware donation from the CE Linux Forum.

Signed-off-by: default avatarAlessio Igor Bogani <abogani@texware.it>
Signed-off-by: default avatarJan Kara <jack@suse.cz>
parent d1668fe3
Loading
Loading
Loading
Loading
+2 −2
Original line number Original line Diff line number Diff line
@@ -204,10 +204,10 @@ static int udf_release_file(struct inode *inode, struct file *filp)
{
{
	if (filp->f_mode & FMODE_WRITE) {
	if (filp->f_mode & FMODE_WRITE) {
		mutex_lock(&inode->i_mutex);
		mutex_lock(&inode->i_mutex);
		lock_kernel();
		down_write(&UDF_I(inode)->i_data_sem);
		udf_discard_prealloc(inode);
		udf_discard_prealloc(inode);
		udf_truncate_tail_extent(inode);
		udf_truncate_tail_extent(inode);
		unlock_kernel();
		up_write(&UDF_I(inode)->i_data_sem);
		mutex_unlock(&inode->i_mutex);
		mutex_unlock(&inode->i_mutex);
	}
	}
	return 0;
	return 0;
+10 −9
Original line number Original line Diff line number Diff line
@@ -301,10 +301,9 @@ static int udf_get_block(struct inode *inode, sector_t block,
	err = -EIO;
	err = -EIO;
	new = 0;
	new = 0;
	bh = NULL;
	bh = NULL;

	lock_kernel();

	iinfo = UDF_I(inode);
	iinfo = UDF_I(inode);

	down_write(&iinfo->i_data_sem);
	if (block == iinfo->i_next_alloc_block + 1) {
	if (block == iinfo->i_next_alloc_block + 1) {
		iinfo->i_next_alloc_block++;
		iinfo->i_next_alloc_block++;
		iinfo->i_next_alloc_goal++;
		iinfo->i_next_alloc_goal++;
@@ -323,7 +322,7 @@ static int udf_get_block(struct inode *inode, sector_t block,
	map_bh(bh_result, inode->i_sb, phys);
	map_bh(bh_result, inode->i_sb, phys);


abort:
abort:
	unlock_kernel();
	up_write(&iinfo->i_data_sem);
	return err;
	return err;
}
}


@@ -1021,16 +1020,16 @@ void udf_truncate(struct inode *inode)
	if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
	if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
		return;
		return;


	lock_kernel();
	iinfo = UDF_I(inode);
	iinfo = UDF_I(inode);
	if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
	if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
		down_write(&iinfo->i_data_sem);
		if (inode->i_sb->s_blocksize <
		if (inode->i_sb->s_blocksize <
				(udf_file_entry_alloc_offset(inode) +
				(udf_file_entry_alloc_offset(inode) +
				 inode->i_size)) {
				 inode->i_size)) {
			udf_expand_file_adinicb(inode, inode->i_size, &err);
			udf_expand_file_adinicb(inode, inode->i_size, &err);
			if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
			if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
				inode->i_size = iinfo->i_lenAlloc;
				inode->i_size = iinfo->i_lenAlloc;
				unlock_kernel();
				up_write(&iinfo->i_data_sem);
				return;
				return;
			} else
			} else
				udf_truncate_extents(inode);
				udf_truncate_extents(inode);
@@ -1041,10 +1040,13 @@ void udf_truncate(struct inode *inode)
				offset - udf_file_entry_alloc_offset(inode));
				offset - udf_file_entry_alloc_offset(inode));
			iinfo->i_lenAlloc = inode->i_size;
			iinfo->i_lenAlloc = inode->i_size;
		}
		}
		up_write(&iinfo->i_data_sem);
	} else {
	} else {
		block_truncate_page(inode->i_mapping, inode->i_size,
		block_truncate_page(inode->i_mapping, inode->i_size,
				    udf_get_block);
				    udf_get_block);
		down_write(&iinfo->i_data_sem);
		udf_truncate_extents(inode);
		udf_truncate_extents(inode);
		up_write(&iinfo->i_data_sem);
	}
	}


	inode->i_mtime = inode->i_ctime = current_fs_time(inode->i_sb);
	inode->i_mtime = inode->i_ctime = current_fs_time(inode->i_sb);
@@ -1052,7 +1054,6 @@ void udf_truncate(struct inode *inode)
		udf_sync_inode(inode);
		udf_sync_inode(inode);
	else
	else
		mark_inode_dirty(inode);
		mark_inode_dirty(inode);
	unlock_kernel();
}
}


static void __udf_read_inode(struct inode *inode)
static void __udf_read_inode(struct inode *inode)
@@ -2043,7 +2044,7 @@ long udf_block_map(struct inode *inode, sector_t block)
	struct extent_position epos = {};
	struct extent_position epos = {};
	int ret;
	int ret;


	lock_kernel();
	down_read(&UDF_I(inode)->i_data_sem);


	if (inode_bmap(inode, block, &epos, &eloc, &elen, &offset) ==
	if (inode_bmap(inode, block, &epos, &eloc, &elen, &offset) ==
						(EXT_RECORDED_ALLOCATED >> 30))
						(EXT_RECORDED_ALLOCATED >> 30))
@@ -2051,7 +2052,7 @@ long udf_block_map(struct inode *inode, sector_t block)
	else
	else
		ret = 0;
		ret = 0;


	unlock_kernel();
	up_read(&UDF_I(inode)->i_data_sem);
	brelse(epos.bh);
	brelse(epos.bh);


	if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_VARCONV))
	if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_VARCONV))
+4 −3
Original line number Original line Diff line number Diff line
@@ -893,18 +893,18 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry,
	struct udf_inode_info *iinfo;
	struct udf_inode_info *iinfo;
	struct super_block *sb = dir->i_sb;
	struct super_block *sb = dir->i_sb;


	lock_kernel();
	inode = udf_new_inode(dir, S_IFLNK | S_IRWXUGO, &err);
	inode = udf_new_inode(dir, S_IFLNK | S_IRWXUGO, &err);
	if (!inode)
	if (!inode)
		goto out;
		goto out;


	iinfo = UDF_I(inode);
	down_write(&iinfo->i_data_sem);
	name = kmalloc(UDF_NAME_LEN, GFP_NOFS);
	name = kmalloc(UDF_NAME_LEN, GFP_NOFS);
	if (!name) {
	if (!name) {
		err = -ENOMEM;
		err = -ENOMEM;
		goto out_no_entry;
		goto out_no_entry;
	}
	}


	iinfo = UDF_I(inode);
	inode->i_data.a_ops = &udf_symlink_aops;
	inode->i_data.a_ops = &udf_symlink_aops;
	inode->i_op = &udf_symlink_inode_operations;
	inode->i_op = &udf_symlink_inode_operations;


@@ -1024,6 +1024,7 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry,
	udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL);
	udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL);
	if (UDF_I(dir)->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
	if (UDF_I(dir)->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
		mark_inode_dirty(dir);
		mark_inode_dirty(dir);
	up_write(&iinfo->i_data_sem);
	if (fibh.sbh != fibh.ebh)
	if (fibh.sbh != fibh.ebh)
		brelse(fibh.ebh);
		brelse(fibh.ebh);
	brelse(fibh.sbh);
	brelse(fibh.sbh);
@@ -1032,10 +1033,10 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry,


out:
out:
	kfree(name);
	kfree(name);
	unlock_kernel();
	return err;
	return err;


out_no_entry:
out_no_entry:
	up_write(&iinfo->i_data_sem);
	inode_dec_link_count(inode);
	inode_dec_link_count(inode);
	iput(inode);
	iput(inode);
	goto out;
	goto out;
+1 −0
Original line number Original line Diff line number Diff line
@@ -135,6 +135,7 @@ static struct inode *udf_alloc_inode(struct super_block *sb)
	ei->i_next_alloc_block = 0;
	ei->i_next_alloc_block = 0;
	ei->i_next_alloc_goal = 0;
	ei->i_next_alloc_goal = 0;
	ei->i_strat4096 = 0;
	ei->i_strat4096 = 0;
	init_rwsem(&ei->i_data_sem);


	return &ei->vfs_inode;
	return &ei->vfs_inode;
}
}
+7 −5
Original line number Original line Diff line number Diff line
@@ -27,7 +27,6 @@
#include <linux/mm.h>
#include <linux/mm.h>
#include <linux/stat.h>
#include <linux/stat.h>
#include <linux/pagemap.h>
#include <linux/pagemap.h>
#include <linux/smp_lock.h>
#include <linux/buffer_head.h>
#include <linux/buffer_head.h>
#include "udf_i.h"
#include "udf_i.h"


@@ -78,13 +77,16 @@ static int udf_symlink_filler(struct file *file, struct page *page)
	int err = -EIO;
	int err = -EIO;
	unsigned char *p = kmap(page);
	unsigned char *p = kmap(page);
	struct udf_inode_info *iinfo;
	struct udf_inode_info *iinfo;
	uint32_t pos;


	lock_kernel();
	iinfo = UDF_I(inode);
	iinfo = UDF_I(inode);
	pos = udf_block_map(inode, 0);

	down_read(&iinfo->i_data_sem);
	if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
	if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
		symlink = iinfo->i_ext.i_data + iinfo->i_lenEAttr;
		symlink = iinfo->i_ext.i_data + iinfo->i_lenEAttr;
	} else {
	} else {
		bh = sb_bread(inode->i_sb, udf_block_map(inode, 0));
		bh = sb_bread(inode->i_sb, pos);


		if (!bh)
		if (!bh)
			goto out;
			goto out;
@@ -95,14 +97,14 @@ static int udf_symlink_filler(struct file *file, struct page *page)
	udf_pc_to_char(inode->i_sb, symlink, inode->i_size, p);
	udf_pc_to_char(inode->i_sb, symlink, inode->i_size, p);
	brelse(bh);
	brelse(bh);


	unlock_kernel();
	up_read(&iinfo->i_data_sem);
	SetPageUptodate(page);
	SetPageUptodate(page);
	kunmap(page);
	kunmap(page);
	unlock_page(page);
	unlock_page(page);
	return 0;
	return 0;


out:
out:
	unlock_kernel();
	up_read(&iinfo->i_data_sem);
	SetPageError(page);
	SetPageError(page);
	kunmap(page);
	kunmap(page);
	unlock_page(page);
	unlock_page(page);
Loading