Blame view
fs/reiserfs/file.c
7.62 KB
1da177e4c
|
1 2 3 |
/* * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README */ |
1da177e4c
|
4 |
#include <linux/time.h> |
f466c6fdb
|
5 |
#include "reiserfs.h" |
a3063ab88
|
6 |
#include "acl.h" |
c45ac8887
|
7 |
#include "xattr.h" |
17093991a
|
8 |
#include <linux/uaccess.h> |
1da177e4c
|
9 10 11 12 13 14 15 16 |
#include <linux/pagemap.h> #include <linux/swap.h> #include <linux/writeback.h> #include <linux/blkdev.h> #include <linux/buffer_head.h> #include <linux/quotaops.h> /* |
098297b27
|
17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
* We pack the tails of files on file close, not at the time they are written. * This implies an unnecessary copy of the tail and an unnecessary indirect item * insertion/balancing, for files that are written in one write. * It avoids unnecessary tail packings (balances) for files that are written in * multiple writes and are small enough to have tails. * * file_release is called by the VFS layer when the file is closed. If * this is the last open file descriptor, and the file * small enough to have a tail, and the tail is currently in an * unformatted node, the tail is converted back into a direct item. * * We use reiserfs_truncate_file to pack the tail, since it already has * all the conditions coded. */ |
bd4c625c0
|
31 |
static int reiserfs_file_release(struct inode *inode, struct file *filp) |
1da177e4c
|
32 |
{ |
bd4c625c0
|
33 34 35 |
struct reiserfs_transaction_handle th; int err; int jbegin_failure = 0; |
1da177e4c
|
36 |
|
14a61442c
|
37 |
BUG_ON(!S_ISREG(inode->i_mode)); |
1da177e4c
|
38 |
|
0e4f6a791
|
39 40 |
if (atomic_add_unless(&REISERFS_I(inode)->openers, -1, 1)) return 0; |
a228bf8f0
|
41 |
mutex_lock(&REISERFS_I(inode)->tailpack); |
0e4f6a791
|
42 43 |
if (!atomic_dec_and_test(&REISERFS_I(inode)->openers)) { |
a228bf8f0
|
44 |
mutex_unlock(&REISERFS_I(inode)->tailpack); |
0e4f6a791
|
45 46 |
return 0; } |
bd4c625c0
|
47 |
/* fast out for when nothing needs to be done */ |
0e4f6a791
|
48 |
if ((!(REISERFS_I(inode)->i_flags & i_pack_on_close_mask) || |
bd4c625c0
|
49 50 |
!tail_has_to_be_packed(inode)) && REISERFS_I(inode)->i_prealloc_count <= 0) { |
a228bf8f0
|
51 |
mutex_unlock(&REISERFS_I(inode)->tailpack); |
bd4c625c0
|
52 53 |
return 0; } |
1da177e4c
|
54 |
|
b5f3953c1
|
55 |
reiserfs_write_lock(inode->i_sb); |
098297b27
|
56 57 |
/* * freeing preallocation only involves relogging blocks that |
bd4c625c0
|
58 59 60 61 62 |
* are already in the current transaction. preallocation gets * freed at the end of each transaction, so it is impossible for * us to log any additional blocks (including quota blocks) */ err = journal_begin(&th, inode->i_sb, 1); |
1da177e4c
|
63 |
if (err) { |
098297b27
|
64 65 |
/* * uh oh, we can't allow the inode to go away while there |
bd4c625c0
|
66 67 68 69 |
* is still preallocation blocks pending. Try to join the * aborted transaction */ jbegin_failure = err; |
b491dd176
|
70 |
err = journal_join_abort(&th, inode->i_sb); |
bd4c625c0
|
71 72 |
if (err) { |
098297b27
|
73 74 75 76 77 78 79 |
/* * hmpf, our choices here aren't good. We can pin * the inode which will disallow unmount from ever * happening, we can do nothing, which will corrupt * random memory on unmount, or we can forcibly * remove the file from the preallocation list, which * will leak blocks on disk. Lets pin the inode |
bd4c625c0
|
80 81 82 |
* and let the admin know what is going on. */ igrab(inode); |
45b03d5e8
|
83 |
reiserfs_warning(inode->i_sb, "clm-9001", |
bd4c625c0
|
84 |
"pinning inode %lu because the " |
533221fba
|
85 86 |
"preallocation can't be freed", inode->i_ino); |
bd4c625c0
|
87 88 |
goto out; } |
1da177e4c
|
89 |
} |
bd4c625c0
|
90 |
reiserfs_update_inode_transaction(inode); |
1da177e4c
|
91 92 |
#ifdef REISERFS_PREALLOCATE |
bd4c625c0
|
93 |
reiserfs_discard_prealloc(&th, inode); |
1da177e4c
|
94 |
#endif |
58d854265
|
95 |
err = journal_end(&th); |
bd4c625c0
|
96 97 98 99 |
/* copy back the error code from journal_begin */ if (!err) err = jbegin_failure; |
0e4f6a791
|
100 |
if (!err && |
bd4c625c0
|
101 102 |
(REISERFS_I(inode)->i_flags & i_pack_on_close_mask) && tail_has_to_be_packed(inode)) { |
0e4f6a791
|
103 |
|
098297b27
|
104 105 106 107 108 109 |
/* * if regular file is released by last holder and it has been * appended (we append by unformatted node only) or its direct * item(s) had to be converted, then it may have to be * indirect2direct converted */ |
bd4c625c0
|
110 111 |
err = reiserfs_truncate_file(inode, 0); } |
cf776a7a4
|
112 |
out: |
bd4c625c0
|
113 |
reiserfs_write_unlock(inode->i_sb); |
a228bf8f0
|
114 |
mutex_unlock(&REISERFS_I(inode)->tailpack); |
bd4c625c0
|
115 |
return err; |
1da177e4c
|
116 |
} |
0e4f6a791
|
117 |
static int reiserfs_file_open(struct inode *inode, struct file *file) |
de14569f9
|
118 |
{ |
0e4f6a791
|
119 |
int err = dquot_file_open(inode, file); |
098297b27
|
120 121 |
/* somebody might be tailpacking on final close; wait for it */ |
0e4f6a791
|
122 |
if (!atomic_inc_not_zero(&REISERFS_I(inode)->openers)) { |
a228bf8f0
|
123 |
mutex_lock(&REISERFS_I(inode)->tailpack); |
0e4f6a791
|
124 |
atomic_inc(&REISERFS_I(inode)->openers); |
a228bf8f0
|
125 |
mutex_unlock(&REISERFS_I(inode)->tailpack); |
0e4f6a791
|
126 127 |
} return err; |
de14569f9
|
128 |
} |
cfac4b47c
|
129 |
void reiserfs_vfs_truncate_file(struct inode *inode) |
bd4c625c0
|
130 |
{ |
a228bf8f0
|
131 |
mutex_lock(&REISERFS_I(inode)->tailpack); |
bd4c625c0
|
132 |
reiserfs_truncate_file(inode, 1); |
a228bf8f0
|
133 |
mutex_unlock(&REISERFS_I(inode)->tailpack); |
1da177e4c
|
134 135 136 137 138 139 140 141 |
} /* Sync a reiserfs file. */ /* * FIXME: sync_mapping_buffers() never has anything to sync. Can * be removed... */ |
02c24a821
|
142 143 |
static int reiserfs_sync_file(struct file *filp, loff_t start, loff_t end, int datasync) |
bd4c625c0
|
144 |
{ |
7ea808591
|
145 |
struct inode *inode = filp->f_mapping->host; |
ee93961be
|
146 |
int err; |
bd4c625c0
|
147 |
int barrier_done; |
02c24a821
|
148 149 150 |
err = filemap_write_and_wait_range(inode->i_mapping, start, end); if (err) return err; |
5955102c9
|
151 |
inode_lock(inode); |
995c762ea
|
152 |
BUG_ON(!S_ISREG(inode->i_mode)); |
ee93961be
|
153 |
err = sync_mapping_buffers(inode->i_mapping); |
995c762ea
|
154 155 156 157 |
reiserfs_write_lock(inode->i_sb); barrier_done = reiserfs_commit_for_inode(inode); reiserfs_write_unlock(inode->i_sb); if (barrier_done != 1 && reiserfs_barrier_flush(inode->i_sb)) |
dd3932edd
|
158 |
blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL); |
5955102c9
|
159 |
inode_unlock(inode); |
bd4c625c0
|
160 161 |
if (barrier_done < 0) return barrier_done; |
ee93961be
|
162 |
return (err < 0) ? -EIO : 0; |
1da177e4c
|
163 |
} |
1da177e4c
|
164 165 |
/* taken fs/buffer.c:__block_commit_write */ int reiserfs_commit_page(struct inode *inode, struct page *page, |
bd4c625c0
|
166 |
unsigned from, unsigned to) |
1da177e4c
|
167 |
{ |
bd4c625c0
|
168 169 170 171 |
unsigned block_start, block_end; int partial = 0; unsigned blocksize; struct buffer_head *bh, *head; |
09cbfeaf1
|
172 |
unsigned long i_size_index = inode->i_size >> PAGE_SHIFT; |
bd4c625c0
|
173 174 175 |
int new; int logit = reiserfs_file_data_log(inode); struct super_block *s = inode->i_sb; |
09cbfeaf1
|
176 |
int bh_per_page = PAGE_SIZE / s->s_blocksize; |
bd4c625c0
|
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 |
struct reiserfs_transaction_handle th; int ret = 0; th.t_trans_id = 0; blocksize = 1 << inode->i_blkbits; if (logit) { reiserfs_write_lock(s); ret = journal_begin(&th, s, bh_per_page + 1); if (ret) goto drop_write_lock; reiserfs_update_inode_transaction(inode); } for (bh = head = page_buffers(page), block_start = 0; bh != head || !block_start; block_start = block_end, bh = bh->b_this_page) { new = buffer_new(bh); clear_buffer_new(bh); block_end = block_start + blocksize; if (block_end <= from || block_start >= to) { if (!buffer_uptodate(bh)) partial = 1; } else { set_buffer_uptodate(bh); if (logit) { reiserfs_prepare_for_journal(s, bh, 1); |
09f1b80ba
|
204 |
journal_mark_dirty(&th, bh); |
bd4c625c0
|
205 206 |
} else if (!buffer_dirty(bh)) { mark_buffer_dirty(bh); |
098297b27
|
207 208 |
/* * do data=ordered on any page past the end |
bd4c625c0
|
209 210 211 212 213 214 215 216 |
* of file and any buffer marked BH_New. */ if (reiserfs_data_ordered(inode->i_sb) && (new || page->index >= i_size_index)) { reiserfs_add_ordered_list(inode, bh); } } } |
1da177e4c
|
217 |
} |
bd4c625c0
|
218 |
if (logit) { |
58d854265
|
219 |
ret = journal_end(&th); |
cf776a7a4
|
220 |
drop_write_lock: |
bd4c625c0
|
221 222 223 224 225 226 227 228 229 230 231 |
reiserfs_write_unlock(s); } /* * If this is a partial write which happened to make all buffers * uptodate then we can optimize away a bogus readpage() for * the next read(). Here we 'discover' whether the page went * uptodate as a result of this (potentially partial) write. */ if (!partial) SetPageUptodate(page); return ret; |
1da177e4c
|
232 |
} |
4b6f5d20b
|
233 |
const struct file_operations reiserfs_file_operations = { |
205cb37b8
|
234 |
.unlocked_ioctl = reiserfs_ioctl, |
52b499c43
|
235 236 237 |
#ifdef CONFIG_COMPAT .compat_ioctl = reiserfs_compat_ioctl, #endif |
0e4f6a791
|
238 239 |
.mmap = generic_file_mmap, .open = reiserfs_file_open, |
bd4c625c0
|
240 241 |
.release = reiserfs_file_release, .fsync = reiserfs_sync_file, |
aad4f8bb4
|
242 |
.read_iter = generic_file_read_iter, |
8174202b3
|
243 |
.write_iter = generic_file_write_iter, |
5274f052e
|
244 |
.splice_read = generic_file_splice_read, |
8d0207652
|
245 |
.splice_write = iter_file_splice_write, |
91efc167d
|
246 |
.llseek = generic_file_llseek, |
1da177e4c
|
247 |
}; |
c5ef1c42c
|
248 |
const struct inode_operations reiserfs_file_inode_operations = { |
bd4c625c0
|
249 250 251 252 253 254 |
.setattr = reiserfs_setattr, .setxattr = reiserfs_setxattr, .getxattr = reiserfs_getxattr, .listxattr = reiserfs_listxattr, .removexattr = reiserfs_removexattr, .permission = reiserfs_permission, |
4e34e719e
|
255 |
.get_acl = reiserfs_get_acl, |
47f70d08f
|
256 |
.set_acl = reiserfs_set_acl, |
1da177e4c
|
257 |
}; |