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