diff options
Diffstat (limited to 'fs/nilfs2/file.c')
-rw-r--r-- | fs/nilfs2/file.c | 62 |
1 files changed, 59 insertions, 3 deletions
diff --git a/fs/nilfs2/file.c b/fs/nilfs2/file.c index 7ddd42e24f77..8031086db8d5 100644 --- a/fs/nilfs2/file.c +++ b/fs/nilfs2/file.c | |||
@@ -73,10 +73,66 @@ nilfs_file_aio_write(struct kiocb *iocb, const struct iovec *iov, | |||
73 | return ret; | 73 | return ret; |
74 | } | 74 | } |
75 | 75 | ||
76 | static int nilfs_page_mkwrite(struct vm_area_struct *vma, struct page *page) | 76 | static int nilfs_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) |
77 | { | 77 | { |
78 | if (!(vma->vm_flags & (VM_WRITE | VM_MAYWRITE))) | 78 | struct page *page = vmf->page; |
79 | return -EPERM; | 79 | struct inode *inode = vma->vm_file->f_dentry->d_inode; |
80 | struct nilfs_transaction_info ti; | ||
81 | int ret; | ||
82 | |||
83 | if (unlikely(nilfs_near_disk_full(NILFS_SB(inode->i_sb)->s_nilfs))) | ||
84 | return VM_FAULT_SIGBUS; /* -ENOSPC */ | ||
85 | |||
86 | lock_page(page); | ||
87 | if (page->mapping != inode->i_mapping || | ||
88 | page_offset(page) >= i_size_read(inode) || !PageUptodate(page)) { | ||
89 | unlock_page(page); | ||
90 | return VM_FAULT_NOPAGE; /* make the VM retry the fault */ | ||
91 | } | ||
92 | |||
93 | /* | ||
94 | * check to see if the page is mapped already (no holes) | ||
95 | */ | ||
96 | if (PageMappedToDisk(page)) { | ||
97 | unlock_page(page); | ||
98 | goto mapped; | ||
99 | } | ||
100 | if (page_has_buffers(page)) { | ||
101 | struct buffer_head *bh, *head; | ||
102 | int fully_mapped = 1; | ||
103 | |||
104 | bh = head = page_buffers(page); | ||
105 | do { | ||
106 | if (!buffer_mapped(bh)) { | ||
107 | fully_mapped = 0; | ||
108 | break; | ||
109 | } | ||
110 | } while (bh = bh->b_this_page, bh != head); | ||
111 | |||
112 | if (fully_mapped) { | ||
113 | SetPageMappedToDisk(page); | ||
114 | unlock_page(page); | ||
115 | goto mapped; | ||
116 | } | ||
117 | } | ||
118 | unlock_page(page); | ||
119 | |||
120 | /* | ||
121 | * fill hole blocks | ||
122 | */ | ||
123 | ret = nilfs_transaction_begin(inode->i_sb, &ti, 1); | ||
124 | /* never returns -ENOMEM, but may return -ENOSPC */ | ||
125 | if (unlikely(ret)) | ||
126 | return VM_FAULT_SIGBUS; | ||
127 | |||
128 | ret = block_page_mkwrite(vma, vmf, nilfs_get_block); | ||
129 | if (unlikely(ret)) { | ||
130 | nilfs_transaction_abort(inode->i_sb); | ||
131 | return ret; | ||
132 | } | ||
133 | nilfs_transaction_commit(inode->i_sb); | ||
134 | |||
135 | mapped: | ||
80 | SetPageChecked(page); | 136 | SetPageChecked(page); |
81 | wait_on_page_writeback(page); | 137 | wait_on_page_writeback(page); |
82 | return 0; | 138 | return 0; |