Commit 5eec54fc authored by Ian Abbott's avatar Ian Abbott Committed by Jan Kara

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: default avatarIan Abbott <abbotti@mev.co.uk>
Signed-off-by: default avatarJan Kara <jack@suse.cz>
parent 3f6bba82
...@@ -114,7 +114,7 @@ static void deliver_alarm(void) ...@@ -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, ...@@ -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) ...@@ -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, ...@@ -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;
} }
...@@ -154,6 +173,7 @@ const struct address_space_operations udf_aops = { ...@@ -154,6 +173,7 @@ const struct address_space_operations udf_aops = {
.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,
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment