UDF: Add support for O_DIRECT
Add support for the O_DIRECT flag. There are two cases to deal with: 1. Small files stored in the ICB (inode control block?): just return 0 from the new udf_adinicb_direct_IO() handler to fall back to buffered I/O. 2. Larger files, not stored in the ICB: nothing special here. Just call blockdev_direct_IO() from our new udf_direct_IO() handler and tidy up any blocks instantiated outside i_size on error. This is pretty standard. Factor error handling code out of udf_write_begin() into new function udf_write_failed() so it can also be called by udf_direct_IO(). Also change the whitespace in udf_aops to make it a bit neater. Signed-off-by: Ian Abbott <abbotti@mev.co.uk> Signed-off-by: Jan Kara <jack@suse.cz>
This commit is contained in:
@@ -114,7 +114,7 @@ static void deliver_alarm(void)
|
|||||||
skew += this_tick - last_tick;
|
skew += this_tick - last_tick;
|
||||||
|
|
||||||
while (skew >= one_tick) {
|
while (skew >= one_tick) {
|
||||||
alarm_handler(SIGVTALRM, NULL);
|
alarm_handler(SIGVTALRM, NULL, NULL);
|
||||||
skew -= one_tick;
|
skew -= one_tick;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -118,11 +118,20 @@ static int udf_adinicb_write_end(struct file *file,
|
|||||||
return simple_write_end(file, mapping, pos, len, copied, page, fsdata);
|
return simple_write_end(file, mapping, pos, len, copied, page, fsdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ssize_t udf_adinicb_direct_IO(int rw, struct kiocb *iocb,
|
||||||
|
const struct iovec *iov,
|
||||||
|
loff_t offset, unsigned long nr_segs)
|
||||||
|
{
|
||||||
|
/* Fallback to buffered I/O. */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
const struct address_space_operations udf_adinicb_aops = {
|
const struct address_space_operations udf_adinicb_aops = {
|
||||||
.readpage = udf_adinicb_readpage,
|
.readpage = udf_adinicb_readpage,
|
||||||
.writepage = udf_adinicb_writepage,
|
.writepage = udf_adinicb_writepage,
|
||||||
.write_begin = udf_adinicb_write_begin,
|
.write_begin = udf_adinicb_write_begin,
|
||||||
.write_end = udf_adinicb_write_end,
|
.write_end = udf_adinicb_write_end,
|
||||||
|
.direct_IO = udf_adinicb_direct_IO,
|
||||||
};
|
};
|
||||||
|
|
||||||
static ssize_t udf_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
|
static ssize_t udf_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
|
||||||
|
@@ -95,6 +95,22 @@ void udf_evict_inode(struct inode *inode)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void udf_write_failed(struct address_space *mapping, loff_t to)
|
||||||
|
{
|
||||||
|
struct inode *inode = mapping->host;
|
||||||
|
struct udf_inode_info *iinfo = UDF_I(inode);
|
||||||
|
loff_t isize = inode->i_size;
|
||||||
|
|
||||||
|
if (to > isize) {
|
||||||
|
truncate_pagecache(inode, to, isize);
|
||||||
|
if (iinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) {
|
||||||
|
down_write(&iinfo->i_data_sem);
|
||||||
|
udf_truncate_extents(inode);
|
||||||
|
up_write(&iinfo->i_data_sem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int udf_writepage(struct page *page, struct writeback_control *wbc)
|
static int udf_writepage(struct page *page, struct writeback_control *wbc)
|
||||||
{
|
{
|
||||||
return block_write_full_page(page, udf_get_block, wbc);
|
return block_write_full_page(page, udf_get_block, wbc);
|
||||||
@@ -124,21 +140,24 @@ static int udf_write_begin(struct file *file, struct address_space *mapping,
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = block_write_begin(mapping, pos, len, flags, pagep, udf_get_block);
|
ret = block_write_begin(mapping, pos, len, flags, pagep, udf_get_block);
|
||||||
if (unlikely(ret)) {
|
if (unlikely(ret))
|
||||||
struct inode *inode = mapping->host;
|
udf_write_failed(mapping, pos + len);
|
||||||
struct udf_inode_info *iinfo = UDF_I(inode);
|
return ret;
|
||||||
loff_t isize = inode->i_size;
|
}
|
||||||
|
|
||||||
if (pos + len > isize) {
|
static ssize_t udf_direct_IO(int rw, struct kiocb *iocb,
|
||||||
truncate_pagecache(inode, pos + len, isize);
|
const struct iovec *iov,
|
||||||
if (iinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) {
|
loff_t offset, unsigned long nr_segs)
|
||||||
down_write(&iinfo->i_data_sem);
|
{
|
||||||
udf_truncate_extents(inode);
|
struct file *file = iocb->ki_filp;
|
||||||
up_write(&iinfo->i_data_sem);
|
struct address_space *mapping = file->f_mapping;
|
||||||
}
|
struct inode *inode = mapping->host;
|
||||||
}
|
ssize_t ret;
|
||||||
}
|
|
||||||
|
|
||||||
|
ret = blockdev_direct_IO(rw, iocb, inode, iov, offset, nr_segs,
|
||||||
|
udf_get_block);
|
||||||
|
if (unlikely(ret < 0 && (rw & WRITE)))
|
||||||
|
udf_write_failed(mapping, offset + iov_length(iov, nr_segs));
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,8 +171,9 @@ const struct address_space_operations udf_aops = {
|
|||||||
.readpages = udf_readpages,
|
.readpages = udf_readpages,
|
||||||
.writepage = udf_writepage,
|
.writepage = udf_writepage,
|
||||||
.writepages = udf_writepages,
|
.writepages = udf_writepages,
|
||||||
.write_begin = udf_write_begin,
|
.write_begin = udf_write_begin,
|
||||||
.write_end = generic_write_end,
|
.write_end = generic_write_end,
|
||||||
|
.direct_IO = udf_direct_IO,
|
||||||
.bmap = udf_bmap,
|
.bmap = udf_bmap,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user