提交 4d0fb621 编写于 作者: A Alessio Igor Bogani 提交者: Jan Kara

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: NAlessio Igor Bogani <abogani@texware.it>
Signed-off-by: NJan Kara <jack@suse.cz>
上级 d1668fe3
...@@ -204,10 +204,10 @@ static int udf_release_file(struct inode *inode, struct file *filp) ...@@ -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;
......
...@@ -301,10 +301,9 @@ static int udf_get_block(struct inode *inode, sector_t block, ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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))
......
...@@ -893,18 +893,18 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry, ...@@ -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, ...@@ -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, ...@@ -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;
......
...@@ -135,6 +135,7 @@ static struct inode *udf_alloc_inode(struct super_block *sb) ...@@ -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;
} }
......
...@@ -27,7 +27,6 @@ ...@@ -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) ...@@ -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) ...@@ -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);
......
#ifndef _UDF_I_H #ifndef _UDF_I_H
#define _UDF_I_H #define _UDF_I_H
/*
* The i_data_sem and i_mutex serve for protection of allocation information
* of a regular files and symlinks. This includes all extents belonging to
* the file/symlink, a fact whether data are in-inode or in external data
* blocks, preallocation, goal block information... When extents are read,
* i_mutex or i_data_sem must be held (for reading is enough in case of
* i_data_sem). When extents are changed, i_data_sem must be held for writing
* and also i_mutex must be held.
*
* For directories i_mutex is used for all the necessary protection.
*/
struct udf_inode_info { struct udf_inode_info {
struct timespec i_crtime; struct timespec i_crtime;
/* Physical address of inode */ /* Physical address of inode */
...@@ -21,6 +33,7 @@ struct udf_inode_info { ...@@ -21,6 +33,7 @@ struct udf_inode_info {
struct long_ad *i_lad; struct long_ad *i_lad;
__u8 *i_data; __u8 *i_data;
} i_ext; } i_ext;
struct rw_semaphore i_data_sem;
struct inode vfs_inode; struct inode vfs_inode;
}; };
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册