]>
Commit | Line | Data |
---|---|---|
2cb7cef9 BS |
1 | From: Jan Kara <jack@suse.cz> |
2 | References: fate#302681 | |
3 | Subject: [PATCH 25/28] ocfs2: Add quota calls for allocation and freeing of inodes and space | |
4 | Patch-mainline: 2.6.29? | |
5 | ||
6 | Add quota calls for allocation and freeing of inodes and space, also update | |
7 | estimates on number of needed credits for a transaction. Move out inode | |
8 | allocation from ocfs2_mknod_locked() because vfs_dq_init() must be called | |
9 | outside of a transaction. | |
10 | ||
11 | Signed-off-by: Jan Kara <jack@suse.cz> | |
12 | --- | |
82094b55 AF |
13 | fs/ocfs2/alloc.c | 20 +++++++++- |
14 | fs/ocfs2/aops.c | 16 ++++++-- | |
15 | fs/ocfs2/dir.c | 24 +++++++++++- | |
16 | fs/ocfs2/file.c | 68 +++++++++++++++++++++++++++++++++--- | |
17 | fs/ocfs2/inode.c | 10 ++++- | |
18 | fs/ocfs2/journal.h | 99 ++++++++++++++++++++++++++++++++++++----------------- | |
19 | fs/ocfs2/namei.c | 44 +++++++++++++++++++++-- | |
20 | fs/ocfs2/xattr.c | 12 +++--- | |
21 | 8 files changed, 239 insertions(+), 54 deletions(-) | |
2cb7cef9 | 22 | |
82094b55 AF |
23 | --- a/fs/ocfs2/alloc.c |
24 | +++ b/fs/ocfs2/alloc.c | |
2cb7cef9 BS |
25 | @@ -28,6 +28,7 @@ |
26 | #include <linux/slab.h> | |
27 | #include <linux/highmem.h> | |
28 | #include <linux/swap.h> | |
29 | +#include <linux/quotaops.h> | |
30 | ||
31 | #define MLOG_MASK_PREFIX ML_DISK_ALLOC | |
32 | #include <cluster/masklog.h> | |
33 | @@ -5292,7 +5293,7 @@ int ocfs2_remove_btree_range(struct inod | |
34 | } | |
35 | } | |
36 | ||
37 | - handle = ocfs2_start_trans(osb, OCFS2_REMOVE_EXTENT_CREDITS); | |
38 | + handle = ocfs2_start_trans(osb, ocfs2_remove_extent_credits(inode->i_sb)); | |
39 | if (IS_ERR(handle)) { | |
40 | ret = PTR_ERR(handle); | |
41 | mlog_errno(ret); | |
42 | @@ -6523,6 +6524,8 @@ static int ocfs2_do_truncate(struct ocfs | |
43 | goto bail; | |
44 | } | |
45 | ||
46 | + vfs_dq_free_space_nodirty(inode, | |
47 | + ocfs2_clusters_to_bytes(osb->sb, clusters_to_del)); | |
48 | spin_lock(&OCFS2_I(inode)->ip_lock); | |
49 | OCFS2_I(inode)->ip_clusters = le32_to_cpu(fe->i_clusters) - | |
50 | clusters_to_del; | |
51 | @@ -6836,6 +6839,7 @@ int ocfs2_convert_inline_data_to_extents | |
52 | struct page **pages = NULL; | |
53 | loff_t end = osb->s_clustersize; | |
54 | struct ocfs2_extent_tree et; | |
55 | + int did_quota = 0; | |
56 | ||
57 | has_data = i_size_read(inode) ? 1 : 0; | |
58 | ||
59 | @@ -6855,7 +6859,8 @@ int ocfs2_convert_inline_data_to_extents | |
60 | } | |
61 | } | |
62 | ||
63 | - handle = ocfs2_start_trans(osb, OCFS2_INLINE_TO_EXTENTS_CREDITS); | |
64 | + handle = ocfs2_start_trans(osb, | |
65 | + ocfs2_inline_to_extents_credits(osb->sb)); | |
66 | if (IS_ERR(handle)) { | |
67 | ret = PTR_ERR(handle); | |
68 | mlog_errno(ret); | |
69 | @@ -6874,6 +6879,13 @@ int ocfs2_convert_inline_data_to_extents | |
70 | unsigned int page_end; | |
71 | u64 phys; | |
72 | ||
73 | + if (vfs_dq_alloc_space_nodirty(inode, | |
74 | + ocfs2_clusters_to_bytes(osb->sb, 1))) { | |
75 | + ret = -EDQUOT; | |
76 | + goto out_commit; | |
77 | + } | |
78 | + did_quota = 1; | |
79 | + | |
80 | ret = ocfs2_claim_clusters(osb, handle, data_ac, 1, &bit_off, | |
81 | &num); | |
82 | if (ret) { | |
83 | @@ -6947,6 +6959,10 @@ int ocfs2_convert_inline_data_to_extents | |
84 | } | |
85 | ||
86 | out_commit: | |
87 | + if (ret < 0 && did_quota) | |
88 | + vfs_dq_free_space_nodirty(inode, | |
89 | + ocfs2_clusters_to_bytes(osb->sb, 1)); | |
90 | + | |
91 | ocfs2_commit_trans(osb, handle); | |
92 | ||
93 | out_unlock: | |
82094b55 AF |
94 | --- a/fs/ocfs2/aops.c |
95 | +++ b/fs/ocfs2/aops.c | |
2cb7cef9 BS |
96 | @@ -27,6 +27,7 @@ |
97 | #include <linux/swap.h> | |
98 | #include <linux/pipe_fs_i.h> | |
99 | #include <linux/mpage.h> | |
100 | +#include <linux/quotaops.h> | |
101 | ||
102 | #define MLOG_MASK_PREFIX ML_FILE_IO | |
103 | #include <cluster/masklog.h> | |
82094b55 | 104 | @@ -1780,6 +1781,11 @@ int ocfs2_write_begin_nolock(struct addr |
2cb7cef9 BS |
105 | |
106 | wc->w_handle = handle; | |
107 | ||
108 | + if (clusters_to_alloc && vfs_dq_alloc_space_nodirty(inode, | |
109 | + ocfs2_clusters_to_bytes(osb->sb, clusters_to_alloc))) { | |
110 | + ret = -EDQUOT; | |
111 | + goto out_commit; | |
112 | + } | |
113 | /* | |
114 | * We don't want this to fail in ocfs2_write_end(), so do it | |
115 | * here. | |
82094b55 | 116 | @@ -1788,7 +1794,7 @@ int ocfs2_write_begin_nolock(struct addr |
2cb7cef9 BS |
117 | OCFS2_JOURNAL_ACCESS_WRITE); |
118 | if (ret) { | |
119 | mlog_errno(ret); | |
120 | - goto out_commit; | |
121 | + goto out_quota; | |
122 | } | |
123 | ||
124 | /* | |
82094b55 AF |
125 | @@ -1800,14 +1806,14 @@ int ocfs2_write_begin_nolock(struct addr |
126 | cluster_of_pages, mmap_page); | |
2cb7cef9 BS |
127 | if (ret) { |
128 | mlog_errno(ret); | |
129 | - goto out_commit; | |
130 | + goto out_quota; | |
131 | } | |
132 | ||
133 | ret = ocfs2_write_cluster_by_desc(mapping, data_ac, meta_ac, wc, pos, | |
134 | len); | |
135 | if (ret) { | |
136 | mlog_errno(ret); | |
137 | - goto out_commit; | |
138 | + goto out_quota; | |
139 | } | |
140 | ||
141 | if (data_ac) | |
82094b55 | 142 | @@ -1819,6 +1825,10 @@ success: |
2cb7cef9 BS |
143 | *pagep = wc->w_target_page; |
144 | *fsdata = wc; | |
145 | return 0; | |
146 | +out_quota: | |
147 | + if (clusters_to_alloc) | |
148 | + vfs_dq_free_space(inode, | |
149 | + ocfs2_clusters_to_bytes(osb->sb, clusters_to_alloc)); | |
150 | out_commit: | |
151 | ocfs2_commit_trans(osb, handle); | |
152 | ||
82094b55 AF |
153 | --- a/fs/ocfs2/dir.c |
154 | +++ b/fs/ocfs2/dir.c | |
2cb7cef9 BS |
155 | @@ -40,6 +40,7 @@ |
156 | #include <linux/types.h> | |
157 | #include <linux/slab.h> | |
158 | #include <linux/highmem.h> | |
159 | +#include <linux/quotaops.h> | |
160 | ||
161 | #define MLOG_MASK_PREFIX ML_NAMEI | |
162 | #include <cluster/masklog.h> | |
163 | @@ -1216,9 +1217,9 @@ static int ocfs2_expand_inline_dir(struc | |
164 | unsigned int blocks_wanted, | |
165 | struct buffer_head **first_block_bh) | |
166 | { | |
167 | - int ret, credits = OCFS2_INLINE_TO_EXTENTS_CREDITS; | |
168 | u32 alloc, bit_off, len; | |
169 | struct super_block *sb = dir->i_sb; | |
170 | + int ret, credits = ocfs2_inline_to_extents_credits(sb); | |
171 | u64 blkno, bytes = blocks_wanted << sb->s_blocksize_bits; | |
172 | struct ocfs2_super *osb = OCFS2_SB(dir->i_sb); | |
173 | struct ocfs2_inode_info *oi = OCFS2_I(dir); | |
174 | @@ -1227,6 +1228,7 @@ static int ocfs2_expand_inline_dir(struc | |
175 | struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; | |
176 | handle_t *handle; | |
177 | struct ocfs2_extent_tree et; | |
178 | + int did_quota = 0; | |
179 | ||
180 | ocfs2_init_dinode_extent_tree(&et, dir, di_bh); | |
181 | ||
182 | @@ -1264,6 +1266,12 @@ static int ocfs2_expand_inline_dir(struc | |
183 | goto out_sem; | |
184 | } | |
185 | ||
186 | + if (vfs_dq_alloc_space_nodirty(dir, | |
187 | + ocfs2_clusters_to_bytes(osb->sb, alloc))) { | |
188 | + ret = -EDQUOT; | |
189 | + goto out_commit; | |
190 | + } | |
191 | + did_quota = 1; | |
192 | /* | |
193 | * Try to claim as many clusters as the bitmap can give though | |
194 | * if we only get one now, that's enough to continue. The rest | |
195 | @@ -1386,6 +1394,9 @@ static int ocfs2_expand_inline_dir(struc | |
196 | dirdata_bh = NULL; | |
197 | ||
198 | out_commit: | |
199 | + if (ret < 0 && did_quota) | |
200 | + vfs_dq_free_space_nodirty(dir, | |
201 | + ocfs2_clusters_to_bytes(osb->sb, 2)); | |
202 | ocfs2_commit_trans(osb, handle); | |
203 | ||
204 | out_sem: | |
205 | @@ -1410,7 +1421,7 @@ static int ocfs2_do_extend_dir(struct su | |
206 | struct buffer_head **new_bh) | |
207 | { | |
208 | int status; | |
209 | - int extend; | |
210 | + int extend, did_quota = 0; | |
211 | u64 p_blkno, v_blkno; | |
212 | ||
213 | spin_lock(&OCFS2_I(dir)->ip_lock); | |
214 | @@ -1420,6 +1431,13 @@ static int ocfs2_do_extend_dir(struct su | |
215 | if (extend) { | |
216 | u32 offset = OCFS2_I(dir)->ip_clusters; | |
217 | ||
82094b55 AF |
218 | + if (vfs_dq_alloc_space_nodirty(dir, |
219 | + ocfs2_clusters_to_bytes(sb, 1))) { | |
220 | + status = -EDQUOT; | |
221 | + goto bail; | |
222 | + } | |
223 | + did_quota = 1; | |
2cb7cef9 BS |
224 | + |
225 | status = ocfs2_add_inode_data(OCFS2_SB(sb), dir, &offset, | |
226 | 1, 0, parent_fe_bh, handle, | |
227 | data_ac, meta_ac, NULL); | |
228 | @@ -1445,6 +1463,8 @@ static int ocfs2_do_extend_dir(struct su | |
229 | } | |
230 | status = 0; | |
231 | bail: | |
232 | + if (did_quota && status < 0) | |
233 | + vfs_dq_free_space_nodirty(dir, ocfs2_clusters_to_bytes(sb, 1)); | |
234 | mlog_exit(status); | |
235 | return status; | |
236 | } | |
82094b55 AF |
237 | --- a/fs/ocfs2/file.c |
238 | +++ b/fs/ocfs2/file.c | |
2cb7cef9 BS |
239 | @@ -35,6 +35,7 @@ |
240 | #include <linux/mount.h> | |
241 | #include <linux/writeback.h> | |
242 | #include <linux/falloc.h> | |
243 | +#include <linux/quotaops.h> | |
244 | ||
245 | #define MLOG_MASK_PREFIX ML_INODE | |
246 | #include <cluster/masklog.h> | |
247 | @@ -57,6 +58,7 @@ | |
248 | #include "super.h" | |
249 | #include "xattr.h" | |
250 | #include "acl.h" | |
251 | +#include "quota.h" | |
252 | ||
253 | #include "buffer_head_io.h" | |
254 | ||
255 | @@ -537,6 +539,8 @@ static int __ocfs2_extend_allocation(str | |
256 | enum ocfs2_alloc_restarted why; | |
257 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); | |
258 | struct ocfs2_extent_tree et; | |
259 | + u32 total_clusters = clusters_to_add; | |
260 | + int did_quota = 0; | |
261 | ||
262 | mlog_entry("(clusters_to_add = %u)\n", clusters_to_add); | |
263 | ||
264 | @@ -585,6 +589,12 @@ restart_all: | |
265 | goto leave; | |
266 | } | |
267 | ||
268 | + if (!did_quota && vfs_dq_alloc_space_nodirty(inode, | |
269 | + ocfs2_clusters_to_bytes(osb->sb, total_clusters))) { | |
270 | + status = -EDQUOT; | |
271 | + goto leave; | |
272 | + } | |
273 | + did_quota = 1; | |
274 | restarted_transaction: | |
275 | /* reserve a write to the file entry early on - that we if we | |
276 | * run out of credits in the allocation path, we can still | |
277 | @@ -655,6 +665,9 @@ restarted_transaction: | |
278 | OCFS2_I(inode)->ip_clusters, (long long)i_size_read(inode)); | |
279 | ||
280 | leave: | |
281 | + if (status < 0 && did_quota) | |
282 | + vfs_dq_free_space(inode, | |
283 | + ocfs2_clusters_to_bytes(osb->sb, total_clusters)); | |
284 | if (handle) { | |
285 | ocfs2_commit_trans(osb, handle); | |
286 | handle = NULL; | |
287 | @@ -886,6 +899,9 @@ int ocfs2_setattr(struct dentry *dentry, | |
288 | struct ocfs2_super *osb = OCFS2_SB(sb); | |
289 | struct buffer_head *bh = NULL; | |
290 | handle_t *handle = NULL; | |
291 | + int locked[MAXQUOTAS] = {0, 0}; | |
292 | + int credits, qtype; | |
293 | + struct ocfs2_mem_dqinfo *oinfo; | |
294 | ||
295 | mlog_entry("(0x%p, '%.*s')\n", dentry, | |
296 | dentry->d_name.len, dentry->d_name.name); | |
297 | @@ -956,11 +972,47 @@ int ocfs2_setattr(struct dentry *dentry, | |
298 | } | |
299 | } | |
300 | ||
301 | - handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS); | |
302 | - if (IS_ERR(handle)) { | |
303 | - status = PTR_ERR(handle); | |
304 | - mlog_errno(status); | |
305 | - goto bail_unlock; | |
306 | + if ((attr->ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) || | |
307 | + (attr->ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid)) { | |
308 | + credits = OCFS2_INODE_UPDATE_CREDITS; | |
309 | + if (attr->ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid | |
310 | + && OCFS2_HAS_RO_COMPAT_FEATURE(sb, | |
311 | + OCFS2_FEATURE_RO_COMPAT_USRQUOTA)) { | |
312 | + oinfo = sb_dqinfo(sb, USRQUOTA)->dqi_priv; | |
313 | + status = ocfs2_lock_global_qf(oinfo, 1); | |
314 | + if (status < 0) | |
315 | + goto bail_unlock; | |
316 | + credits += ocfs2_calc_qinit_credits(sb, USRQUOTA) + | |
317 | + ocfs2_calc_qdel_credits(sb, USRQUOTA); | |
318 | + locked[USRQUOTA] = 1; | |
319 | + } | |
320 | + if (attr->ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid | |
321 | + && OCFS2_HAS_RO_COMPAT_FEATURE(sb, | |
322 | + OCFS2_FEATURE_RO_COMPAT_GRPQUOTA)) { | |
323 | + oinfo = sb_dqinfo(sb, GRPQUOTA)->dqi_priv; | |
324 | + status = ocfs2_lock_global_qf(oinfo, 1); | |
325 | + if (status < 0) | |
326 | + goto bail_unlock; | |
327 | + credits += ocfs2_calc_qinit_credits(sb, GRPQUOTA) + | |
328 | + ocfs2_calc_qdel_credits(sb, GRPQUOTA); | |
329 | + locked[GRPQUOTA] = 1; | |
330 | + } | |
331 | + handle = ocfs2_start_trans(osb, credits); | |
332 | + if (IS_ERR(handle)) { | |
333 | + status = PTR_ERR(handle); | |
334 | + mlog_errno(status); | |
335 | + goto bail_unlock; | |
336 | + } | |
337 | + status = vfs_dq_transfer(inode, attr) ? -EDQUOT : 0; | |
338 | + if (status < 0) | |
339 | + goto bail_commit; | |
340 | + } else { | |
341 | + handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS); | |
342 | + if (IS_ERR(handle)) { | |
343 | + status = PTR_ERR(handle); | |
344 | + mlog_errno(status); | |
345 | + goto bail_unlock; | |
346 | + } | |
347 | } | |
348 | ||
349 | /* | |
350 | @@ -983,6 +1035,12 @@ int ocfs2_setattr(struct dentry *dentry, | |
351 | bail_commit: | |
352 | ocfs2_commit_trans(osb, handle); | |
353 | bail_unlock: | |
354 | + for (qtype = 0; qtype < MAXQUOTAS; qtype++) { | |
355 | + if (!locked[qtype]) | |
356 | + continue; | |
357 | + oinfo = sb_dqinfo(sb, qtype)->dqi_priv; | |
358 | + ocfs2_unlock_global_qf(oinfo, 1); | |
359 | + } | |
360 | ocfs2_inode_unlock(inode, 1); | |
361 | bail_unlock_rw: | |
362 | if (size_change) | |
82094b55 AF |
363 | --- a/fs/ocfs2/inode.c |
364 | +++ b/fs/ocfs2/inode.c | |
2cb7cef9 BS |
365 | @@ -28,6 +28,7 @@ |
366 | #include <linux/slab.h> | |
367 | #include <linux/highmem.h> | |
368 | #include <linux/pagemap.h> | |
369 | +#include <linux/quotaops.h> | |
370 | ||
371 | #include <asm/byteorder.h> | |
372 | ||
373 | @@ -619,7 +620,8 @@ static int ocfs2_remove_inode(struct ino | |
374 | goto bail; | |
375 | } | |
376 | ||
377 | - handle = ocfs2_start_trans(osb, OCFS2_DELETE_INODE_CREDITS); | |
378 | + handle = ocfs2_start_trans(osb, OCFS2_DELETE_INODE_CREDITS + | |
379 | + ocfs2_quota_trans_credits(inode->i_sb)); | |
380 | if (IS_ERR(handle)) { | |
381 | status = PTR_ERR(handle); | |
382 | mlog_errno(status); | |
383 | @@ -651,6 +653,7 @@ static int ocfs2_remove_inode(struct ino | |
384 | } | |
385 | ||
386 | ocfs2_remove_from_cache(inode, di_bh); | |
387 | + vfs_dq_free_inode(inode); | |
388 | ||
389 | status = ocfs2_free_dinode(handle, inode_alloc_inode, | |
390 | inode_alloc_bh, di); | |
391 | @@ -933,7 +936,10 @@ void ocfs2_delete_inode(struct inode *in | |
392 | ||
393 | mlog_entry("(inode->i_ino = %lu)\n", inode->i_ino); | |
394 | ||
395 | - if (is_bad_inode(inode)) { | |
396 | + /* When we fail in read_inode() we mark inode as bad. The second test | |
397 | + * catches the case when inode allocation fails before allocating | |
398 | + * a block for inode. */ | |
399 | + if (is_bad_inode(inode) || !OCFS2_I(inode)->ip_blkno) { | |
400 | mlog(0, "Skipping delete of bad inode\n"); | |
401 | goto bail; | |
402 | } | |
82094b55 AF |
403 | --- a/fs/ocfs2/journal.h |
404 | +++ b/fs/ocfs2/journal.h | |
2cb7cef9 BS |
405 | @@ -293,6 +293,37 @@ int ocfs2_journal_dirty |
406 | /* extended attribute block update */ | |
407 | #define OCFS2_XATTR_BLOCK_UPDATE_CREDITS 1 | |
408 | ||
409 | +/* global quotafile inode update, data block */ | |
410 | +#define OCFS2_QINFO_WRITE_CREDITS (OCFS2_INODE_UPDATE_CREDITS + 1) | |
411 | + | |
412 | +/* | |
413 | + * The two writes below can accidentally see global info dirty due | |
414 | + * to set_info() quotactl so make them prepared for the writes. | |
415 | + */ | |
416 | +/* quota data block, global info */ | |
417 | +/* Write to local quota file */ | |
418 | +#define OCFS2_QWRITE_CREDITS (OCFS2_QINFO_WRITE_CREDITS + 1) | |
419 | + | |
420 | +/* global quota data block, local quota data block, global quota inode, | |
421 | + * global quota info */ | |
422 | +#define OCFS2_QSYNC_CREDITS (OCFS2_INODE_UPDATE_CREDITS + 3) | |
423 | + | |
424 | +static inline int ocfs2_quota_trans_credits(struct super_block *sb) | |
425 | +{ | |
426 | + int credits = 0; | |
427 | + | |
428 | + if (OCFS2_HAS_RO_COMPAT_FEATURE(sb, OCFS2_FEATURE_RO_COMPAT_USRQUOTA)) | |
429 | + credits += OCFS2_QWRITE_CREDITS; | |
430 | + if (OCFS2_HAS_RO_COMPAT_FEATURE(sb, OCFS2_FEATURE_RO_COMPAT_GRPQUOTA)) | |
431 | + credits += OCFS2_QWRITE_CREDITS; | |
432 | + return credits; | |
433 | +} | |
434 | + | |
435 | +/* Number of credits needed for removing quota structure from file */ | |
436 | +int ocfs2_calc_qdel_credits(struct super_block *sb, int type); | |
437 | +/* Number of credits needed for initialization of new quota structure */ | |
438 | +int ocfs2_calc_qinit_credits(struct super_block *sb, int type); | |
439 | + | |
440 | /* group extend. inode update and last group update. */ | |
441 | #define OCFS2_GROUP_EXTEND_CREDITS (OCFS2_INODE_UPDATE_CREDITS + 1) | |
442 | ||
443 | @@ -303,8 +334,11 @@ int ocfs2_journal_dirty | |
444 | * prev. group desc. if we relink. */ | |
445 | #define OCFS2_SUBALLOC_ALLOC (3) | |
446 | ||
447 | -#define OCFS2_INLINE_TO_EXTENTS_CREDITS (OCFS2_SUBALLOC_ALLOC \ | |
448 | - + OCFS2_INODE_UPDATE_CREDITS) | |
449 | +static inline int ocfs2_inline_to_extents_credits(struct super_block *sb) | |
450 | +{ | |
451 | + return OCFS2_SUBALLOC_ALLOC + OCFS2_INODE_UPDATE_CREDITS + | |
452 | + ocfs2_quota_trans_credits(sb); | |
453 | +} | |
454 | ||
455 | /* dinode + group descriptor update. We don't relink on free yet. */ | |
456 | #define OCFS2_SUBALLOC_FREE (2) | |
457 | @@ -313,16 +347,23 @@ int ocfs2_journal_dirty | |
458 | #define OCFS2_TRUNCATE_LOG_FLUSH_ONE_REC (OCFS2_SUBALLOC_FREE \ | |
459 | + OCFS2_TRUNCATE_LOG_UPDATE) | |
460 | ||
461 | -#define OCFS2_REMOVE_EXTENT_CREDITS (OCFS2_TRUNCATE_LOG_UPDATE + OCFS2_INODE_UPDATE_CREDITS) | |
462 | +static inline int ocfs2_remove_extent_credits(struct super_block *sb) | |
463 | +{ | |
464 | + return OCFS2_TRUNCATE_LOG_UPDATE + OCFS2_INODE_UPDATE_CREDITS + | |
465 | + ocfs2_quota_trans_credits(sb); | |
466 | +} | |
467 | ||
468 | /* data block for new dir/symlink, 2 for bitmap updates (bitmap fe + | |
469 | * bitmap block for the new bit) */ | |
470 | #define OCFS2_DIR_LINK_ADDITIONAL_CREDITS (1 + 2) | |
471 | ||
472 | /* parent fe, parent block, new file entry, inode alloc fe, inode alloc | |
473 | - * group descriptor + mkdir/symlink blocks */ | |
474 | -#define OCFS2_MKNOD_CREDITS (3 + OCFS2_SUBALLOC_ALLOC \ | |
475 | - + OCFS2_DIR_LINK_ADDITIONAL_CREDITS) | |
476 | + * group descriptor + mkdir/symlink blocks + quota update */ | |
477 | +static inline int ocfs2_mknod_credits(struct super_block *sb) | |
478 | +{ | |
479 | + return 3 + OCFS2_SUBALLOC_ALLOC + OCFS2_DIR_LINK_ADDITIONAL_CREDITS + | |
480 | + ocfs2_quota_trans_credits(sb); | |
481 | +} | |
482 | ||
483 | /* local alloc metadata change + main bitmap updates */ | |
484 | #define OCFS2_WINDOW_MOVE_CREDITS (OCFS2_INODE_UPDATE_CREDITS \ | |
485 | @@ -332,13 +373,21 @@ int ocfs2_journal_dirty | |
486 | * for the dinode, one for the new block. */ | |
487 | #define OCFS2_SIMPLE_DIR_EXTEND_CREDITS (2) | |
488 | ||
489 | -/* file update (nlink, etc) + directory mtime/ctime + dir entry block */ | |
490 | -#define OCFS2_LINK_CREDITS (2*OCFS2_INODE_UPDATE_CREDITS + 1) | |
491 | +/* file update (nlink, etc) + directory mtime/ctime + dir entry block + quota | |
492 | + * update on dir */ | |
493 | +static inline int ocfs2_link_credits(struct super_block *sb) | |
494 | +{ | |
495 | + return 2*OCFS2_INODE_UPDATE_CREDITS + 1 + | |
496 | + ocfs2_quota_trans_credits(sb); | |
497 | +} | |
498 | ||
499 | /* inode + dir inode (if we unlink a dir), + dir entry block + orphan | |
500 | * dir inode link */ | |
501 | -#define OCFS2_UNLINK_CREDITS (2 * OCFS2_INODE_UPDATE_CREDITS + 1 \ | |
502 | - + OCFS2_LINK_CREDITS) | |
503 | +static inline int ocfs2_unlink_credits(struct super_block *sb) | |
504 | +{ | |
505 | + /* The quota update from ocfs2_link_credits is unused here... */ | |
506 | + return 2 * OCFS2_INODE_UPDATE_CREDITS + 1 + ocfs2_link_credits(sb); | |
507 | +} | |
508 | ||
509 | /* dinode + orphan dir dinode + inode alloc dinode + orphan dir entry + | |
510 | * inode alloc group descriptor */ | |
511 | @@ -347,8 +396,10 @@ int ocfs2_journal_dirty | |
512 | /* dinode update, old dir dinode update, new dir dinode update, old | |
513 | * dir dir entry, new dir dir entry, dir entry update for renaming | |
514 | * directory + target unlink */ | |
515 | -#define OCFS2_RENAME_CREDITS (3 * OCFS2_INODE_UPDATE_CREDITS + 3 \ | |
516 | - + OCFS2_UNLINK_CREDITS) | |
517 | +static inline int ocfs2_rename_credits(struct super_block *sb) | |
518 | +{ | |
519 | + return 3 * OCFS2_INODE_UPDATE_CREDITS + 3 + ocfs2_unlink_credits(sb); | |
520 | +} | |
521 | ||
522 | /* global bitmap dinode, group desc., relinked group, | |
523 | * suballocator dinode, group desc., relinked group, | |
524 | @@ -357,21 +408,6 @@ int ocfs2_journal_dirty | |
525 | + OCFS2_INODE_UPDATE_CREDITS \ | |
526 | + OCFS2_XATTR_BLOCK_UPDATE_CREDITS) | |
527 | ||
528 | -/* global quotafile inode update, data block */ | |
529 | -#define OCFS2_QINFO_WRITE_CREDITS (OCFS2_INODE_UPDATE_CREDITS + 1) | |
530 | - | |
531 | -/* | |
532 | - * The two writes below can accidentally see global info dirty due | |
533 | - * to set_info() quotactl so make them prepared for the writes. | |
534 | - */ | |
535 | -/* quota data block, global info */ | |
536 | -/* Write to local quota file */ | |
537 | -#define OCFS2_QWRITE_CREDITS (OCFS2_QINFO_WRITE_CREDITS + 1) | |
538 | - | |
539 | -/* global quota data block, local quota data block, global quota inode, | |
540 | - * global quota info */ | |
541 | -#define OCFS2_QSYNC_CREDITS (OCFS2_INODE_UPDATE_CREDITS + 3) | |
542 | - | |
543 | /* | |
544 | * Please note that the caller must make sure that root_el is the root | |
545 | * of extent tree. So for an inode, it should be &fe->id2.i_list. Otherwise | |
546 | @@ -401,18 +437,19 @@ static inline int ocfs2_calc_extend_cred | |
547 | * credit for the dinode there. */ | |
548 | extent_blocks = 1 + 1 + le16_to_cpu(root_el->l_tree_depth); | |
549 | ||
550 | - return bitmap_blocks + sysfile_bitmap_blocks + extent_blocks; | |
551 | + return bitmap_blocks + sysfile_bitmap_blocks + extent_blocks + | |
552 | + ocfs2_quota_trans_credits(sb); | |
553 | } | |
554 | ||
555 | static inline int ocfs2_calc_symlink_credits(struct super_block *sb) | |
556 | { | |
557 | - int blocks = OCFS2_MKNOD_CREDITS; | |
558 | + int blocks = ocfs2_mknod_credits(sb); | |
559 | ||
560 | /* links can be longer than one block so we may update many | |
561 | * within our single allocated extent. */ | |
562 | blocks += ocfs2_clusters_to_blocks(sb, 1); | |
563 | ||
564 | - return blocks; | |
565 | + return blocks + ocfs2_quota_trans_credits(sb); | |
566 | } | |
567 | ||
568 | static inline int ocfs2_calc_group_alloc_credits(struct super_block *sb, | |
569 | @@ -449,6 +486,8 @@ static inline int ocfs2_calc_tree_trunc_ | |
570 | /* update to the truncate log. */ | |
571 | credits += OCFS2_TRUNCATE_LOG_UPDATE; | |
572 | ||
573 | + credits += ocfs2_quota_trans_credits(sb); | |
574 | + | |
575 | return credits; | |
576 | } | |
577 | ||
82094b55 AF |
578 | --- a/fs/ocfs2/namei.c |
579 | +++ b/fs/ocfs2/namei.c | |
2cb7cef9 BS |
580 | @@ -40,6 +40,7 @@ |
581 | #include <linux/types.h> | |
582 | #include <linux/slab.h> | |
583 | #include <linux/highmem.h> | |
584 | +#include <linux/quotaops.h> | |
585 | ||
586 | #define MLOG_MASK_PREFIX ML_NAMEI | |
587 | #include <cluster/masklog.h> | |
588 | @@ -212,6 +213,7 @@ static struct inode *ocfs2_get_init_inod | |
589 | } else | |
590 | inode->i_gid = current->fsgid; | |
591 | inode->i_mode = mode; | |
592 | + vfs_dq_init(inode); | |
593 | return inode; | |
594 | } | |
595 | ||
596 | @@ -233,6 +235,7 @@ static int ocfs2_mknod(struct inode *dir | |
597 | struct ocfs2_alloc_context *xattr_ac = NULL; | |
598 | int want_clusters = 0; | |
599 | int xattr_credits = 0; | |
600 | + int did_quota_inode = 0; | |
601 | struct ocfs2_security_xattr_info si = { | |
602 | .enable = 1, | |
603 | }; | |
604 | @@ -323,7 +326,8 @@ static int ocfs2_mknod(struct inode *dir | |
605 | goto leave; | |
606 | } | |
607 | ||
608 | - handle = ocfs2_start_trans(osb, OCFS2_MKNOD_CREDITS + xattr_credits); | |
609 | + handle = ocfs2_start_trans(osb, | |
610 | + ocfs2_mknod_credits(dir->i_sb) + xattr_credits); | |
611 | if (IS_ERR(handle)) { | |
612 | status = PTR_ERR(handle); | |
613 | handle = NULL; | |
614 | @@ -331,6 +335,15 @@ static int ocfs2_mknod(struct inode *dir | |
615 | goto leave; | |
616 | } | |
617 | ||
618 | + /* We don't use standard VFS wrapper because we don't want vfs_dq_init | |
619 | + * to be called. */ | |
620 | + if (sb_any_quota_active(osb->sb) && | |
621 | + osb->sb->dq_op->alloc_inode(inode, 1) == NO_QUOTA) { | |
622 | + status = -EDQUOT; | |
623 | + goto leave; | |
624 | + } | |
625 | + did_quota_inode = 1; | |
626 | + | |
627 | /* do the real work now. */ | |
628 | status = ocfs2_mknod_locked(osb, dir, inode, dentry, dev, | |
629 | &new_fe_bh, parent_fe_bh, handle, | |
630 | @@ -399,6 +412,8 @@ static int ocfs2_mknod(struct inode *dir | |
631 | d_instantiate(dentry, inode); | |
632 | status = 0; | |
633 | leave: | |
634 | + if (status < 0 && did_quota_inode) | |
635 | + vfs_dq_free_inode(inode); | |
636 | if (handle) | |
637 | ocfs2_commit_trans(osb, handle); | |
638 | ||
639 | @@ -649,7 +664,7 @@ static int ocfs2_link(struct dentry *old | |
640 | goto out_unlock_inode; | |
641 | } | |
642 | ||
643 | - handle = ocfs2_start_trans(osb, OCFS2_LINK_CREDITS); | |
644 | + handle = ocfs2_start_trans(osb, ocfs2_link_credits(osb->sb)); | |
645 | if (IS_ERR(handle)) { | |
646 | err = PTR_ERR(handle); | |
647 | handle = NULL; | |
648 | @@ -836,7 +851,7 @@ static int ocfs2_unlink(struct inode *di | |
649 | } | |
650 | } | |
651 | ||
652 | - handle = ocfs2_start_trans(osb, OCFS2_UNLINK_CREDITS); | |
653 | + handle = ocfs2_start_trans(osb, ocfs2_unlink_credits(osb->sb)); | |
654 | if (IS_ERR(handle)) { | |
655 | status = PTR_ERR(handle); | |
656 | handle = NULL; | |
657 | @@ -1242,7 +1257,7 @@ static int ocfs2_rename(struct inode *ol | |
658 | } | |
659 | } | |
660 | ||
661 | - handle = ocfs2_start_trans(osb, OCFS2_RENAME_CREDITS); | |
662 | + handle = ocfs2_start_trans(osb, ocfs2_rename_credits(osb->sb)); | |
663 | if (IS_ERR(handle)) { | |
664 | status = PTR_ERR(handle); | |
665 | handle = NULL; | |
666 | @@ -1560,6 +1575,7 @@ static int ocfs2_symlink(struct inode *d | |
667 | struct ocfs2_alloc_context *xattr_ac = NULL; | |
668 | int want_clusters = 0; | |
669 | int xattr_credits = 0; | |
670 | + int did_quota = 0, did_quota_inode = 0; | |
671 | struct ocfs2_security_xattr_info si = { | |
672 | .enable = 1, | |
673 | }; | |
674 | @@ -1656,6 +1672,15 @@ static int ocfs2_symlink(struct inode *d | |
675 | goto bail; | |
676 | } | |
677 | ||
678 | + /* We don't use standard VFS wrapper because we don't want vfs_dq_init | |
679 | + * to be called. */ | |
680 | + if (sb_any_quota_active(osb->sb) && | |
681 | + osb->sb->dq_op->alloc_inode(inode, 1) == NO_QUOTA) { | |
682 | + status = -EDQUOT; | |
683 | + goto bail; | |
684 | + } | |
685 | + did_quota_inode = 1; | |
686 | + | |
687 | status = ocfs2_mknod_locked(osb, dir, inode, dentry, | |
688 | 0, &new_fe_bh, parent_fe_bh, handle, | |
689 | inode_ac); | |
690 | @@ -1671,6 +1696,12 @@ static int ocfs2_symlink(struct inode *d | |
691 | u32 offset = 0; | |
692 | ||
693 | inode->i_op = &ocfs2_symlink_inode_operations; | |
694 | + if (vfs_dq_alloc_space_nodirty(inode, | |
695 | + ocfs2_clusters_to_bytes(osb->sb, 1))) { | |
696 | + status = -EDQUOT; | |
697 | + goto bail; | |
698 | + } | |
699 | + did_quota = 1; | |
700 | status = ocfs2_add_inode_data(osb, inode, &offset, 1, 0, | |
701 | new_fe_bh, | |
702 | handle, data_ac, NULL, | |
703 | @@ -1736,6 +1767,11 @@ static int ocfs2_symlink(struct inode *d | |
704 | dentry->d_op = &ocfs2_dentry_ops; | |
705 | d_instantiate(dentry, inode); | |
706 | bail: | |
707 | + if (status < 0 && did_quota) | |
708 | + vfs_dq_free_space_nodirty(inode, | |
709 | + ocfs2_clusters_to_bytes(osb->sb, 1)); | |
710 | + if (status < 0 && did_quota_inode) | |
711 | + vfs_dq_free_inode(inode); | |
712 | if (handle) | |
713 | ocfs2_commit_trans(osb, handle); | |
714 | ||
82094b55 AF |
715 | --- a/fs/ocfs2/xattr.c |
716 | +++ b/fs/ocfs2/xattr.c | |
2cb7cef9 BS |
717 | @@ -1613,7 +1613,7 @@ static int ocfs2_remove_value_outside(st |
718 | ||
719 | ocfs2_init_dealloc_ctxt(&ctxt.dealloc); | |
720 | ||
721 | - ctxt.handle = ocfs2_start_trans(osb, OCFS2_REMOVE_EXTENT_CREDITS); | |
722 | + ctxt.handle = ocfs2_start_trans(osb, ocfs2_remove_extent_credits(inode->i_sb)); | |
723 | if (IS_ERR(ctxt.handle)) { | |
724 | ret = PTR_ERR(ctxt.handle); | |
725 | mlog_errno(ret); | |
726 | @@ -2190,7 +2190,7 @@ static int ocfs2_calc_xattr_set_need(str | |
727 | */ | |
728 | if (!xi->value) { | |
729 | if (!ocfs2_xattr_is_local(xe)) | |
730 | - credits += OCFS2_REMOVE_EXTENT_CREDITS; | |
731 | + credits += ocfs2_remove_extent_credits(inode->i_sb); | |
732 | ||
733 | goto out; | |
734 | } | |
735 | @@ -2207,7 +2207,7 @@ static int ocfs2_calc_xattr_set_need(str | |
736 | */ | |
737 | if (ocfs2_xattr_can_be_in_inode(inode, xi, xis)) { | |
738 | clusters_add += new_clusters; | |
739 | - credits += OCFS2_REMOVE_EXTENT_CREDITS + | |
740 | + credits += ocfs2_remove_extent_credits(inode->i_sb) + | |
741 | OCFS2_INODE_UPDATE_CREDITS; | |
742 | if (!ocfs2_xattr_is_local(xe)) | |
743 | credits += ocfs2_calc_extend_credits( | |
744 | @@ -2231,7 +2231,7 @@ static int ocfs2_calc_xattr_set_need(str | |
745 | xv = &def_xv.xv; | |
746 | ||
747 | if (old_clusters >= new_clusters) { | |
748 | - credits += OCFS2_REMOVE_EXTENT_CREDITS; | |
749 | + credits += ocfs2_remove_extent_credits(inode->i_sb); | |
750 | goto out; | |
751 | } else { | |
752 | meta_add += ocfs2_extend_meta_needed(&xv->xr_list); | |
753 | @@ -4700,7 +4700,7 @@ static int ocfs2_rm_xattr_cluster(struct | |
754 | } | |
755 | } | |
756 | ||
757 | - handle = ocfs2_start_trans(osb, OCFS2_REMOVE_EXTENT_CREDITS); | |
758 | + handle = ocfs2_start_trans(osb, ocfs2_remove_extent_credits(inode->i_sb)); | |
759 | if (IS_ERR(handle)) { | |
760 | ret = -ENOMEM; | |
761 | mlog_errno(ret); | |
762 | @@ -5059,7 +5059,7 @@ static int ocfs2_delete_xattr_in_bucket( | |
763 | ||
764 | ocfs2_init_dealloc_ctxt(&ctxt.dealloc); | |
765 | ||
766 | - ctxt.handle = ocfs2_start_trans(osb, OCFS2_REMOVE_EXTENT_CREDITS); | |
767 | + ctxt.handle = ocfs2_start_trans(osb, ocfs2_remove_extent_credits(inode->i_sb)); | |
768 | if (IS_ERR(ctxt.handle)) { | |
769 | ret = PTR_ERR(ctxt.handle); | |
770 | mlog_errno(ret); |