]> git.proxmox.com Git - mirror_ubuntu-focal-kernel.git/blame - fs/ocfs2/quota_global.c
ocfs2: Add quota calls for allocation and freeing of inodes and space
[mirror_ubuntu-focal-kernel.git] / fs / ocfs2 / quota_global.c
CommitLineData
9e33d69f
JK
1/*
2 * Implementation of operations over global quota file
3 */
4#include <linux/fs.h>
5#include <linux/quota.h>
6#include <linux/quotaops.h>
7#include <linux/dqblk_qtree.h>
8
9#define MLOG_MASK_PREFIX ML_QUOTA
10#include <cluster/masklog.h>
11
12#include "ocfs2_fs.h"
13#include "ocfs2.h"
14#include "alloc.h"
15#include "inode.h"
16#include "journal.h"
17#include "file.h"
18#include "sysfile.h"
19#include "dlmglue.h"
20#include "uptodate.h"
21#include "quota.h"
22
23static void ocfs2_global_disk2memdqb(struct dquot *dquot, void *dp)
24{
25 struct ocfs2_global_disk_dqblk *d = dp;
26 struct mem_dqblk *m = &dquot->dq_dqb;
27
28 /* Update from disk only entries not set by the admin */
29 if (!test_bit(DQ_LASTSET_B + QIF_ILIMITS_B, &dquot->dq_flags)) {
30 m->dqb_ihardlimit = le64_to_cpu(d->dqb_ihardlimit);
31 m->dqb_isoftlimit = le64_to_cpu(d->dqb_isoftlimit);
32 }
33 if (!test_bit(DQ_LASTSET_B + QIF_INODES_B, &dquot->dq_flags))
34 m->dqb_curinodes = le64_to_cpu(d->dqb_curinodes);
35 if (!test_bit(DQ_LASTSET_B + QIF_BLIMITS_B, &dquot->dq_flags)) {
36 m->dqb_bhardlimit = le64_to_cpu(d->dqb_bhardlimit);
37 m->dqb_bsoftlimit = le64_to_cpu(d->dqb_bsoftlimit);
38 }
39 if (!test_bit(DQ_LASTSET_B + QIF_SPACE_B, &dquot->dq_flags))
40 m->dqb_curspace = le64_to_cpu(d->dqb_curspace);
41 if (!test_bit(DQ_LASTSET_B + QIF_BTIME_B, &dquot->dq_flags))
42 m->dqb_btime = le64_to_cpu(d->dqb_btime);
43 if (!test_bit(DQ_LASTSET_B + QIF_ITIME_B, &dquot->dq_flags))
44 m->dqb_itime = le64_to_cpu(d->dqb_itime);
45 OCFS2_DQUOT(dquot)->dq_use_count = le32_to_cpu(d->dqb_use_count);
46}
47
48static void ocfs2_global_mem2diskdqb(void *dp, struct dquot *dquot)
49{
50 struct ocfs2_global_disk_dqblk *d = dp;
51 struct mem_dqblk *m = &dquot->dq_dqb;
52
53 d->dqb_id = cpu_to_le32(dquot->dq_id);
54 d->dqb_use_count = cpu_to_le32(OCFS2_DQUOT(dquot)->dq_use_count);
55 d->dqb_ihardlimit = cpu_to_le64(m->dqb_ihardlimit);
56 d->dqb_isoftlimit = cpu_to_le64(m->dqb_isoftlimit);
57 d->dqb_curinodes = cpu_to_le64(m->dqb_curinodes);
58 d->dqb_bhardlimit = cpu_to_le64(m->dqb_bhardlimit);
59 d->dqb_bsoftlimit = cpu_to_le64(m->dqb_bsoftlimit);
60 d->dqb_curspace = cpu_to_le64(m->dqb_curspace);
61 d->dqb_btime = cpu_to_le64(m->dqb_btime);
62 d->dqb_itime = cpu_to_le64(m->dqb_itime);
63}
64
65static int ocfs2_global_is_id(void *dp, struct dquot *dquot)
66{
67 struct ocfs2_global_disk_dqblk *d = dp;
68 struct ocfs2_mem_dqinfo *oinfo =
69 sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
70
71 if (qtree_entry_unused(&oinfo->dqi_gi, dp))
72 return 0;
73 return le32_to_cpu(d->dqb_id) == dquot->dq_id;
74}
75
76struct qtree_fmt_operations ocfs2_global_ops = {
77 .mem2disk_dqblk = ocfs2_global_mem2diskdqb,
78 .disk2mem_dqblk = ocfs2_global_disk2memdqb,
79 .is_id = ocfs2_global_is_id,
80};
81
82
83struct buffer_head *ocfs2_read_quota_block(struct inode *inode,
84 int block, int *err)
85{
86 struct buffer_head *tmp = NULL;
87
88 *err = ocfs2_read_virt_blocks(inode, block, 1, &tmp, 0, NULL);
89 if (*err)
90 mlog_errno(*err);
91
92 return tmp;
93}
94
95static struct buffer_head *ocfs2_get_quota_block(struct inode *inode,
96 int block, int *err)
97{
98 u64 pblock, pcount;
99 struct buffer_head *bh;
100
101 down_read(&OCFS2_I(inode)->ip_alloc_sem);
102 *err = ocfs2_extent_map_get_blocks(inode, block, &pblock, &pcount,
103 NULL);
104 up_read(&OCFS2_I(inode)->ip_alloc_sem);
105 if (*err) {
106 mlog_errno(*err);
107 return NULL;
108 }
109 bh = sb_getblk(inode->i_sb, pblock);
110 if (!bh) {
111 *err = -EIO;
112 mlog_errno(*err);
113 }
114 return bh;
115}
116
117/* Read data from global quotafile - avoid pagecache and such because we cannot
118 * afford acquiring the locks... We use quota cluster lock to serialize
119 * operations. Caller is responsible for acquiring it. */
120ssize_t ocfs2_quota_read(struct super_block *sb, int type, char *data,
121 size_t len, loff_t off)
122{
123 struct ocfs2_mem_dqinfo *oinfo = sb_dqinfo(sb, type)->dqi_priv;
124 struct inode *gqinode = oinfo->dqi_gqinode;
125 loff_t i_size = i_size_read(gqinode);
126 int offset = off & (sb->s_blocksize - 1);
127 sector_t blk = off >> sb->s_blocksize_bits;
128 int err = 0;
129 struct buffer_head *bh;
130 size_t toread, tocopy;
131
132 if (off > i_size)
133 return 0;
134 if (off + len > i_size)
135 len = i_size - off;
136 toread = len;
137 while (toread > 0) {
138 tocopy = min((size_t)(sb->s_blocksize - offset), toread);
139 bh = ocfs2_read_quota_block(gqinode, blk, &err);
140 if (!bh) {
141 mlog_errno(err);
142 return err;
143 }
144 memcpy(data, bh->b_data + offset, tocopy);
145 brelse(bh);
146 offset = 0;
147 toread -= tocopy;
148 data += tocopy;
149 blk++;
150 }
151 return len;
152}
153
154/* Write to quotafile (we know the transaction is already started and has
155 * enough credits) */
156ssize_t ocfs2_quota_write(struct super_block *sb, int type,
157 const char *data, size_t len, loff_t off)
158{
159 struct mem_dqinfo *info = sb_dqinfo(sb, type);
160 struct ocfs2_mem_dqinfo *oinfo = info->dqi_priv;
161 struct inode *gqinode = oinfo->dqi_gqinode;
162 int offset = off & (sb->s_blocksize - 1);
163 sector_t blk = off >> sb->s_blocksize_bits;
164 int err = 0, new = 0;
165 struct buffer_head *bh;
166 handle_t *handle = journal_current_handle();
167
168 if (!handle) {
169 mlog(ML_ERROR, "Quota write (off=%llu, len=%llu) cancelled "
170 "because transaction was not started.\n",
171 (unsigned long long)off, (unsigned long long)len);
172 return -EIO;
173 }
174 if (len > sb->s_blocksize - OCFS2_QBLK_RESERVED_SPACE - offset) {
175 WARN_ON(1);
176 len = sb->s_blocksize - OCFS2_QBLK_RESERVED_SPACE - offset;
177 }
178
179 mutex_lock_nested(&gqinode->i_mutex, I_MUTEX_QUOTA);
180 if (gqinode->i_size < off + len) {
181 down_write(&OCFS2_I(gqinode)->ip_alloc_sem);
182 err = ocfs2_extend_no_holes(gqinode, off + len, off);
183 up_write(&OCFS2_I(gqinode)->ip_alloc_sem);
184 if (err < 0)
185 goto out;
186 err = ocfs2_simple_size_update(gqinode,
187 oinfo->dqi_gqi_bh,
188 off + len);
189 if (err < 0)
190 goto out;
191 new = 1;
192 }
193 /* Not rewriting whole block? */
194 if ((offset || len < sb->s_blocksize - OCFS2_QBLK_RESERVED_SPACE) &&
195 !new) {
196 bh = ocfs2_read_quota_block(gqinode, blk, &err);
197 if (!bh) {
198 mlog_errno(err);
199 return err;
200 }
201 err = ocfs2_journal_access(handle, gqinode, bh,
202 OCFS2_JOURNAL_ACCESS_WRITE);
203 } else {
204 bh = ocfs2_get_quota_block(gqinode, blk, &err);
205 if (!bh) {
206 mlog_errno(err);
207 return err;
208 }
209 err = ocfs2_journal_access(handle, gqinode, bh,
210 OCFS2_JOURNAL_ACCESS_CREATE);
211 }
212 if (err < 0) {
213 brelse(bh);
214 goto out;
215 }
216 lock_buffer(bh);
217 if (new)
218 memset(bh->b_data, 0, sb->s_blocksize);
219 memcpy(bh->b_data + offset, data, len);
220 flush_dcache_page(bh->b_page);
221 unlock_buffer(bh);
222 ocfs2_set_buffer_uptodate(gqinode, bh);
223 err = ocfs2_journal_dirty(handle, bh);
224 brelse(bh);
225 if (err < 0)
226 goto out;
227out:
228 if (err) {
229 mutex_unlock(&gqinode->i_mutex);
230 mlog_errno(err);
231 return err;
232 }
233 gqinode->i_version++;
234 ocfs2_mark_inode_dirty(handle, gqinode, oinfo->dqi_gqi_bh);
235 mutex_unlock(&gqinode->i_mutex);
236 return len;
237}
238
239int ocfs2_lock_global_qf(struct ocfs2_mem_dqinfo *oinfo, int ex)
240{
241 int status;
242 struct buffer_head *bh = NULL;
243
244 status = ocfs2_inode_lock(oinfo->dqi_gqinode, &bh, ex);
245 if (status < 0)
246 return status;
247 spin_lock(&dq_data_lock);
248 if (!oinfo->dqi_gqi_count++)
249 oinfo->dqi_gqi_bh = bh;
250 else
251 WARN_ON(bh != oinfo->dqi_gqi_bh);
252 spin_unlock(&dq_data_lock);
253 return 0;
254}
255
256void ocfs2_unlock_global_qf(struct ocfs2_mem_dqinfo *oinfo, int ex)
257{
258 ocfs2_inode_unlock(oinfo->dqi_gqinode, ex);
259 brelse(oinfo->dqi_gqi_bh);
260 spin_lock(&dq_data_lock);
261 if (!--oinfo->dqi_gqi_count)
262 oinfo->dqi_gqi_bh = NULL;
263 spin_unlock(&dq_data_lock);
264}
265
266/* Read information header from global quota file */
267int ocfs2_global_read_info(struct super_block *sb, int type)
268{
269 struct inode *gqinode = NULL;
270 unsigned int ino[MAXQUOTAS] = { USER_QUOTA_SYSTEM_INODE,
271 GROUP_QUOTA_SYSTEM_INODE };
272 struct ocfs2_global_disk_dqinfo dinfo;
273 struct mem_dqinfo *info = sb_dqinfo(sb, type);
274 struct ocfs2_mem_dqinfo *oinfo = info->dqi_priv;
275 int status;
276
277 mlog_entry_void();
278
279 /* Read global header */
280 gqinode = ocfs2_get_system_file_inode(OCFS2_SB(sb), ino[type],
281 OCFS2_INVALID_SLOT);
282 if (!gqinode) {
283 mlog(ML_ERROR, "failed to get global quota inode (type=%d)\n",
284 type);
285 status = -EINVAL;
286 goto out_err;
287 }
288 oinfo->dqi_gi.dqi_sb = sb;
289 oinfo->dqi_gi.dqi_type = type;
290 ocfs2_qinfo_lock_res_init(&oinfo->dqi_gqlock, oinfo);
291 oinfo->dqi_gi.dqi_entry_size = sizeof(struct ocfs2_global_disk_dqblk);
292 oinfo->dqi_gi.dqi_ops = &ocfs2_global_ops;
293 oinfo->dqi_gqi_bh = NULL;
294 oinfo->dqi_gqi_count = 0;
295 oinfo->dqi_gqinode = gqinode;
296 status = ocfs2_lock_global_qf(oinfo, 0);
297 if (status < 0) {
298 mlog_errno(status);
299 goto out_err;
300 }
301 status = sb->s_op->quota_read(sb, type, (char *)&dinfo,
302 sizeof(struct ocfs2_global_disk_dqinfo),
303 OCFS2_GLOBAL_INFO_OFF);
304 ocfs2_unlock_global_qf(oinfo, 0);
305 if (status != sizeof(struct ocfs2_global_disk_dqinfo)) {
306 mlog(ML_ERROR, "Cannot read global quota info (%d).\n",
307 status);
308 if (status >= 0)
309 status = -EIO;
310 mlog_errno(status);
311 goto out_err;
312 }
313 info->dqi_bgrace = le32_to_cpu(dinfo.dqi_bgrace);
314 info->dqi_igrace = le32_to_cpu(dinfo.dqi_igrace);
315 oinfo->dqi_syncms = le32_to_cpu(dinfo.dqi_syncms);
316 oinfo->dqi_gi.dqi_blocks = le32_to_cpu(dinfo.dqi_blocks);
317 oinfo->dqi_gi.dqi_free_blk = le32_to_cpu(dinfo.dqi_free_blk);
318 oinfo->dqi_gi.dqi_free_entry = le32_to_cpu(dinfo.dqi_free_entry);
319 oinfo->dqi_gi.dqi_blocksize_bits = sb->s_blocksize_bits;
320 oinfo->dqi_gi.dqi_usable_bs = sb->s_blocksize -
321 OCFS2_QBLK_RESERVED_SPACE;
322 oinfo->dqi_gi.dqi_qtree_depth = qtree_depth(&oinfo->dqi_gi);
323out_err:
324 mlog_exit(status);
325 return status;
326}
327
328/* Write information to global quota file. Expects exlusive lock on quota
329 * file inode and quota info */
330static int __ocfs2_global_write_info(struct super_block *sb, int type)
331{
332 struct mem_dqinfo *info = sb_dqinfo(sb, type);
333 struct ocfs2_mem_dqinfo *oinfo = info->dqi_priv;
334 struct ocfs2_global_disk_dqinfo dinfo;
335 ssize_t size;
336
337 spin_lock(&dq_data_lock);
338 info->dqi_flags &= ~DQF_INFO_DIRTY;
339 dinfo.dqi_bgrace = cpu_to_le32(info->dqi_bgrace);
340 dinfo.dqi_igrace = cpu_to_le32(info->dqi_igrace);
341 spin_unlock(&dq_data_lock);
342 dinfo.dqi_syncms = cpu_to_le32(oinfo->dqi_syncms);
343 dinfo.dqi_blocks = cpu_to_le32(oinfo->dqi_gi.dqi_blocks);
344 dinfo.dqi_free_blk = cpu_to_le32(oinfo->dqi_gi.dqi_free_blk);
345 dinfo.dqi_free_entry = cpu_to_le32(oinfo->dqi_gi.dqi_free_entry);
346 size = sb->s_op->quota_write(sb, type, (char *)&dinfo,
347 sizeof(struct ocfs2_global_disk_dqinfo),
348 OCFS2_GLOBAL_INFO_OFF);
349 if (size != sizeof(struct ocfs2_global_disk_dqinfo)) {
350 mlog(ML_ERROR, "Cannot write global quota info structure\n");
351 if (size >= 0)
352 size = -EIO;
353 return size;
354 }
355 return 0;
356}
357
358int ocfs2_global_write_info(struct super_block *sb, int type)
359{
360 int err;
361 struct ocfs2_mem_dqinfo *info = sb_dqinfo(sb, type)->dqi_priv;
362
363 err = ocfs2_qinfo_lock(info, 1);
364 if (err < 0)
365 return err;
366 err = __ocfs2_global_write_info(sb, type);
367 ocfs2_qinfo_unlock(info, 1);
368 return err;
369}
370
371/* Read in information from global quota file and acquire a reference to it.
372 * dquot_acquire() has already started the transaction and locked quota file */
373int ocfs2_global_read_dquot(struct dquot *dquot)
374{
375 int err, err2, ex = 0;
376 struct ocfs2_mem_dqinfo *info =
377 sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
378
379 err = ocfs2_qinfo_lock(info, 0);
380 if (err < 0)
381 goto out;
382 err = qtree_read_dquot(&info->dqi_gi, dquot);
383 if (err < 0)
384 goto out_qlock;
385 OCFS2_DQUOT(dquot)->dq_use_count++;
386 OCFS2_DQUOT(dquot)->dq_origspace = dquot->dq_dqb.dqb_curspace;
387 OCFS2_DQUOT(dquot)->dq_originodes = dquot->dq_dqb.dqb_curinodes;
388 if (!dquot->dq_off) { /* No real quota entry? */
389 /* Upgrade to exclusive lock for allocation */
390 err = ocfs2_qinfo_lock(info, 1);
391 if (err < 0)
392 goto out_qlock;
393 ex = 1;
394 }
395 err = qtree_write_dquot(&info->dqi_gi, dquot);
396 if (ex && info_dirty(sb_dqinfo(dquot->dq_sb, dquot->dq_type))) {
397 err2 = __ocfs2_global_write_info(dquot->dq_sb, dquot->dq_type);
398 if (!err)
399 err = err2;
400 }
401out_qlock:
402 if (ex)
403 ocfs2_qinfo_unlock(info, 1);
404 ocfs2_qinfo_unlock(info, 0);
405out:
406 if (err < 0)
407 mlog_errno(err);
408 return err;
409}
410
411/* Sync local information about quota modifications with global quota file.
412 * Caller must have started the transaction and obtained exclusive lock for
413 * global quota file inode */
414int __ocfs2_sync_dquot(struct dquot *dquot, int freeing)
415{
416 int err, err2;
417 struct super_block *sb = dquot->dq_sb;
418 int type = dquot->dq_type;
419 struct ocfs2_mem_dqinfo *info = sb_dqinfo(sb, type)->dqi_priv;
420 struct ocfs2_global_disk_dqblk dqblk;
421 s64 spacechange, inodechange;
422 time_t olditime, oldbtime;
423
424 err = sb->s_op->quota_read(sb, type, (char *)&dqblk,
425 sizeof(struct ocfs2_global_disk_dqblk),
426 dquot->dq_off);
427 if (err != sizeof(struct ocfs2_global_disk_dqblk)) {
428 if (err >= 0) {
429 mlog(ML_ERROR, "Short read from global quota file "
430 "(%u read)\n", err);
431 err = -EIO;
432 }
433 goto out;
434 }
435
436 /* Update space and inode usage. Get also other information from
437 * global quota file so that we don't overwrite any changes there.
438 * We are */
439 spin_lock(&dq_data_lock);
440 spacechange = dquot->dq_dqb.dqb_curspace -
441 OCFS2_DQUOT(dquot)->dq_origspace;
442 inodechange = dquot->dq_dqb.dqb_curinodes -
443 OCFS2_DQUOT(dquot)->dq_originodes;
444 olditime = dquot->dq_dqb.dqb_itime;
445 oldbtime = dquot->dq_dqb.dqb_btime;
446 ocfs2_global_disk2memdqb(dquot, &dqblk);
447 mlog(0, "Syncing global dquot %d space %lld+%lld, inodes %lld+%lld\n",
448 dquot->dq_id, dquot->dq_dqb.dqb_curspace, spacechange,
449 dquot->dq_dqb.dqb_curinodes, inodechange);
450 if (!test_bit(DQ_LASTSET_B + QIF_SPACE_B, &dquot->dq_flags))
451 dquot->dq_dqb.dqb_curspace += spacechange;
452 if (!test_bit(DQ_LASTSET_B + QIF_INODES_B, &dquot->dq_flags))
453 dquot->dq_dqb.dqb_curinodes += inodechange;
454 /* Set properly space grace time... */
455 if (dquot->dq_dqb.dqb_bsoftlimit &&
456 dquot->dq_dqb.dqb_curspace > dquot->dq_dqb.dqb_bsoftlimit) {
457 if (!test_bit(DQ_LASTSET_B + QIF_BTIME_B, &dquot->dq_flags) &&
458 oldbtime > 0) {
459 if (dquot->dq_dqb.dqb_btime > 0)
460 dquot->dq_dqb.dqb_btime =
461 min(dquot->dq_dqb.dqb_btime, oldbtime);
462 else
463 dquot->dq_dqb.dqb_btime = oldbtime;
464 }
465 } else {
466 dquot->dq_dqb.dqb_btime = 0;
467 clear_bit(DQ_BLKS_B, &dquot->dq_flags);
468 }
469 /* Set properly inode grace time... */
470 if (dquot->dq_dqb.dqb_isoftlimit &&
471 dquot->dq_dqb.dqb_curinodes > dquot->dq_dqb.dqb_isoftlimit) {
472 if (!test_bit(DQ_LASTSET_B + QIF_ITIME_B, &dquot->dq_flags) &&
473 olditime > 0) {
474 if (dquot->dq_dqb.dqb_itime > 0)
475 dquot->dq_dqb.dqb_itime =
476 min(dquot->dq_dqb.dqb_itime, olditime);
477 else
478 dquot->dq_dqb.dqb_itime = olditime;
479 }
480 } else {
481 dquot->dq_dqb.dqb_itime = 0;
482 clear_bit(DQ_INODES_B, &dquot->dq_flags);
483 }
484 /* All information is properly updated, clear the flags */
485 __clear_bit(DQ_LASTSET_B + QIF_SPACE_B, &dquot->dq_flags);
486 __clear_bit(DQ_LASTSET_B + QIF_INODES_B, &dquot->dq_flags);
487 __clear_bit(DQ_LASTSET_B + QIF_BLIMITS_B, &dquot->dq_flags);
488 __clear_bit(DQ_LASTSET_B + QIF_ILIMITS_B, &dquot->dq_flags);
489 __clear_bit(DQ_LASTSET_B + QIF_BTIME_B, &dquot->dq_flags);
490 __clear_bit(DQ_LASTSET_B + QIF_ITIME_B, &dquot->dq_flags);
491 OCFS2_DQUOT(dquot)->dq_origspace = dquot->dq_dqb.dqb_curspace;
492 OCFS2_DQUOT(dquot)->dq_originodes = dquot->dq_dqb.dqb_curinodes;
493 spin_unlock(&dq_data_lock);
494 err = ocfs2_qinfo_lock(info, freeing);
495 if (err < 0) {
496 mlog(ML_ERROR, "Failed to lock quota info, loosing quota write"
497 " (type=%d, id=%u)\n", dquot->dq_type,
498 (unsigned)dquot->dq_id);
499 goto out;
500 }
501 if (freeing)
502 OCFS2_DQUOT(dquot)->dq_use_count--;
503 err = qtree_write_dquot(&info->dqi_gi, dquot);
504 if (err < 0)
505 goto out_qlock;
506 if (freeing && !OCFS2_DQUOT(dquot)->dq_use_count) {
507 err = qtree_release_dquot(&info->dqi_gi, dquot);
508 if (info_dirty(sb_dqinfo(sb, type))) {
509 err2 = __ocfs2_global_write_info(sb, type);
510 if (!err)
511 err = err2;
512 }
513 }
514out_qlock:
515 ocfs2_qinfo_unlock(info, freeing);
516out:
517 if (err < 0)
518 mlog_errno(err);
519 return err;
520}
521
522/*
523 * Wrappers for generic quota functions
524 */
525
526static int ocfs2_write_dquot(struct dquot *dquot)
527{
528 handle_t *handle;
529 struct ocfs2_super *osb = OCFS2_SB(dquot->dq_sb);
530 int status = 0;
531
532 mlog_entry("id=%u, type=%d", dquot->dq_id, dquot->dq_type);
533
534 handle = ocfs2_start_trans(osb, OCFS2_QWRITE_CREDITS);
535 if (IS_ERR(handle)) {
536 status = PTR_ERR(handle);
537 mlog_errno(status);
538 goto out;
539 }
540 status = dquot_commit(dquot);
541 ocfs2_commit_trans(osb, handle);
542out:
543 mlog_exit(status);
544 return status;
545}
546
547int ocfs2_calc_qdel_credits(struct super_block *sb, int type)
548{
549 struct ocfs2_mem_dqinfo *oinfo;
550 int features[MAXQUOTAS] = { OCFS2_FEATURE_RO_COMPAT_USRQUOTA,
551 OCFS2_FEATURE_RO_COMPAT_GRPQUOTA };
552
553 if (!OCFS2_HAS_RO_COMPAT_FEATURE(sb, features[type]))
554 return 0;
555
556 oinfo = sb_dqinfo(sb, type)->dqi_priv;
557 /* We modify tree, leaf block, global info, local chunk header,
558 * global and local inode */
559 return oinfo->dqi_gi.dqi_qtree_depth + 2 + 1 +
560 2 * OCFS2_INODE_UPDATE_CREDITS;
561}
562
563static int ocfs2_release_dquot(struct dquot *dquot)
564{
565 handle_t *handle;
566 struct ocfs2_mem_dqinfo *oinfo =
567 sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
568 struct ocfs2_super *osb = OCFS2_SB(dquot->dq_sb);
569 int status = 0;
570
571 mlog_entry("id=%u, type=%d", dquot->dq_id, dquot->dq_type);
572
573 status = ocfs2_lock_global_qf(oinfo, 1);
574 if (status < 0)
575 goto out;
576 handle = ocfs2_start_trans(osb,
577 ocfs2_calc_qdel_credits(dquot->dq_sb, dquot->dq_type));
578 if (IS_ERR(handle)) {
579 status = PTR_ERR(handle);
580 mlog_errno(status);
581 goto out_ilock;
582 }
583 status = dquot_release(dquot);
584 ocfs2_commit_trans(osb, handle);
585out_ilock:
586 ocfs2_unlock_global_qf(oinfo, 1);
587out:
588 mlog_exit(status);
589 return status;
590}
591
592int ocfs2_calc_qinit_credits(struct super_block *sb, int type)
593{
594 struct ocfs2_mem_dqinfo *oinfo;
595 int features[MAXQUOTAS] = { OCFS2_FEATURE_RO_COMPAT_USRQUOTA,
596 OCFS2_FEATURE_RO_COMPAT_GRPQUOTA };
597 struct ocfs2_dinode *lfe, *gfe;
598
599 if (!OCFS2_HAS_RO_COMPAT_FEATURE(sb, features[type]))
600 return 0;
601
602 oinfo = sb_dqinfo(sb, type)->dqi_priv;
603 gfe = (struct ocfs2_dinode *)oinfo->dqi_gqi_bh->b_data;
604 lfe = (struct ocfs2_dinode *)oinfo->dqi_lqi_bh->b_data;
605 /* We can extend local file + global file. In local file we
606 * can modify info, chunk header block and dquot block. In
607 * global file we can modify info, tree and leaf block */
608 return ocfs2_calc_extend_credits(sb, &lfe->id2.i_list, 0) +
609 ocfs2_calc_extend_credits(sb, &gfe->id2.i_list, 0) +
610 3 + oinfo->dqi_gi.dqi_qtree_depth + 2;
611}
612
613static int ocfs2_acquire_dquot(struct dquot *dquot)
614{
615 handle_t *handle;
616 struct ocfs2_mem_dqinfo *oinfo =
617 sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
618 struct ocfs2_super *osb = OCFS2_SB(dquot->dq_sb);
619 int status = 0;
620
621 mlog_entry("id=%u, type=%d", dquot->dq_id, dquot->dq_type);
622 /* We need an exclusive lock, because we're going to update use count
623 * and instantiate possibly new dquot structure */
624 status = ocfs2_lock_global_qf(oinfo, 1);
625 if (status < 0)
626 goto out;
627 handle = ocfs2_start_trans(osb,
628 ocfs2_calc_qinit_credits(dquot->dq_sb, dquot->dq_type));
629 if (IS_ERR(handle)) {
630 status = PTR_ERR(handle);
631 mlog_errno(status);
632 goto out_ilock;
633 }
634 status = dquot_acquire(dquot);
635 ocfs2_commit_trans(osb, handle);
636out_ilock:
637 ocfs2_unlock_global_qf(oinfo, 1);
638out:
639 mlog_exit(status);
640 return status;
641}
642
643static int ocfs2_mark_dquot_dirty(struct dquot *dquot)
644{
645 unsigned long mask = (1 << (DQ_LASTSET_B + QIF_ILIMITS_B)) |
646 (1 << (DQ_LASTSET_B + QIF_BLIMITS_B)) |
647 (1 << (DQ_LASTSET_B + QIF_INODES_B)) |
648 (1 << (DQ_LASTSET_B + QIF_SPACE_B)) |
649 (1 << (DQ_LASTSET_B + QIF_BTIME_B)) |
650 (1 << (DQ_LASTSET_B + QIF_ITIME_B));
651 int sync = 0;
652 int status;
653 struct super_block *sb = dquot->dq_sb;
654 int type = dquot->dq_type;
655 struct ocfs2_mem_dqinfo *oinfo = sb_dqinfo(sb, type)->dqi_priv;
656 handle_t *handle;
657 struct ocfs2_super *osb = OCFS2_SB(sb);
658
659 mlog_entry("id=%u, type=%d", dquot->dq_id, type);
660 dquot_mark_dquot_dirty(dquot);
661
662 /* In case user set some limits, sync dquot immediately to global
663 * quota file so that information propagates quicker */
664 spin_lock(&dq_data_lock);
665 if (dquot->dq_flags & mask)
666 sync = 1;
667 spin_unlock(&dq_data_lock);
668 if (!sync) {
669 status = ocfs2_write_dquot(dquot);
670 goto out;
671 }
672 status = ocfs2_lock_global_qf(oinfo, 1);
673 if (status < 0)
674 goto out;
675 handle = ocfs2_start_trans(osb, OCFS2_QSYNC_CREDITS);
676 if (IS_ERR(handle)) {
677 status = PTR_ERR(handle);
678 mlog_errno(status);
679 goto out_ilock;
680 }
681 status = ocfs2_sync_dquot(dquot);
682 if (status < 0) {
683 mlog_errno(status);
684 goto out_trans;
685 }
686 /* Now write updated local dquot structure */
687 status = dquot_commit(dquot);
688out_trans:
689 ocfs2_commit_trans(osb, handle);
690out_ilock:
691 ocfs2_unlock_global_qf(oinfo, 1);
692out:
693 mlog_exit(status);
694 return status;
695}
696
697/* This should happen only after set_dqinfo(). */
698static int ocfs2_write_info(struct super_block *sb, int type)
699{
700 handle_t *handle;
701 int status = 0;
702 struct ocfs2_mem_dqinfo *oinfo = sb_dqinfo(sb, type)->dqi_priv;
703
704 mlog_entry_void();
705
706 status = ocfs2_lock_global_qf(oinfo, 1);
707 if (status < 0)
708 goto out;
709 handle = ocfs2_start_trans(OCFS2_SB(sb), OCFS2_QINFO_WRITE_CREDITS);
710 if (IS_ERR(handle)) {
711 status = PTR_ERR(handle);
712 mlog_errno(status);
713 goto out_ilock;
714 }
715 status = dquot_commit_info(sb, type);
716 ocfs2_commit_trans(OCFS2_SB(sb), handle);
717out_ilock:
718 ocfs2_unlock_global_qf(oinfo, 1);
719out:
720 mlog_exit(status);
721 return status;
722}
723
724/* This is difficult. We have to lock quota inode and start transaction
725 * in this function but we don't want to take the penalty of exlusive
726 * quota file lock when we are just going to use cached structures. So
727 * we just take read lock check whether we have dquot cached and if so,
728 * we don't have to take the write lock... */
729static int ocfs2_dquot_initialize(struct inode *inode, int type)
730{
731 handle_t *handle = NULL;
732 int status = 0;
733 struct super_block *sb = inode->i_sb;
734 struct ocfs2_mem_dqinfo *oinfo;
735 int exclusive = 0;
736 int cnt;
737 qid_t id;
738
739 mlog_entry_void();
740
741 for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
742 if (type != -1 && cnt != type)
743 continue;
744 if (!sb_has_quota_active(sb, cnt))
745 continue;
746 oinfo = sb_dqinfo(sb, cnt)->dqi_priv;
747 status = ocfs2_lock_global_qf(oinfo, 0);
748 if (status < 0)
749 goto out;
750 /* This is just a performance optimization not a reliable test.
751 * Since we hold an inode lock, noone can actually release
752 * the structure until we are finished with initialization. */
753 if (inode->i_dquot[cnt] != NODQUOT) {
754 ocfs2_unlock_global_qf(oinfo, 0);
755 continue;
756 }
757 /* When we have inode lock, we know that no dquot_release() can
758 * run and thus we can safely check whether we need to
759 * read+modify global file to get quota information or whether
760 * our node already has it. */
761 if (cnt == USRQUOTA)
762 id = inode->i_uid;
763 else if (cnt == GRPQUOTA)
764 id = inode->i_gid;
765 else
766 BUG();
767 /* Obtain exclusion from quota off... */
768 down_write(&sb_dqopt(sb)->dqptr_sem);
769 exclusive = !dquot_is_cached(sb, id, cnt);
770 up_write(&sb_dqopt(sb)->dqptr_sem);
771 if (exclusive) {
772 status = ocfs2_lock_global_qf(oinfo, 1);
773 if (status < 0) {
774 exclusive = 0;
775 mlog_errno(status);
776 goto out_ilock;
777 }
778 handle = ocfs2_start_trans(OCFS2_SB(sb),
779 ocfs2_calc_qinit_credits(sb, cnt));
780 if (IS_ERR(handle)) {
781 status = PTR_ERR(handle);
782 mlog_errno(status);
783 goto out_ilock;
784 }
785 }
786 dquot_initialize(inode, cnt);
787 if (exclusive) {
788 ocfs2_commit_trans(OCFS2_SB(sb), handle);
789 ocfs2_unlock_global_qf(oinfo, 1);
790 }
791 ocfs2_unlock_global_qf(oinfo, 0);
792 }
793 mlog_exit(0);
794 return 0;
795out_ilock:
796 if (exclusive)
797 ocfs2_unlock_global_qf(oinfo, 1);
798 ocfs2_unlock_global_qf(oinfo, 0);
799out:
800 mlog_exit(status);
801 return status;
802}
803
804static int ocfs2_dquot_drop_slow(struct inode *inode)
805{
806 int status;
807 int cnt;
808 int got_lock[MAXQUOTAS] = {0, 0};
809 handle_t *handle;
810 struct super_block *sb = inode->i_sb;
811 struct ocfs2_mem_dqinfo *oinfo;
812
813 for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
814 if (!sb_has_quota_active(sb, cnt))
815 continue;
816 oinfo = sb_dqinfo(sb, cnt)->dqi_priv;
817 status = ocfs2_lock_global_qf(oinfo, 1);
818 if (status < 0)
819 goto out;
820 got_lock[cnt] = 1;
821 }
822 handle = ocfs2_start_trans(OCFS2_SB(sb),
823 ocfs2_calc_qinit_credits(sb, USRQUOTA) +
824 ocfs2_calc_qinit_credits(sb, GRPQUOTA));
825 if (IS_ERR(handle)) {
826 status = PTR_ERR(handle);
827 mlog_errno(status);
828 goto out;
829 }
830 dquot_drop(inode);
831 ocfs2_commit_trans(OCFS2_SB(sb), handle);
832out:
833 for (cnt = 0; cnt < MAXQUOTAS; cnt++)
834 if (got_lock[cnt]) {
835 oinfo = sb_dqinfo(sb, cnt)->dqi_priv;
836 ocfs2_unlock_global_qf(oinfo, 1);
837 }
838 return status;
839}
840
841/* See the comment before ocfs2_dquot_initialize. */
842static int ocfs2_dquot_drop(struct inode *inode)
843{
844 int status = 0;
845 struct super_block *sb = inode->i_sb;
846 struct ocfs2_mem_dqinfo *oinfo;
847 int exclusive = 0;
848 int cnt;
849 int got_lock[MAXQUOTAS] = {0, 0};
850
851 mlog_entry_void();
852 for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
853 if (!sb_has_quota_active(sb, cnt))
854 continue;
855 oinfo = sb_dqinfo(sb, cnt)->dqi_priv;
856 status = ocfs2_lock_global_qf(oinfo, 0);
857 if (status < 0)
858 goto out;
859 got_lock[cnt] = 1;
860 }
861 /* Lock against anyone releasing references so that when when we check
862 * we know we are not going to be last ones to release dquot */
863 down_write(&sb_dqopt(sb)->dqptr_sem);
864 /* Urgh, this is a terrible hack :( */
865 for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
866 if (inode->i_dquot[cnt] != NODQUOT &&
867 atomic_read(&inode->i_dquot[cnt]->dq_count) > 1) {
868 exclusive = 1;
869 break;
870 }
871 }
872 if (!exclusive)
873 dquot_drop_locked(inode);
874 up_write(&sb_dqopt(sb)->dqptr_sem);
875out:
876 for (cnt = 0; cnt < MAXQUOTAS; cnt++)
877 if (got_lock[cnt]) {
878 oinfo = sb_dqinfo(sb, cnt)->dqi_priv;
879 ocfs2_unlock_global_qf(oinfo, 0);
880 }
881 /* In case we bailed out because we had to do expensive locking
882 * do it now... */
883 if (exclusive)
884 status = ocfs2_dquot_drop_slow(inode);
885 mlog_exit(status);
886 return status;
887}
888
889static struct dquot *ocfs2_alloc_dquot(struct super_block *sb, int type)
890{
891 struct ocfs2_dquot *dquot =
892 kmem_cache_zalloc(ocfs2_dquot_cachep, GFP_NOFS);
893
894 if (!dquot)
895 return NULL;
896 return &dquot->dq_dquot;
897}
898
899static void ocfs2_destroy_dquot(struct dquot *dquot)
900{
901 kmem_cache_free(ocfs2_dquot_cachep, dquot);
902}
903
904struct dquot_operations ocfs2_quota_operations = {
905 .initialize = ocfs2_dquot_initialize,
906 .drop = ocfs2_dquot_drop,
907 .alloc_space = dquot_alloc_space,
908 .alloc_inode = dquot_alloc_inode,
909 .free_space = dquot_free_space,
910 .free_inode = dquot_free_inode,
911 .transfer = dquot_transfer,
912 .write_dquot = ocfs2_write_dquot,
913 .acquire_dquot = ocfs2_acquire_dquot,
914 .release_dquot = ocfs2_release_dquot,
915 .mark_dirty = ocfs2_mark_dquot_dirty,
916 .write_info = ocfs2_write_info,
917 .alloc_dquot = ocfs2_alloc_dquot,
918 .destroy_dquot = ocfs2_destroy_dquot,
919};