1/* 2 * Copyright 2016, NICTA 3 * 4 * This software may be distributed and modified according to the terms of 5 * the GNU General Public License version 2. Note that NO WARRANTY is provided. 6 * See "LICENSE_GPLv2.txt" for details. 7 * 8 * @TAG(NICTA_GPL) 9 */ 10 11#include <plat/linux/wrapper_pp_inferred.c> 12 13static int ext2fs_readpage_nolock(struct file *file, struct page *page); 14static int ext2fs_writepage_nolock(struct page *page, struct writeback_control *wbc); 15static int ext2fs_writepages_nolock(struct address_space *mapping, struct writeback_control *wbc); 16static int ext2fs_readpages_nolock(struct file *file, struct address_space *mapping, 17 struct list_head *pages, unsigned nr_pages); 18static sector_t ext2fs_bmap_nolock(struct address_space *mapping, sector_t block); 19static int ext2fs_write_begin_nolock(struct file *file, struct address_space *mapping, 20 loff_t pos, unsigned len, unsigned flags, 21 struct page **pagep, void **fsdata); 22static int ext2fs_write_end_nolock(struct file *file, struct address_space *mapping, 23 loff_t pos, unsigned len, unsigned copied, 24 struct page *page, void *fsdata); 25 26/* calls writepage directly; no lock */ 27static int __nolock_write_one_page(struct page *page, int wait) 28{ 29 struct address_space *mapping = page->mapping; 30 int ret = 0; 31 struct writeback_control wbc = { 32 .sync_mode = WB_SYNC_ALL, 33 .nr_to_write = 1, 34 }; 35 36 BUG_ON(!PageLocked(page)); 37 38 if (wait) 39 wait_on_page_writeback(page); 40 41 if (clear_page_dirty_for_io(page)) { 42#if LINUX_VERSION_CODE < KERNEL_VERSION(4,4,0) 43 page_cache_get(page); 44#else 45 get_page(page); 46#endif 47 /* ret = mapping->a_ops->writepage(page, &wbc); */ 48 ret = ext2fs_writepage_nolock (page, &wbc); 49 if (ret == 0 && wait) { 50 wait_on_page_writeback(page); 51 if (PageError(page)) 52 ret = -EIO; 53 } 54#if LINUX_VERSION_CODE < KERNEL_VERSION(4,4,0) 55 page_cache_release(page); 56#else 57 put_page(page); 58#endif 59 } else { 60 unlock_page(page); 61 } 62 return ret; 63} 64 65struct kmem_cache *ext2fs_inode_slab; 66 67static struct dentry *ext2fs_mount(struct file_system_type *fs_type, 68 int flags, const char *name, void *data) 69{ 70 return mount_bdev(fs_type, flags, name, data, ext2fs_fill_super); 71} 72 73static int ext2fs_readpage(struct file *file, struct page *page) 74{ 75 struct inode *inode = page->mapping->host; 76 Ext2State *state = inode->i_sb->s_fs_info; 77 78 down(&state->iop_lock); /* aop */ 79 take_inode_addrspace(inode); 80 81 int res = ext2fs_readpage_nolock(file, page); 82 83 release_inode_addrspace(inode); 84 up(&state->iop_lock); /* aop */ 85 86 return res; 87} 88 89static int ext2fs_readpage_nolock(struct file *file, struct page *page) 90{ 91 return mpage_readpage(page, ext2fs_get_block); 92} 93 94static int ext2fs_readpages(struct file *file, struct address_space *mapping, 95 struct list_head *pages, unsigned nr_pages) 96{ 97 struct page *first_page = list_first_entry(pages, struct page, lru); /* TODO: is there a helper function to do this? */ 98 struct inode *inode = mapping->host; 99 Ext2State *state = inode->i_sb->s_fs_info; 100 101 down(&state->iop_lock); /* aop */ 102 take_inode_addrspace(inode); 103 104 int res = ext2fs_readpages_nolock(file, mapping, pages, nr_pages); 105 106 release_inode_addrspace(inode); 107 up(&state->iop_lock); /* aop */ 108 109 return res; 110} 111 112static int ext2fs_readpages_nolock(struct file *file, struct address_space *mapping, 113 struct list_head *pages, unsigned nr_pages) 114{ 115 return mpage_readpages(mapping, pages, nr_pages, ext2fs_get_block); 116} 117 118static int ext2fs_writepage(struct page *page, struct writeback_control *wbc) 119{ 120 struct inode* inode = page->mapping->host; 121 Ext2State *state = inode->i_sb->s_fs_info; 122 123 down(&state->iop_lock); /* aop */ 124 take_inode_addrspace(inode); 125 126 int res = ext2fs_writepage_nolock(page, wbc); 127 128 release_inode_addrspace(inode); 129 up(&state->iop_lock); /* aop */ 130 131 return res; 132} 133 134static int ext2fs_writepage_nolock(struct page *page, struct writeback_control *wbc) 135{ 136 137 return block_write_full_page(page, ext2fs_get_block, wbc); 138} 139 140static int ext2fs_writepages(struct address_space *mapping, struct writeback_control *wbc) 141{ 142 struct inode* inode = mapping->host; 143 Ext2State *state = inode->i_sb->s_fs_info; 144 145 down(&state->iop_lock); /* aop */ 146 take_inode_addrspace(inode); 147 148 int res = ext2fs_writepages_nolock(mapping, wbc); 149 150 release_inode_addrspace(inode); 151 up(&state->iop_lock); /* aop */ 152 153 return res; 154} 155 156static int ext2fs_writepages_nolock(struct address_space *mapping, struct writeback_control *wbc) 157{ 158 return mpage_writepages(mapping, wbc, ext2fs_get_block); 159} 160 161/* CALLER MUST LOCK */ 162static void ext2fs_write_failed(struct address_space *mapping, loff_t to) 163{ 164 struct inode *inode = mapping->host; 165 if (to > inode->i_size) { 166 truncate_pagecache(inode, inode->i_size); 167 if (ext2fs_can_truncate(inode) == 0) { 168 ext2fs_truncate(inode, inode->i_size); 169 } 170 } 171} 172 173static int ext2fs_write_begin(struct file *file, struct address_space *mapping, 174 loff_t pos, unsigned len, unsigned flags, 175 struct page **pagep, void **fsdata) 176{ 177 int ret; 178 struct inode* inode = mapping->host; 179 Ext2State *state = inode->i_sb->s_fs_info; 180 181 down(&state->iop_lock); /* aop */ 182 take_inode_addrspace(inode); 183 184 ret = ext2fs_write_begin_nolock(file, mapping, pos, len, flags, pagep, fsdata); 185 186 release_inode_addrspace(inode); 187 up(&state->iop_lock); /* aop */ 188 189 return ret; 190} 191 192static int ext2fs_write_begin_nolock(struct file *file, struct address_space *mapping, 193 loff_t pos, unsigned len, unsigned flags, 194 struct page **pagep, void **fsdata) 195{ 196 int ret = block_write_begin(mapping, pos, len, flags, pagep, ext2fs_get_block); 197 if (ret < 0) { 198 ext2fs_write_failed(mapping, pos + len); 199 } 200 201 return ret; 202} 203 204static int ext2fs_write_end(struct file *file, struct address_space *mapping, 205 loff_t pos, unsigned len, unsigned copied, 206 struct page *page, void *fsdata) 207{ 208 struct inode* inode = mapping->host; 209 Ext2State *state = inode->i_sb->s_fs_info; 210 int ret; 211 212 down(&state->iop_lock); /* aop */ 213 take_inode_addrspace(inode); 214 215 ret = ext2fs_write_end_nolock(file, mapping, pos, len, copied, page, fsdata); 216 217 release_inode_addrspace(inode); 218 up(&state->iop_lock); /* aop */ 219 220 return ret; 221} 222 223static int ext2fs_write_end_nolock(struct file *file, struct address_space *mapping, 224 loff_t pos, unsigned len, unsigned copied, 225 struct page *page, void *fsdata) 226{ 227 int ret = generic_write_end(file, mapping, pos, len, copied, page, fsdata); 228 if (ret < len) { 229 ext2fs_write_failed(mapping, pos + len); 230 } 231 232 return ret; 233} 234 235static sector_t ext2fs_bmap(struct address_space *mapping, sector_t block) 236{ 237 struct inode* inode = mapping->host; 238 Ext2State *state = inode->i_sb->s_fs_info; 239 240 down(&state->iop_lock); /* aop */ 241 sector_t res = ext2fs_bmap_nolock(mapping, block); 242 up (&state->iop_lock); /* aop */ 243 244 return res; 245} 246 247static sector_t ext2fs_bmap_nolock(struct address_space *mapping, sector_t block) 248{ 249 return generic_block_bmap(mapping, block, ext2fs_get_block); 250} 251 252/* support migrate to new internal iter API */ 253#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 7, 0) 254static ssize_t ext2fs_direct_IO_nolock(struct kiocb *iocb, 255 struct iov_iter *iter, loff_t offset) 256{ 257 struct file *file = iocb->ki_filp; 258 struct address_space *mapping = file->f_mapping; 259 struct inode *inode = mapping->host; 260 size_t count = iov_iter_count(iter); 261 ssize_t ret; 262 263 ret = blockdev_direct_IO(iocb, inode, iter, offset, ext2fs_get_block); 264 if (ret < 0) { 265 truncate_pagecache(inode, inode->i_size); 266 if (ext2fs_can_truncate(inode) == 0) { 267 ext2fs_truncate(inode, inode->i_size); 268 } 269 } 270 271 return ret; 272} 273 274static ssize_t ext2fs_direct_IO(struct kiocb *iocb, struct iov_iter *iter, 275 loff_t offset) 276{ 277 ssize_t ret; 278 struct file *file = iocb->ki_filp; 279 struct address_space *mapping = file->f_mapping; 280 struct inode *inode = mapping->host; 281 Ext2State *state = inode->i_sb->s_fs_info; 282 283 down(&state->iop_lock); /* aop */ 284 take_inode_addrspace(inode); 285 286 ret = ext2fs_direct_IO_nolock(iocb, iter, offset); 287 288 release_inode_addrspace(inode); 289 up(&state->iop_lock); /* aop */ 290 291 return ret; 292} 293 294#else /* KERNEL_VERSION > KERNEL_VERSION_CODE(4, 7, 0) */ 295static ssize_t ext2fs_direct_IO_nolock(struct kiocb *iocb, struct iov_iter *iter) 296{ 297 struct file *file = iocb->ki_filp; 298 struct address_space *mapping = file->f_mapping; 299 struct inode *inode = mapping->host; 300 size_t count = iov_iter_count(iter); 301 loff_t offset = iocb->ki_pos; 302 ssize_t ret; 303 304 ret = blockdev_direct_IO(iocb, inode, iter, ext2fs_get_block); 305 if (ret < 0 && iov_iter_rw(iter) == WRITE) 306 ext2fs_write_failed(mapping, offset + count); 307 return ret; 308} 309 310static ssize_t ext2fs_direct_IO(struct kiocb *iocb, struct iov_iter *iter) 311{ 312 ssize_t ret; 313 struct file *file = iocb->ki_filp; 314 struct address_space *mapping = file->f_mapping; 315 struct inode *inode = mapping->host; 316 Ext2State *state = inode->i_sb->s_fs_info; 317 318 down (&state->iop_lock); /* aop */ 319 take_inode_addrspace(inode); 320 321 ret = ext2fs_direct_IO_nolock(iocb, iter); 322 323 release_inode_addrspace(inode); 324 up (&state->iop_lock); /* aop */ 325 326 return ret; 327} 328#endif 329 330static void ext2fs_destroy_inode(struct inode *inode) 331{ 332 call_rcu(&inode->i_rcu, ext2fs_i_callback); 333} 334 335/* 336 * address space operations 337 * 338 * while these are top-level, then can be indirectly called by 339 * COGENT from some VFS ADT functions 340 * 341 * to prevent deadlock, we need to swap any iops to use the nolock 342 * version if we were being called from within COGENT 343 */ 344const struct address_space_operations ext2fs_address_operations = 345{ 346 .readpage = ext2fs_readpage, 347 .readpages = ext2fs_readpages, 348 .direct_IO = ext2fs_direct_IO, 349 .writepage = ext2fs_writepage, 350 .write_begin = ext2fs_write_begin, 351 .write_end = ext2fs_write_end, 352 .bmap = ext2fs_bmap, 353 .writepages = ext2fs_writepages, 354 355 .migratepage = buffer_migrate_page, 356 .is_partially_uptodate = block_is_partially_uptodate, 357 .error_remove_page = generic_error_remove_page, 358}; 359 360const struct address_space_operations ext2fs_address_operations_nolock = 361{ 362 .readpage = ext2fs_readpage_nolock, 363 .readpages = ext2fs_readpages_nolock, 364 .direct_IO = ext2fs_direct_IO_nolock, 365 .writepage = ext2fs_writepage_nolock, 366 .write_begin = ext2fs_write_begin_nolock, 367 .write_end = ext2fs_write_end_nolock, 368 .bmap = ext2fs_bmap_nolock, 369 .writepages = ext2fs_writepages_nolock, 370 371 .migratepage = buffer_migrate_page, 372 .is_partially_uptodate = block_is_partially_uptodate, 373 .error_remove_page = generic_error_remove_page, 374}; 375 376 377/* 378 * "super-block" operations 379 * these are performed on a mounted instance 380 * 381 * these functions may also be top-level or re-entrant (in particlar, *_inode) 382 */ 383const struct super_operations ext2fs_super_operations = 384{ 385 .statfs = ext2fs_statfs, /* FIXME: not re-entrant safe */ 386 387 .alloc_inode = ext2fs_alloc_inode, /* nolock */ 388 .destroy_inode = ext2fs_destroy_inode,/* nolock */ 389 .write_inode = ext2fs_write_inode, /* lockok, ret? */ 390 .evict_inode = ext2fs_evict_inode, /* lockok */ 391 392 .put_super = ext2fs_put_super, /* lockok */ 393 // sync_fs 394}; 395 396const struct super_operations ext2fs_super_operations_nolock = 397{ 398 .statfs = ext2fs_statfs, /* FIXME: not re-entrant safe */ 399 400 .alloc_inode = ext2fs_alloc_inode, /* nolock */ 401 .destroy_inode = ext2fs_destroy_inode, /* nolock */ 402 .write_inode = ext2fs_write_inode_nolock, /* lockok, ret? */ 403 .evict_inode = ext2fs_evict_inode_nolock, /* lockok */ 404 405 .put_super = ext2fs_put_super, /* lockok */ 406 // sync_fs 407}; 408 409static struct file_system_type ext2fs_fs_type = { 410 .name = "ext2fs", 411 .owner = THIS_MODULE, 412 .mount = ext2fs_mount, /* no lock */ 413 .kill_sb = kill_block_super, 414 .fs_flags = FS_REQUIRES_DEV, 415}; 416 417static void inode_slab_ctor (void *obj) 418{ 419 VfsInode *abstract_inode = obj; 420 memset(abstract_inode, 0, sizeof(VfsInode)); 421 inode_init_once (&(abstract_inode->vfs.inode_lin)); 422} 423 424static int __init ext2fs_init(void) 425{ 426 int err; 427 428 ext2fs_inode_slab = kmem_cache_create("ext2fs_inode_slab", 429 sizeof(VfsInode), 0, 430 SLAB_MEM_SPREAD | SLAB_RECLAIM_ACCOUNT, 431 &inode_slab_ctor); 432 433 if (!ext2fs_inode_slab) { 434 printk ("could not create slab cache\n"); 435 return -ENOMEM; 436 } 437 438 err = register_filesystem(&ext2fs_fs_type); 439 if (err) { 440 printk ("cannot register file system, error %d", err); 441 442 kmem_cache_destroy (ext2fs_inode_slab); 443 return err; 444 } 445 446 return 0; 447} 448 449static void __exit ext2fs_exit(void) 450{ 451 /* Ensure all delayed rcu free inodes are flushed before we 452 * destroy cache. */ 453 rcu_barrier(); 454 kmem_cache_destroy(ext2fs_inode_slab); 455 456 unregister_filesystem(&ext2fs_fs_type); 457} 458 459module_init(ext2fs_init); 460module_exit(ext2fs_exit); 461 462MODULE_LICENSE("GPL"); 463MODULE_VERSION(__stringify(EXT2FS_VERSION)); 464MODULE_AUTHOR("Alex Hixon, Peter Chubb"); 465MODULE_DESCRIPTION("EXT2FS - ext2 File System"); 466