aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorIan Abbott <abbotti@mev.co.uk>2012-09-05 12:44:31 -0400
committerJan Kara <jack@suse.cz>2012-09-06 10:20:39 -0400
commit5eec54fcde7e065eb3d8a6e70e61d90673ca706b (patch)
treeb5946eb5ad36a2121334e38a1ccf417fa8babd14 /fs
parent3f6bba823767e3c78efcf1bea5b6fdf98ad80e3b (diff)
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>
Diffstat (limited to 'fs')
-rw-r--r--fs/udf/file.c9
-rw-r--r--fs/udf/inode.c52
2 files changed, 45 insertions, 16 deletions
diff --git a/fs/udf/file.c b/fs/udf/file.c
index d1c6093fd3d3..77b5953eaac8 100644
--- a/fs/udf/file.c
+++ b/fs/udf/file.c
@@ -118,11 +118,20 @@ static int udf_adinicb_write_end(struct file *file,
118 return simple_write_end(file, mapping, pos, len, copied, page, fsdata); 118 return simple_write_end(file, mapping, pos, len, copied, page, fsdata);
119} 119}
120 120
121static ssize_t udf_adinicb_direct_IO(int rw, struct kiocb *iocb,
122 const struct iovec *iov,
123 loff_t offset, unsigned long nr_segs)
124{
125 /* Fallback to buffered I/O. */
126 return 0;
127}
128
121const struct address_space_operations udf_adinicb_aops = { 129const struct address_space_operations udf_adinicb_aops = {
122 .readpage = udf_adinicb_readpage, 130 .readpage = udf_adinicb_readpage,
123 .writepage = udf_adinicb_writepage, 131 .writepage = udf_adinicb_writepage,
124 .write_begin = udf_adinicb_write_begin, 132 .write_begin = udf_adinicb_write_begin,
125 .write_end = udf_adinicb_write_end, 133 .write_end = udf_adinicb_write_end,
134 .direct_IO = udf_adinicb_direct_IO,
126}; 135};
127 136
128static ssize_t udf_file_aio_write(struct kiocb *iocb, const struct iovec *iov, 137static ssize_t udf_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
diff --git a/fs/udf/inode.c b/fs/udf/inode.c
index 1a0588e77a2f..41d58309d6a8 100644
--- a/fs/udf/inode.c
+++ b/fs/udf/inode.c
@@ -95,6 +95,22 @@ void udf_evict_inode(struct inode *inode)
95 } 95 }
96} 96}
97 97
98static void udf_write_failed(struct address_space *mapping, loff_t to)
99{
100 struct inode *inode = mapping->host;
101 struct udf_inode_info *iinfo = UDF_I(inode);
102 loff_t isize = inode->i_size;
103
104 if (to > isize) {
105 truncate_pagecache(inode, to, isize);
106 if (iinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) {
107 down_write(&iinfo->i_data_sem);
108 udf_truncate_extents(inode);
109 up_write(&iinfo->i_data_sem);
110 }
111 }
112}
113
98static int udf_writepage(struct page *page, struct writeback_control *wbc) 114static int udf_writepage(struct page *page, struct writeback_control *wbc)
99{ 115{
100 return block_write_full_page(page, udf_get_block, wbc); 116 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 int ret; 140 int ret;
125 141
126 ret = block_write_begin(mapping, pos, len, flags, pagep, udf_get_block); 142 ret = block_write_begin(mapping, pos, len, flags, pagep, udf_get_block);
127 if (unlikely(ret)) { 143 if (unlikely(ret))
128 struct inode *inode = mapping->host; 144 udf_write_failed(mapping, pos + len);
129 struct udf_inode_info *iinfo = UDF_I(inode); 145 return ret;
130 loff_t isize = inode->i_size; 146}
131
132 if (pos + len > isize) {
133 truncate_pagecache(inode, pos + len, isize);
134 if (iinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) {
135 down_write(&iinfo->i_data_sem);
136 udf_truncate_extents(inode);
137 up_write(&iinfo->i_data_sem);
138 }
139 }
140 }
141 147
148static ssize_t udf_direct_IO(int rw, struct kiocb *iocb,
149 const struct iovec *iov,
150 loff_t offset, unsigned long nr_segs)
151{
152 struct file *file = iocb->ki_filp;
153 struct address_space *mapping = file->f_mapping;
154 struct inode *inode = mapping->host;
155 ssize_t ret;
156
157 ret = blockdev_direct_IO(rw, iocb, inode, iov, offset, nr_segs,
158 udf_get_block);
159 if (unlikely(ret < 0 && (rw & WRITE)))
160 udf_write_failed(mapping, offset + iov_length(iov, nr_segs));
142 return ret; 161 return ret;
143} 162}
144 163
@@ -152,8 +171,9 @@ const struct address_space_operations udf_aops = {
152 .readpages = udf_readpages, 171 .readpages = udf_readpages,
153 .writepage = udf_writepage, 172 .writepage = udf_writepage,
154 .writepages = udf_writepages, 173 .writepages = udf_writepages,
155 .write_begin = udf_write_begin, 174 .write_begin = udf_write_begin,
156 .write_end = generic_write_end, 175 .write_end = generic_write_end,
176 .direct_IO = udf_direct_IO,
157 .bmap = udf_bmap, 177 .bmap = udf_bmap,
158}; 178};
159 179