diff options
Diffstat (limited to 'fs/ceph/addr.c')
-rw-r--r-- | fs/ceph/addr.c | 93 |
1 files changed, 81 insertions, 12 deletions
diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c index ec3ba43b9faa..b53278c9fd97 100644 --- a/fs/ceph/addr.c +++ b/fs/ceph/addr.c | |||
@@ -209,6 +209,7 @@ static int readpage_nounlock(struct file *filp, struct page *page) | |||
209 | err = 0; | 209 | err = 0; |
210 | if (err < 0) { | 210 | if (err < 0) { |
211 | SetPageError(page); | 211 | SetPageError(page); |
212 | ceph_fscache_readpage_cancel(inode, page); | ||
212 | goto out; | 213 | goto out; |
213 | } else { | 214 | } else { |
214 | if (err < PAGE_CACHE_SIZE) { | 215 | if (err < PAGE_CACHE_SIZE) { |
@@ -256,6 +257,8 @@ static void finish_read(struct ceph_osd_request *req, struct ceph_msg *msg) | |||
256 | for (i = 0; i < num_pages; i++) { | 257 | for (i = 0; i < num_pages; i++) { |
257 | struct page *page = osd_data->pages[i]; | 258 | struct page *page = osd_data->pages[i]; |
258 | 259 | ||
260 | if (rc < 0) | ||
261 | goto unlock; | ||
259 | if (bytes < (int)PAGE_CACHE_SIZE) { | 262 | if (bytes < (int)PAGE_CACHE_SIZE) { |
260 | /* zero (remainder of) page */ | 263 | /* zero (remainder of) page */ |
261 | int s = bytes < 0 ? 0 : bytes; | 264 | int s = bytes < 0 ? 0 : bytes; |
@@ -266,6 +269,7 @@ static void finish_read(struct ceph_osd_request *req, struct ceph_msg *msg) | |||
266 | flush_dcache_page(page); | 269 | flush_dcache_page(page); |
267 | SetPageUptodate(page); | 270 | SetPageUptodate(page); |
268 | ceph_readpage_to_fscache(inode, page); | 271 | ceph_readpage_to_fscache(inode, page); |
272 | unlock: | ||
269 | unlock_page(page); | 273 | unlock_page(page); |
270 | page_cache_release(page); | 274 | page_cache_release(page); |
271 | bytes -= PAGE_CACHE_SIZE; | 275 | bytes -= PAGE_CACHE_SIZE; |
@@ -1207,6 +1211,41 @@ const struct address_space_operations ceph_aops = { | |||
1207 | /* | 1211 | /* |
1208 | * vm ops | 1212 | * vm ops |
1209 | */ | 1213 | */ |
1214 | static int ceph_filemap_fault(struct vm_area_struct *vma, struct vm_fault *vmf) | ||
1215 | { | ||
1216 | struct inode *inode = file_inode(vma->vm_file); | ||
1217 | struct ceph_inode_info *ci = ceph_inode(inode); | ||
1218 | struct ceph_file_info *fi = vma->vm_file->private_data; | ||
1219 | loff_t off = vmf->pgoff << PAGE_CACHE_SHIFT; | ||
1220 | int want, got, ret; | ||
1221 | |||
1222 | dout("filemap_fault %p %llx.%llx %llu~%zd trying to get caps\n", | ||
1223 | inode, ceph_vinop(inode), off, (size_t)PAGE_CACHE_SIZE); | ||
1224 | if (fi->fmode & CEPH_FILE_MODE_LAZY) | ||
1225 | want = CEPH_CAP_FILE_CACHE | CEPH_CAP_FILE_LAZYIO; | ||
1226 | else | ||
1227 | want = CEPH_CAP_FILE_CACHE; | ||
1228 | while (1) { | ||
1229 | got = 0; | ||
1230 | ret = ceph_get_caps(ci, CEPH_CAP_FILE_RD, want, &got, -1); | ||
1231 | if (ret == 0) | ||
1232 | break; | ||
1233 | if (ret != -ERESTARTSYS) { | ||
1234 | WARN_ON(1); | ||
1235 | return VM_FAULT_SIGBUS; | ||
1236 | } | ||
1237 | } | ||
1238 | dout("filemap_fault %p %llu~%zd got cap refs on %s\n", | ||
1239 | inode, off, (size_t)PAGE_CACHE_SIZE, ceph_cap_string(got)); | ||
1240 | |||
1241 | ret = filemap_fault(vma, vmf); | ||
1242 | |||
1243 | dout("filemap_fault %p %llu~%zd dropping cap refs on %s ret %d\n", | ||
1244 | inode, off, (size_t)PAGE_CACHE_SIZE, ceph_cap_string(got), ret); | ||
1245 | ceph_put_cap_refs(ci, got); | ||
1246 | |||
1247 | return ret; | ||
1248 | } | ||
1210 | 1249 | ||
1211 | /* | 1250 | /* |
1212 | * Reuse write_begin here for simplicity. | 1251 | * Reuse write_begin here for simplicity. |
@@ -1214,23 +1253,41 @@ const struct address_space_operations ceph_aops = { | |||
1214 | static int ceph_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) | 1253 | static int ceph_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) |
1215 | { | 1254 | { |
1216 | struct inode *inode = file_inode(vma->vm_file); | 1255 | struct inode *inode = file_inode(vma->vm_file); |
1217 | struct page *page = vmf->page; | 1256 | struct ceph_inode_info *ci = ceph_inode(inode); |
1257 | struct ceph_file_info *fi = vma->vm_file->private_data; | ||
1218 | struct ceph_mds_client *mdsc = ceph_inode_to_client(inode)->mdsc; | 1258 | struct ceph_mds_client *mdsc = ceph_inode_to_client(inode)->mdsc; |
1259 | struct page *page = vmf->page; | ||
1219 | loff_t off = page_offset(page); | 1260 | loff_t off = page_offset(page); |
1220 | loff_t size, len; | 1261 | loff_t size = i_size_read(inode); |
1221 | int ret; | 1262 | size_t len; |
1222 | 1263 | int want, got, ret; | |
1223 | /* Update time before taking page lock */ | ||
1224 | file_update_time(vma->vm_file); | ||
1225 | 1264 | ||
1226 | size = i_size_read(inode); | ||
1227 | if (off + PAGE_CACHE_SIZE <= size) | 1265 | if (off + PAGE_CACHE_SIZE <= size) |
1228 | len = PAGE_CACHE_SIZE; | 1266 | len = PAGE_CACHE_SIZE; |
1229 | else | 1267 | else |
1230 | len = size & ~PAGE_CACHE_MASK; | 1268 | len = size & ~PAGE_CACHE_MASK; |
1231 | 1269 | ||
1232 | dout("page_mkwrite %p %llu~%llu page %p idx %lu\n", inode, | 1270 | dout("page_mkwrite %p %llx.%llx %llu~%zd getting caps i_size %llu\n", |
1233 | off, len, page, page->index); | 1271 | inode, ceph_vinop(inode), off, len, size); |
1272 | if (fi->fmode & CEPH_FILE_MODE_LAZY) | ||
1273 | want = CEPH_CAP_FILE_BUFFER | CEPH_CAP_FILE_LAZYIO; | ||
1274 | else | ||
1275 | want = CEPH_CAP_FILE_BUFFER; | ||
1276 | while (1) { | ||
1277 | got = 0; | ||
1278 | ret = ceph_get_caps(ci, CEPH_CAP_FILE_WR, want, &got, off + len); | ||
1279 | if (ret == 0) | ||
1280 | break; | ||
1281 | if (ret != -ERESTARTSYS) { | ||
1282 | WARN_ON(1); | ||
1283 | return VM_FAULT_SIGBUS; | ||
1284 | } | ||
1285 | } | ||
1286 | dout("page_mkwrite %p %llu~%zd got cap refs on %s\n", | ||
1287 | inode, off, len, ceph_cap_string(got)); | ||
1288 | |||
1289 | /* Update time before taking page lock */ | ||
1290 | file_update_time(vma->vm_file); | ||
1234 | 1291 | ||
1235 | lock_page(page); | 1292 | lock_page(page); |
1236 | 1293 | ||
@@ -1252,14 +1309,26 @@ static int ceph_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) | |||
1252 | ret = VM_FAULT_SIGBUS; | 1309 | ret = VM_FAULT_SIGBUS; |
1253 | } | 1310 | } |
1254 | out: | 1311 | out: |
1255 | dout("page_mkwrite %p %llu~%llu = %d\n", inode, off, len, ret); | 1312 | if (ret != VM_FAULT_LOCKED) { |
1256 | if (ret != VM_FAULT_LOCKED) | ||
1257 | unlock_page(page); | 1313 | unlock_page(page); |
1314 | } else { | ||
1315 | int dirty; | ||
1316 | spin_lock(&ci->i_ceph_lock); | ||
1317 | dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_FILE_WR); | ||
1318 | spin_unlock(&ci->i_ceph_lock); | ||
1319 | if (dirty) | ||
1320 | __mark_inode_dirty(inode, dirty); | ||
1321 | } | ||
1322 | |||
1323 | dout("page_mkwrite %p %llu~%zd dropping cap refs on %s ret %d\n", | ||
1324 | inode, off, len, ceph_cap_string(got), ret); | ||
1325 | ceph_put_cap_refs(ci, got); | ||
1326 | |||
1258 | return ret; | 1327 | return ret; |
1259 | } | 1328 | } |
1260 | 1329 | ||
1261 | static struct vm_operations_struct ceph_vmops = { | 1330 | static struct vm_operations_struct ceph_vmops = { |
1262 | .fault = filemap_fault, | 1331 | .fault = ceph_filemap_fault, |
1263 | .page_mkwrite = ceph_page_mkwrite, | 1332 | .page_mkwrite = ceph_page_mkwrite, |
1264 | .remap_pages = generic_file_remap_pages, | 1333 | .remap_pages = generic_file_remap_pages, |
1265 | }; | 1334 | }; |