]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blob - src/patches/suse-2.6.27.25/patches.suse/ocfs2-Implementation-of-local-and-global-quota-file.patch
Updated xen patches taken from suse.
[people/pmueller/ipfire-2.x.git] / src / patches / suse-2.6.27.25 / patches.suse / ocfs2-Implementation-of-local-and-global-quota-file.patch
1 From: Jan Kara <jack@suse.cz>
2 References: fate#302681
3 Subject: [PATCH 24/28] ocfs2: Implementation of local and global quota file handling
4 Patch-mainline: 2.6.29?
5
6 For each quota type each node has local quota file. In this file it stores
7 changes users have made to disk usage via this node. Once in a while this
8 information is synced to global file (and thus with other nodes) so that
9 limits enforcement at least aproximately works.
10
11 Global quota files contain all the information about usage and limits. It's
12 mostly handled by the generic VFS code (which implements a trie of structures
13 inside a quota file). We only have to provide functions to convert structures
14 from on-disk format to in-memory one. We also have to provide wrappers for
15 various quota functions starting transactions and acquiring necessary cluster
16 locks before the actual IO is really started.
17
18 Signed-off-by: Jan Kara <jack@suse.cz>
19 ---
20 fs/ocfs2/Makefile | 2 +
21 fs/ocfs2/cluster/masklog.h | 1 +
22 fs/ocfs2/dlmglue.c | 137 +++++++
23 fs/ocfs2/dlmglue.h | 17 +
24 fs/ocfs2/file.c | 6 +-
25 fs/ocfs2/file.h | 4 +
26 fs/ocfs2/journal.h | 15 +
27 fs/ocfs2/ocfs2_fs.h | 95 +++++
28 fs/ocfs2/ocfs2_lockid.h | 5 +
29 fs/ocfs2/quota.h | 94 +++++
30 fs/ocfs2/quota_global.c | 855 ++++++++++++++++++++++++++++++++++++++++++++
31 fs/ocfs2/quota_local.c | 846 +++++++++++++++++++++++++++++++++++++++++++
32 fs/ocfs2/super.c | 35 ++-
33 13 files changed, 2107 insertions(+), 5 deletions(-)
34 create mode 100644 fs/ocfs2/quota.h
35 create mode 100644 fs/ocfs2/quota_global.c
36 create mode 100644 fs/ocfs2/quota_local.c
37
38 Index: linux-2.6.27-ocfs2/fs/ocfs2/Makefile
39 ===================================================================
40 --- linux-2.6.27-ocfs2.orig/fs/ocfs2/Makefile
41 +++ linux-2.6.27-ocfs2/fs/ocfs2/Makefile
42 @@ -35,6 +35,8 @@ ocfs2-objs := \
43 sysfile.o \
44 uptodate.o \
45 ver.o \
46 + quota_local.o \
47 + quota_global.o \
48 xattr.o
49
50 ifeq ($(CONFIG_OCFS2_FS_POSIX_ACL),y)
51 Index: linux-2.6.27-ocfs2/fs/ocfs2/cluster/masklog.h
52 ===================================================================
53 --- linux-2.6.27-ocfs2.orig/fs/ocfs2/cluster/masklog.h
54 +++ linux-2.6.27-ocfs2/fs/ocfs2/cluster/masklog.h
55 @@ -113,6 +113,7 @@
56 #define ML_QUORUM 0x0000000008000000ULL /* net connection quorum */
57 #define ML_EXPORT 0x0000000010000000ULL /* ocfs2 export operations */
58 #define ML_XATTR 0x0000000020000000ULL /* ocfs2 extended attributes */
59 +#define ML_QUOTA 0x0000000040000000ULL /* ocfs2 quota operations */
60 /* bits that are infrequently given and frequently matched in the high word */
61 #define ML_ERROR 0x0000000100000000ULL /* sent to KERN_ERR */
62 #define ML_NOTICE 0x0000000200000000ULL /* setn to KERN_NOTICE */
63 Index: linux-2.6.27-ocfs2/fs/ocfs2/dlmglue.c
64 ===================================================================
65 --- linux-2.6.27-ocfs2.orig/fs/ocfs2/dlmglue.c
66 +++ linux-2.6.27-ocfs2/fs/ocfs2/dlmglue.c
67 @@ -32,6 +32,7 @@
68 #include <linux/debugfs.h>
69 #include <linux/seq_file.h>
70 #include <linux/time.h>
71 +#include <linux/quotaops.h>
72
73 #define MLOG_MASK_PREFIX ML_DLM_GLUE
74 #include <cluster/masklog.h>
75 @@ -51,6 +52,7 @@
76 #include "slot_map.h"
77 #include "super.h"
78 #include "uptodate.h"
79 +#include "quota.h"
80
81 #include "buffer_head_io.h"
82
83 @@ -68,6 +70,7 @@ struct ocfs2_mask_waiter {
84 static struct ocfs2_super *ocfs2_get_dentry_osb(struct ocfs2_lock_res *lockres);
85 static struct ocfs2_super *ocfs2_get_inode_osb(struct ocfs2_lock_res *lockres);
86 static struct ocfs2_super *ocfs2_get_file_osb(struct ocfs2_lock_res *lockres);
87 +static struct ocfs2_super *ocfs2_get_qinfo_osb(struct ocfs2_lock_res *lockres);
88
89 /*
90 * Return value from ->downconvert_worker functions.
91 @@ -102,6 +105,7 @@ static int ocfs2_dentry_convert_worker(s
92 static void ocfs2_dentry_post_unlock(struct ocfs2_super *osb,
93 struct ocfs2_lock_res *lockres);
94
95 +static void ocfs2_set_qinfo_lvb(struct ocfs2_lock_res *lockres);
96
97 #define mlog_meta_lvb(__level, __lockres) ocfs2_dump_meta_lvb_info(__level, __PRETTY_FUNCTION__, __LINE__, __lockres)
98
99 @@ -258,6 +262,12 @@ static struct ocfs2_lock_res_ops ocfs2_f
100 .flags = 0,
101 };
102
103 +static struct ocfs2_lock_res_ops ocfs2_qinfo_lops = {
104 + .set_lvb = ocfs2_set_qinfo_lvb,
105 + .get_osb = ocfs2_get_qinfo_osb,
106 + .flags = LOCK_TYPE_REQUIRES_REFRESH | LOCK_TYPE_USES_LVB,
107 +};
108 +
109 static inline int ocfs2_is_inode_lock(struct ocfs2_lock_res *lockres)
110 {
111 return lockres->l_type == OCFS2_LOCK_TYPE_META ||
112 @@ -279,6 +289,13 @@ static inline struct ocfs2_dentry_lock *
113 return (struct ocfs2_dentry_lock *)lockres->l_priv;
114 }
115
116 +static inline struct ocfs2_mem_dqinfo *ocfs2_lock_res_qinfo(struct ocfs2_lock_res *lockres)
117 +{
118 + BUG_ON(lockres->l_type != OCFS2_LOCK_TYPE_QINFO);
119 +
120 + return (struct ocfs2_mem_dqinfo *)lockres->l_priv;
121 +}
122 +
123 static inline struct ocfs2_super *ocfs2_get_lockres_osb(struct ocfs2_lock_res *lockres)
124 {
125 if (lockres->l_ops->get_osb)
126 @@ -507,6 +524,13 @@ static struct ocfs2_super *ocfs2_get_ino
127 return OCFS2_SB(inode->i_sb);
128 }
129
130 +static struct ocfs2_super *ocfs2_get_qinfo_osb(struct ocfs2_lock_res *lockres)
131 +{
132 + struct ocfs2_mem_dqinfo *info = lockres->l_priv;
133 +
134 + return OCFS2_SB(info->dqi_gi.dqi_sb);
135 +}
136 +
137 static struct ocfs2_super *ocfs2_get_file_osb(struct ocfs2_lock_res *lockres)
138 {
139 struct ocfs2_file_private *fp = lockres->l_priv;
140 @@ -609,6 +633,17 @@ void ocfs2_file_lock_res_init(struct ocf
141 lockres->l_flags |= OCFS2_LOCK_NOCACHE;
142 }
143
144 +void ocfs2_qinfo_lock_res_init(struct ocfs2_lock_res *lockres,
145 + struct ocfs2_mem_dqinfo *info)
146 +{
147 + ocfs2_lock_res_init_once(lockres);
148 + ocfs2_build_lock_name(OCFS2_LOCK_TYPE_QINFO, info->dqi_gi.dqi_type,
149 + 0, lockres->l_name);
150 + ocfs2_lock_res_init_common(OCFS2_SB(info->dqi_gi.dqi_sb), lockres,
151 + OCFS2_LOCK_TYPE_QINFO, &ocfs2_qinfo_lops,
152 + info);
153 +}
154 +
155 void ocfs2_lock_res_free(struct ocfs2_lock_res *res)
156 {
157 mlog_entry_void();
158 @@ -3449,6 +3484,108 @@ static int ocfs2_dentry_convert_worker(s
159 return UNBLOCK_CONTINUE_POST;
160 }
161
162 +static void ocfs2_set_qinfo_lvb(struct ocfs2_lock_res *lockres)
163 +{
164 + struct ocfs2_qinfo_lvb *lvb;
165 + struct ocfs2_mem_dqinfo *oinfo = ocfs2_lock_res_qinfo(lockres);
166 + struct mem_dqinfo *info = sb_dqinfo(oinfo->dqi_gi.dqi_sb,
167 + oinfo->dqi_gi.dqi_type);
168 +
169 + mlog_entry_void();
170 +
171 + lvb = (struct ocfs2_qinfo_lvb *)ocfs2_dlm_lvb(&lockres->l_lksb);
172 + lvb->lvb_version = OCFS2_LVB_VERSION;
173 + lvb->lvb_bgrace = cpu_to_be32(info->dqi_bgrace);
174 + lvb->lvb_igrace = cpu_to_be32(info->dqi_igrace);
175 + lvb->lvb_syncms = cpu_to_be32(oinfo->dqi_syncms);
176 + lvb->lvb_blocks = cpu_to_be32(oinfo->dqi_gi.dqi_blocks);
177 + lvb->lvb_free_blk = cpu_to_be32(oinfo->dqi_gi.dqi_free_blk);
178 + lvb->lvb_free_entry = cpu_to_be32(oinfo->dqi_gi.dqi_free_entry);
179 +
180 + mlog_exit_void();
181 +}
182 +
183 +void ocfs2_qinfo_unlock(struct ocfs2_mem_dqinfo *oinfo, int ex)
184 +{
185 + struct ocfs2_lock_res *lockres = &oinfo->dqi_gqlock;
186 + struct ocfs2_super *osb = OCFS2_SB(oinfo->dqi_gi.dqi_sb);
187 + int level = ex ? DLM_LOCK_EX : DLM_LOCK_PR;
188 +
189 + mlog_entry_void();
190 + if (!ocfs2_is_hard_readonly(osb) && !ocfs2_mount_local(osb))
191 + ocfs2_cluster_unlock(osb, lockres, level);
192 + mlog_exit_void();
193 +}
194 +
195 +/* Lock quota info, this function expects at least shared lock on the quota file
196 + * so that we can safely refresh quota info from disk. */
197 +int ocfs2_qinfo_lock(struct ocfs2_mem_dqinfo *oinfo, int ex)
198 +{
199 + struct mem_dqinfo *info = sb_dqinfo(oinfo->dqi_gi.dqi_sb,
200 + oinfo->dqi_gi.dqi_type);
201 + struct ocfs2_lock_res *lockres = &oinfo->dqi_gqlock;
202 + struct ocfs2_super *osb = OCFS2_SB(oinfo->dqi_gi.dqi_sb);
203 + struct ocfs2_qinfo_lvb *lvb;
204 + int level = ex ? DLM_LOCK_EX : DLM_LOCK_PR;
205 + int status = 0;
206 + struct buffer_head *bh;
207 + struct ocfs2_global_disk_dqinfo *gdinfo;
208 +
209 + mlog_entry_void();
210 +
211 + /* We'll allow faking a readonly metadata lock for
212 + * rodevices. */
213 + if (ocfs2_is_hard_readonly(osb)) {
214 + if (ex)
215 + status = -EROFS;
216 + goto bail;
217 + }
218 + if (ocfs2_mount_local(osb))
219 + goto bail;
220 +
221 + status = ocfs2_cluster_lock(osb, lockres, level, 0, 0);
222 + if (status < 0) {
223 + mlog_errno(status);
224 + goto bail;
225 + }
226 + if (!ocfs2_should_refresh_lock_res(lockres))
227 + goto bail;
228 + /* OK, we have the lock but we need to refresh the quota info */
229 + lvb = ocfs2_dlm_lvb(&lockres->l_lksb);
230 + if (lvb->lvb_version == OCFS2_LVB_VERSION) {
231 + info->dqi_bgrace = be32_to_cpu(lvb->lvb_bgrace);
232 + info->dqi_igrace = be32_to_cpu(lvb->lvb_igrace);
233 + oinfo->dqi_syncms = be32_to_cpu(lvb->lvb_syncms);
234 + oinfo->dqi_gi.dqi_blocks = be32_to_cpu(lvb->lvb_blocks);
235 + oinfo->dqi_gi.dqi_free_blk = be32_to_cpu(lvb->lvb_free_blk);
236 + oinfo->dqi_gi.dqi_free_entry =
237 + be32_to_cpu(lvb->lvb_free_entry);
238 + } else {
239 + bh = ocfs2_bread(oinfo->dqi_gqinode, 0, &status, 0);
240 + if (!bh) {
241 + ocfs2_qinfo_unlock(oinfo, ex);
242 + mlog_errno(status);
243 + goto bail_refresh;
244 + }
245 + gdinfo = (struct ocfs2_global_disk_dqinfo *)
246 + (bh->b_data + OCFS2_GLOBAL_INFO_OFF);
247 + info->dqi_bgrace = le32_to_cpu(gdinfo->dqi_bgrace);
248 + info->dqi_igrace = le32_to_cpu(gdinfo->dqi_igrace);
249 + oinfo->dqi_syncms = le32_to_cpu(gdinfo->dqi_syncms);
250 + oinfo->dqi_gi.dqi_blocks = le32_to_cpu(gdinfo->dqi_blocks);
251 + oinfo->dqi_gi.dqi_free_blk = le32_to_cpu(gdinfo->dqi_free_blk);
252 + oinfo->dqi_gi.dqi_free_entry =
253 + le32_to_cpu(gdinfo->dqi_free_entry);
254 + brelse(bh);
255 + ocfs2_track_lock_refresh(lockres);
256 + }
257 +bail_refresh:
258 + ocfs2_complete_lock_res_refresh(lockres, status);
259 +bail:
260 + mlog_exit(status);
261 + return status;
262 +}
263 +
264 /*
265 * This is the filesystem locking protocol. It provides the lock handling
266 * hooks for the underlying DLM. It has a maximum version number.
267 Index: linux-2.6.27-ocfs2/fs/ocfs2/dlmglue.h
268 ===================================================================
269 --- linux-2.6.27-ocfs2.orig/fs/ocfs2/dlmglue.h
270 +++ linux-2.6.27-ocfs2/fs/ocfs2/dlmglue.h
271 @@ -49,6 +49,17 @@ struct ocfs2_meta_lvb {
272 __be32 lvb_reserved2;
273 };
274
275 +struct ocfs2_qinfo_lvb {
276 + __u8 lvb_version;
277 + __u8 lvb_reserved[3];
278 + __be32 lvb_bgrace;
279 + __be32 lvb_igrace;
280 + __be32 lvb_syncms;
281 + __be32 lvb_blocks;
282 + __be32 lvb_free_blk;
283 + __be32 lvb_free_entry;
284 +};
285 +
286 /* ocfs2_inode_lock_full() 'arg_flags' flags */
287 /* don't wait on recovery. */
288 #define OCFS2_META_LOCK_RECOVERY (0x01)
289 @@ -69,6 +80,9 @@ void ocfs2_dentry_lock_res_init(struct o
290 struct ocfs2_file_private;
291 void ocfs2_file_lock_res_init(struct ocfs2_lock_res *lockres,
292 struct ocfs2_file_private *fp);
293 +struct ocfs2_mem_dqinfo;
294 +void ocfs2_qinfo_lock_res_init(struct ocfs2_lock_res *lockres,
295 + struct ocfs2_mem_dqinfo *info);
296 void ocfs2_lock_res_free(struct ocfs2_lock_res *res);
297 int ocfs2_create_new_inode_locks(struct inode *inode);
298 int ocfs2_drop_inode_locks(struct inode *inode);
299 @@ -103,6 +117,9 @@ int ocfs2_dentry_lock(struct dentry *den
300 void ocfs2_dentry_unlock(struct dentry *dentry, int ex);
301 int ocfs2_file_lock(struct file *file, int ex, int trylock);
302 void ocfs2_file_unlock(struct file *file);
303 +int ocfs2_qinfo_lock(struct ocfs2_mem_dqinfo *oinfo, int ex);
304 +void ocfs2_qinfo_unlock(struct ocfs2_mem_dqinfo *oinfo, int ex);
305 +
306
307 void ocfs2_mark_lockres_freeing(struct ocfs2_lock_res *lockres);
308 void ocfs2_simple_drop_lockres(struct ocfs2_super *osb,
309 Index: linux-2.6.27-ocfs2/fs/ocfs2/file.c
310 ===================================================================
311 --- linux-2.6.27-ocfs2.orig/fs/ocfs2/file.c
312 +++ linux-2.6.27-ocfs2/fs/ocfs2/file.c
313 @@ -304,9 +304,9 @@ bail:
314 return status;
315 }
316
317 -static int ocfs2_simple_size_update(struct inode *inode,
318 - struct buffer_head *di_bh,
319 - u64 new_i_size)
320 +int ocfs2_simple_size_update(struct inode *inode,
321 + struct buffer_head *di_bh,
322 + u64 new_i_size)
323 {
324 int ret;
325 struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
326 Index: linux-2.6.27-ocfs2/fs/ocfs2/file.h
327 ===================================================================
328 --- linux-2.6.27-ocfs2.orig/fs/ocfs2/file.h
329 +++ linux-2.6.27-ocfs2/fs/ocfs2/file.h
330 @@ -51,6 +51,9 @@ int ocfs2_add_inode_data(struct ocfs2_su
331 struct ocfs2_alloc_context *data_ac,
332 struct ocfs2_alloc_context *meta_ac,
333 enum ocfs2_alloc_restarted *reason_ret);
334 +int ocfs2_simple_size_update(struct inode *inode,
335 + struct buffer_head *di_bh,
336 + u64 new_i_size);
337 int ocfs2_extend_no_holes(struct inode *inode, u64 new_i_size,
338 u64 zero_to);
339 int ocfs2_setattr(struct dentry *dentry, struct iattr *attr);
340 Index: linux-2.6.27-ocfs2/fs/ocfs2/journal.h
341 ===================================================================
342 --- linux-2.6.27-ocfs2.orig/fs/ocfs2/journal.h
343 +++ linux-2.6.27-ocfs2/fs/ocfs2/journal.h
344 @@ -357,6 +357,21 @@ int ocfs2_journal_dirty
345 + OCFS2_INODE_UPDATE_CREDITS \
346 + OCFS2_XATTR_BLOCK_UPDATE_CREDITS)
347
348 +/* global quotafile inode update, data block */
349 +#define OCFS2_QINFO_WRITE_CREDITS (OCFS2_INODE_UPDATE_CREDITS + 1)
350 +
351 +/*
352 + * The two writes below can accidentally see global info dirty due
353 + * to set_info() quotactl so make them prepared for the writes.
354 + */
355 +/* quota data block, global info */
356 +/* Write to local quota file */
357 +#define OCFS2_QWRITE_CREDITS (OCFS2_QINFO_WRITE_CREDITS + 1)
358 +
359 +/* global quota data block, local quota data block, global quota inode,
360 + * global quota info */
361 +#define OCFS2_QSYNC_CREDITS (OCFS2_INODE_UPDATE_CREDITS + 3)
362 +
363 /*
364 * Please note that the caller must make sure that root_el is the root
365 * of extent tree. So for an inode, it should be &fe->id2.i_list. Otherwise
366 Index: linux-2.6.27-ocfs2/fs/ocfs2/ocfs2_fs.h
367 ===================================================================
368 --- linux-2.6.27-ocfs2.orig/fs/ocfs2/ocfs2_fs.h
369 +++ linux-2.6.27-ocfs2/fs/ocfs2/ocfs2_fs.h
370 @@ -859,6 +859,101 @@ struct ocfs2_xattr_block {
371 } xb_attrs;
372 };
373
374 +/*
375 + * On disk structures for global quota file
376 + */
377 +
378 +/* Magic numbers and known versions for global quota files */
379 +#define OCFS2_GLOBAL_QMAGICS {\
380 + 0x0cf52470, /* USRQUOTA */ \
381 + 0x0cf52471 /* GRPQUOTA */ \
382 +}
383 +
384 +#define OCFS2_GLOBAL_QVERSIONS {\
385 + 0, \
386 + 0, \
387 +}
388 +
389 +/* Generic header of all quota files */
390 +struct ocfs2_disk_dqheader {
391 + __le32 dqh_magic; /* Magic number identifying file */
392 + __le32 dqh_version; /* Quota format version */
393 +};
394 +
395 +#define OCFS2_GLOBAL_INFO_OFF (sizeof(struct ocfs2_disk_dqheader))
396 +
397 +/* Information header of global quota file (immediately follows the generic
398 + * header) */
399 +struct ocfs2_global_disk_dqinfo {
400 +/*00*/ __le32 dqi_bgrace;
401 + __le32 dqi_igrace;
402 + __le32 dqi_syncms;
403 + __le32 dqi_blocks;
404 +/*10*/ __le32 dqi_free_blk;
405 + __le32 dqi_free_entry;
406 +};
407 +
408 +/* Structure with global user / group information. We reserve some space
409 + * for future use. */
410 +struct ocfs2_global_disk_dqblk {
411 +/*00*/ __le32 dqb_id; /* ID the structure belongs to */
412 + __le32 dqb_use_count; /* Number of nodes having reference to this structure */
413 + __le64 dqb_ihardlimit; /* absolute limit on allocated inodes */
414 +/*10*/ __le64 dqb_isoftlimit; /* preferred inode limit */
415 + __le64 dqb_curinodes; /* current # allocated inodes */
416 +/*20*/ __le64 dqb_bhardlimit; /* absolute limit on disk space */
417 + __le64 dqb_bsoftlimit; /* preferred limit on disk space */
418 +/*30*/ __le64 dqb_curspace; /* current space occupied */
419 + __le64 dqb_btime; /* time limit for excessive disk use */
420 +/*40*/ __le64 dqb_itime; /* time limit for excessive inode use */
421 + __le64 dqb_pad1;
422 +/*50*/ __le64 dqb_pad2;
423 +};
424 +
425 +/*
426 + * On-disk structures for local quota file
427 + */
428 +
429 +/* Magic numbers and known versions for local quota files */
430 +#define OCFS2_LOCAL_QMAGICS {\
431 + 0x0cf524c0, /* USRQUOTA */ \
432 + 0x0cf524c1 /* GRPQUOTA */ \
433 +}
434 +
435 +#define OCFS2_LOCAL_QVERSIONS {\
436 + 0, \
437 + 0, \
438 +}
439 +
440 +/* Quota flags in dqinfo header */
441 +#define OLQF_CLEAN 0x0001 /* Quota file is empty (this should be after\
442 + * quota has been cleanly turned off) */
443 +
444 +#define OCFS2_LOCAL_INFO_OFF (sizeof(struct ocfs2_disk_dqheader))
445 +
446 +/* Information header of local quota file (immediately follows the generic
447 + * header) */
448 +struct ocfs2_local_disk_dqinfo {
449 + __le32 dqi_flags; /* Flags for quota file */
450 + __le32 dqi_chunks; /* Number of chunks of quota structures
451 + * with a bitmap */
452 + __le32 dqi_blocks; /* Number of blocks allocated for quota file */
453 +};
454 +
455 +/* Header of one chunk of a quota file */
456 +struct ocfs2_local_disk_chunk {
457 + __le32 dqc_free; /* Number of free entries in the bitmap */
458 + u8 dqc_bitmap[0]; /* Bitmap of entries in the corresponding
459 + * chunk of quota file */
460 +};
461 +
462 +/* One entry in local quota file */
463 +struct ocfs2_local_disk_dqblk {
464 +/*00*/ __le64 dqb_id; /* id this quota applies to */
465 + __le64 dqb_spacemod; /* Change in the amount of used space */
466 +/*10*/ __le64 dqb_inodemod; /* Change in the amount of used inodes */
467 +};
468 +
469 #define OCFS2_XATTR_ENTRY_LOCAL 0x80
470 #define OCFS2_XATTR_TYPE_MASK 0x7F
471 static inline void ocfs2_xattr_set_local(struct ocfs2_xattr_entry *xe,
472 Index: linux-2.6.27-ocfs2/fs/ocfs2/ocfs2_lockid.h
473 ===================================================================
474 --- linux-2.6.27-ocfs2.orig/fs/ocfs2/ocfs2_lockid.h
475 +++ linux-2.6.27-ocfs2/fs/ocfs2/ocfs2_lockid.h
476 @@ -46,6 +46,7 @@ enum ocfs2_lock_type {
477 OCFS2_LOCK_TYPE_DENTRY,
478 OCFS2_LOCK_TYPE_OPEN,
479 OCFS2_LOCK_TYPE_FLOCK,
480 + OCFS2_LOCK_TYPE_QINFO,
481 OCFS2_NUM_LOCK_TYPES
482 };
483
484 @@ -77,6 +78,9 @@ static inline char ocfs2_lock_type_char(
485 case OCFS2_LOCK_TYPE_FLOCK:
486 c = 'F';
487 break;
488 + case OCFS2_LOCK_TYPE_QINFO:
489 + c = 'Q';
490 + break;
491 default:
492 c = '\0';
493 }
494 @@ -95,6 +99,7 @@ static char *ocfs2_lock_type_strings[] =
495 [OCFS2_LOCK_TYPE_DENTRY] = "Dentry",
496 [OCFS2_LOCK_TYPE_OPEN] = "Open",
497 [OCFS2_LOCK_TYPE_FLOCK] = "Flock",
498 + [OCFS2_LOCK_TYPE_QINFO] = "Quota",
499 };
500
501 static inline const char *ocfs2_lock_type_string(enum ocfs2_lock_type type)
502 Index: linux-2.6.27-ocfs2/fs/ocfs2/quota.h
503 ===================================================================
504 --- /dev/null
505 +++ linux-2.6.27-ocfs2/fs/ocfs2/quota.h
506 @@ -0,0 +1,97 @@
507 +/*
508 + * quota.h for OCFS2
509 + *
510 + * On disk quota structures for local and global quota file, in-memory
511 + * structures.
512 + *
513 + */
514 +
515 +#ifndef _OCFS2_QUOTA_H
516 +#define _OCFS2_QUOTA_H
517 +
518 +#include <linux/types.h>
519 +#include <linux/slab.h>
520 +#include <linux/quota.h>
521 +#include <linux/list.h>
522 +#include <linux/dqblk_qtree.h>
523 +
524 +#include "ocfs2.h"
525 +
526 +/* Common stuff */
527 +/* id number of quota format */
528 +#define QFMT_OCFS2 3
529 +
530 +/* How many bytes to we reserve in each quota file block for our internal
531 + * purposes? E.g. checksums... */
532 +#define OCFS2_QBLK_RESERVED_SPACE 8
533 +
534 +/*
535 + * In-memory structures
536 + */
537 +struct ocfs2_dquot {
538 + struct dquot dq_dquot; /* Generic VFS dquot */
539 + loff_t dq_local_off; /* Offset in the local quota file */
540 + struct ocfs2_quota_chunk *dq_chunk; /* Chunk dquot is in */
541 + unsigned int dq_use_count; /* Number of nodes having reference to this entry in global quota file */
542 + s64 dq_origspace; /* Last globally synced space usage */
543 + s64 dq_originodes; /* Last globally synced inode usage */
544 +};
545 +
546 +/* In-memory structure with quota header information */
547 +struct ocfs2_mem_dqinfo {
548 + unsigned int dqi_type; /* Quota type this structure describes */
549 + unsigned int dqi_chunks; /* Number of chunks in local quota file */
550 + unsigned int dqi_blocks; /* Number of blocks allocated for local quota file */
551 + unsigned int dqi_syncms; /* How often should we sync with other nodes */
552 + struct list_head dqi_chunk; /* List of chunks */
553 + struct inode *dqi_gqinode; /* Global quota file inode */
554 + struct ocfs2_lock_res dqi_gqlock; /* Lock protecting quota information structure */
555 + struct buffer_head *dqi_gqi_bh; /* Buffer head with global quota file inode - set only if inode lock is obtained */
556 + int dqi_gqi_count; /* Number of holders of dqi_gqi_bh */
557 + struct buffer_head *dqi_lqi_bh; /* Buffer head with local quota file inode */
558 + struct buffer_head *dqi_ibh; /* Buffer with information header */
559 + struct qtree_mem_dqinfo dqi_gi; /* Info about global file */
560 +};
561 +
562 +static inline struct ocfs2_dquot *OCFS2_DQUOT(struct dquot *dquot)
563 +{
564 + return container_of(dquot, struct ocfs2_dquot, dq_dquot);
565 +}
566 +
567 +struct ocfs2_quota_chunk {
568 + struct list_head qc_chunk; /* List of quotafile chunks */
569 + int qc_num; /* Number of quota chunk */
570 + struct buffer_head *qc_headerbh; /* Buffer head with chunk header */
571 +};
572 +
573 +extern struct kmem_cache *ocfs2_dquot_cachep;
574 +extern struct kmem_cache *ocfs2_qf_chunk_cachep;
575 +
576 +extern struct qtree_fmt_operations ocfs2_global_ops;
577 +
578 +ssize_t ocfs2_quota_read(struct super_block *sb, int type, char *data,
579 + size_t len, loff_t off);
580 +ssize_t ocfs2_quota_write(struct super_block *sb, int type,
581 + const char *data, size_t len, loff_t off);
582 +int ocfs2_global_read_info(struct super_block *sb, int type);
583 +int ocfs2_global_write_info(struct super_block *sb, int type);
584 +int ocfs2_global_read_dquot(struct dquot *dquot);
585 +int __ocfs2_sync_dquot(struct dquot *dquot, int freeing);
586 +static inline int ocfs2_sync_dquot(struct dquot *dquot)
587 +{
588 + return __ocfs2_sync_dquot(dquot, 0);
589 +}
590 +static inline int ocfs2_global_release_dquot(struct dquot *dquot)
591 +{
592 + return __ocfs2_sync_dquot(dquot, 1);
593 +}
594 +
595 +int ocfs2_lock_global_qf(struct ocfs2_mem_dqinfo *oinfo, int ex);
596 +void ocfs2_unlock_global_qf(struct ocfs2_mem_dqinfo *oinfo, int ex);
597 +
598 +int init_ocfs2_quota_format(void);
599 +void exit_ocfs2_quota_format(void);
600 +
601 +extern struct dquot_operations ocfs2_quota_operations;
602 +
603 +#endif /* _OCFS2_QUOTA_H */
604 Index: linux-2.6.27-ocfs2/fs/ocfs2/quota_global.c
605 ===================================================================
606 --- /dev/null
607 +++ linux-2.6.27-ocfs2/fs/ocfs2/quota_global.c
608 @@ -0,0 +1,856 @@
609 +/*
610 + * Implementation of operations over global quota file
611 + */
612 +#include <linux/fs.h>
613 +#include <linux/quota.h>
614 +#include <linux/quotaops.h>
615 +#include <linux/dqblk_qtree.h>
616 +
617 +#define MLOG_MASK_PREFIX ML_QUOTA
618 +#include <cluster/masklog.h>
619 +
620 +#include "ocfs2_fs.h"
621 +#include "ocfs2.h"
622 +#include "alloc.h"
623 +#include "inode.h"
624 +#include "journal.h"
625 +#include "file.h"
626 +#include "sysfile.h"
627 +#include "dlmglue.h"
628 +#include "quota.h"
629 +
630 +static void ocfs2_global_disk2memdqb(struct dquot *dquot, void *dp)
631 +{
632 + struct ocfs2_global_disk_dqblk *d = dp;
633 + struct mem_dqblk *m = &dquot->dq_dqb;
634 +
635 + /* Update from disk only entries not set by the admin */
636 + if (!test_bit(DQ_LASTSET_B + QIF_ILIMITS_B, &dquot->dq_flags)) {
637 + m->dqb_ihardlimit = le64_to_cpu(d->dqb_ihardlimit);
638 + m->dqb_isoftlimit = le64_to_cpu(d->dqb_isoftlimit);
639 + }
640 + if (!test_bit(DQ_LASTSET_B + QIF_INODES_B, &dquot->dq_flags))
641 + m->dqb_curinodes = le64_to_cpu(d->dqb_curinodes);
642 + if (!test_bit(DQ_LASTSET_B + QIF_BLIMITS_B, &dquot->dq_flags)) {
643 + m->dqb_bhardlimit = le64_to_cpu(d->dqb_bhardlimit);
644 + m->dqb_bsoftlimit = le64_to_cpu(d->dqb_bsoftlimit);
645 + }
646 + if (!test_bit(DQ_LASTSET_B + QIF_SPACE_B, &dquot->dq_flags))
647 + m->dqb_curspace = le64_to_cpu(d->dqb_curspace);
648 + if (!test_bit(DQ_LASTSET_B + QIF_BTIME_B, &dquot->dq_flags))
649 + m->dqb_btime = le64_to_cpu(d->dqb_btime);
650 + if (!test_bit(DQ_LASTSET_B + QIF_ITIME_B, &dquot->dq_flags))
651 + m->dqb_itime = le64_to_cpu(d->dqb_itime);
652 + OCFS2_DQUOT(dquot)->dq_use_count = le32_to_cpu(d->dqb_use_count);
653 +}
654 +
655 +static void ocfs2_global_mem2diskdqb(void *dp, struct dquot *dquot)
656 +{
657 + struct ocfs2_global_disk_dqblk *d = dp;
658 + struct mem_dqblk *m = &dquot->dq_dqb;
659 +
660 + d->dqb_id = cpu_to_le32(dquot->dq_id);
661 + d->dqb_use_count = cpu_to_le32(OCFS2_DQUOT(dquot)->dq_use_count);
662 + d->dqb_ihardlimit = cpu_to_le64(m->dqb_ihardlimit);
663 + d->dqb_isoftlimit = cpu_to_le64(m->dqb_isoftlimit);
664 + d->dqb_curinodes = cpu_to_le64(m->dqb_curinodes);
665 + d->dqb_bhardlimit = cpu_to_le64(m->dqb_bhardlimit);
666 + d->dqb_bsoftlimit = cpu_to_le64(m->dqb_bsoftlimit);
667 + d->dqb_curspace = cpu_to_le64(m->dqb_curspace);
668 + d->dqb_btime = cpu_to_le64(m->dqb_btime);
669 + d->dqb_itime = cpu_to_le64(m->dqb_itime);
670 + d->dqb_pad1 = d->dqb_pad2 = 0;
671 +}
672 +
673 +static int ocfs2_global_is_id(void *dp, struct dquot *dquot)
674 +{
675 + struct ocfs2_global_disk_dqblk *d = dp;
676 + struct ocfs2_mem_dqinfo *oinfo =
677 + sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
678 +
679 + if (qtree_entry_unused(&oinfo->dqi_gi, dp))
680 + return 0;
681 + return le32_to_cpu(d->dqb_id) == dquot->dq_id;
682 +}
683 +
684 +struct qtree_fmt_operations ocfs2_global_ops = {
685 + .mem2disk_dqblk = ocfs2_global_mem2diskdqb,
686 + .disk2mem_dqblk = ocfs2_global_disk2memdqb,
687 + .is_id = ocfs2_global_is_id,
688 +};
689 +
690 +/* Read data from global quotafile - avoid pagecache and such because we cannot
691 + * afford acquiring the locks... We use quota cluster lock to serialize
692 + * operations. Caller is responsible for acquiring it. */
693 +ssize_t ocfs2_quota_read(struct super_block *sb, int type, char *data,
694 + size_t len, loff_t off)
695 +{
696 + struct ocfs2_mem_dqinfo *oinfo = sb_dqinfo(sb, type)->dqi_priv;
697 + struct inode *gqinode = oinfo->dqi_gqinode;
698 + loff_t i_size = i_size_read(gqinode);
699 + int offset = off & (sb->s_blocksize - 1);
700 + sector_t blk = off >> sb->s_blocksize_bits;
701 + int err = 0;
702 + struct buffer_head *bh;
703 + size_t toread, tocopy;
704 +
705 + if (off > i_size)
706 + return 0;
707 + if (off + len > i_size)
708 + len = i_size - off;
709 + toread = len;
710 + while (toread > 0) {
711 + tocopy = min(sb->s_blocksize - offset, toread);
712 + bh = ocfs2_bread(gqinode, blk, &err, 0);
713 + if (!bh) {
714 + mlog_errno(err);
715 + return err;
716 + }
717 + memcpy(data, bh->b_data + offset, tocopy);
718 + brelse(bh);
719 + offset = 0;
720 + toread -= tocopy;
721 + data += tocopy;
722 + blk++;
723 + }
724 + return len;
725 +}
726 +
727 +/* Write to quotafile (we know the transaction is already started and has
728 + * enough credits) */
729 +ssize_t ocfs2_quota_write(struct super_block *sb, int type,
730 + const char *data, size_t len, loff_t off)
731 +{
732 + struct mem_dqinfo *info = sb_dqinfo(sb, type);
733 + struct ocfs2_mem_dqinfo *oinfo = info->dqi_priv;
734 + struct inode *gqinode = oinfo->dqi_gqinode;
735 + int offset = off & (sb->s_blocksize - 1);
736 + sector_t blk = off >> sb->s_blocksize_bits;
737 + int err = 0;
738 + struct buffer_head *bh;
739 + handle_t *handle = journal_current_handle();
740 + size_t tocopy, towrite = len;
741 +
742 + if (!handle) {
743 + mlog(ML_ERROR, "Quota write (off=%llu, len=%llu) cancelled "
744 + "because transaction was not started.\n",
745 + (unsigned long long)off, (unsigned long long)len);
746 + return -EIO;
747 + }
748 + mutex_lock_nested(&gqinode->i_mutex, I_MUTEX_QUOTA);
749 + if (gqinode->i_size < off + len) {
750 + down_write(&OCFS2_I(gqinode)->ip_alloc_sem);
751 + err = ocfs2_extend_no_holes(gqinode, off + len, off);
752 + up_write(&OCFS2_I(gqinode)->ip_alloc_sem);
753 + if (err < 0)
754 + goto out;
755 + err = ocfs2_simple_size_update(gqinode,
756 + oinfo->dqi_gqi_bh,
757 + off + len);
758 + if (err < 0)
759 + goto out;
760 + }
761 + WARN_ON(off >> sb->s_blocksize_bits != \
762 + (off + len) >> sb->s_blocksize_bits);
763 + WARN_ON(((off + len) & ((1 << sb->s_blocksize_bits) - 1)) >
764 + sb->s_blocksize - OCFS2_QBLK_RESERVED_SPACE);
765 + for (towrite = len; towrite > 0; towrite -= tocopy) {
766 + tocopy = min(towrite, sb->s_blocksize - offset);
767 + bh = ocfs2_bread(gqinode, blk, &err, 0);
768 + if (!bh) {
769 + mlog_errno(err);
770 + return err;
771 + }
772 + err = ocfs2_journal_access(handle, gqinode, bh,
773 + OCFS2_JOURNAL_ACCESS_WRITE);
774 + if (err < 0) {
775 + brelse(bh);
776 + goto out;
777 + }
778 + lock_buffer(bh);
779 + memcpy(bh->b_data + offset, data, tocopy);
780 + flush_dcache_page(bh->b_page);
781 + unlock_buffer(bh);
782 + err = ocfs2_journal_dirty(handle, bh);
783 + brelse(bh);
784 + if (err < 0)
785 + goto out;
786 + offset = 0;
787 + data += tocopy;
788 + blk++;
789 + }
790 +out:
791 + /* Nothing written? */
792 + if (len == towrite) {
793 + mutex_unlock(&gqinode->i_mutex);
794 + mlog_errno(err);
795 + return err;
796 + }
797 + gqinode->i_version++;
798 + ocfs2_mark_inode_dirty(handle, gqinode, oinfo->dqi_gqi_bh);
799 + mutex_unlock(&gqinode->i_mutex);
800 + return len - towrite;
801 +}
802 +
803 +int ocfs2_lock_global_qf(struct ocfs2_mem_dqinfo *oinfo, int ex)
804 +{
805 + int status;
806 + struct buffer_head *bh = NULL;
807 +
808 + status = ocfs2_inode_lock(oinfo->dqi_gqinode, &bh, ex);
809 + if (status < 0)
810 + return status;
811 + spin_lock(&dq_data_lock);
812 + if (!oinfo->dqi_gqi_count++)
813 + oinfo->dqi_gqi_bh = bh;
814 + else
815 + WARN_ON(bh != oinfo->dqi_gqi_bh);
816 + spin_unlock(&dq_data_lock);
817 + return 0;
818 +}
819 +
820 +void ocfs2_unlock_global_qf(struct ocfs2_mem_dqinfo *oinfo, int ex)
821 +{
822 + ocfs2_inode_unlock(oinfo->dqi_gqinode, ex);
823 + brelse(oinfo->dqi_gqi_bh);
824 + spin_lock(&dq_data_lock);
825 + if (!--oinfo->dqi_gqi_count)
826 + oinfo->dqi_gqi_bh = NULL;
827 + spin_unlock(&dq_data_lock);
828 +}
829 +
830 +/* Read information header from global quota file */
831 +int ocfs2_global_read_info(struct super_block *sb, int type)
832 +{
833 + struct inode *gqinode = NULL;
834 + unsigned int ino[MAXQUOTAS] = { USER_QUOTA_SYSTEM_INODE,
835 + GROUP_QUOTA_SYSTEM_INODE };
836 + struct ocfs2_global_disk_dqinfo dinfo;
837 + struct mem_dqinfo *info = sb_dqinfo(sb, type);
838 + struct ocfs2_mem_dqinfo *oinfo = info->dqi_priv;
839 + int status;
840 +
841 + mlog_entry_void();
842 +
843 + /* Read global header */
844 + gqinode = ocfs2_get_system_file_inode(OCFS2_SB(sb), ino[type],
845 + OCFS2_INVALID_SLOT);
846 + if (!gqinode) {
847 + mlog(ML_ERROR, "failed to get global quota inode (type=%d)\n",
848 + type);
849 + status = -EINVAL;
850 + goto out_err;
851 + }
852 + oinfo->dqi_gi.dqi_sb = sb;
853 + oinfo->dqi_gi.dqi_type = type;
854 + ocfs2_qinfo_lock_res_init(&oinfo->dqi_gqlock, oinfo);
855 + oinfo->dqi_gi.dqi_entry_size = sizeof(struct ocfs2_global_disk_dqblk);
856 + oinfo->dqi_gi.dqi_ops = &ocfs2_global_ops;
857 + oinfo->dqi_gqi_bh = NULL;
858 + oinfo->dqi_gqi_count = 0;
859 + oinfo->dqi_gqinode = gqinode;
860 + status = ocfs2_lock_global_qf(oinfo, 0);
861 + if (status < 0) {
862 + mlog_errno(status);
863 + goto out_err;
864 + }
865 + status = sb->s_op->quota_read(sb, type, (char *)&dinfo,
866 + sizeof(struct ocfs2_global_disk_dqinfo),
867 + OCFS2_GLOBAL_INFO_OFF);
868 + ocfs2_unlock_global_qf(oinfo, 0);
869 + if (status != sizeof(struct ocfs2_global_disk_dqinfo)) {
870 + mlog(ML_ERROR, "Cannot read global quota info (%d).\n",
871 + status);
872 + if (status >= 0)
873 + status = -EIO;
874 + mlog_errno(status);
875 + goto out_err;
876 + }
877 + info->dqi_bgrace = le32_to_cpu(dinfo.dqi_bgrace);
878 + info->dqi_igrace = le32_to_cpu(dinfo.dqi_igrace);
879 + oinfo->dqi_syncms = le32_to_cpu(dinfo.dqi_syncms);
880 + oinfo->dqi_gi.dqi_blocks = le32_to_cpu(dinfo.dqi_blocks);
881 + oinfo->dqi_gi.dqi_free_blk = le32_to_cpu(dinfo.dqi_free_blk);
882 + oinfo->dqi_gi.dqi_free_entry = le32_to_cpu(dinfo.dqi_free_entry);
883 + oinfo->dqi_gi.dqi_blocksize_bits = sb->s_blocksize_bits;
884 + oinfo->dqi_gi.dqi_usable_bs = sb->s_blocksize -
885 + OCFS2_QBLK_RESERVED_SPACE;
886 + oinfo->dqi_gi.dqi_qtree_depth = qtree_depth(&oinfo->dqi_gi);
887 +out_err:
888 + mlog_exit(status);
889 + return status;
890 +}
891 +
892 +/* Write information to global quota file. Expects exlusive lock on quota
893 + * file inode and quota info */
894 +static int __ocfs2_global_write_info(struct super_block *sb, int type)
895 +{
896 + struct mem_dqinfo *info = sb_dqinfo(sb, type);
897 + struct ocfs2_mem_dqinfo *oinfo = info->dqi_priv;
898 + struct ocfs2_global_disk_dqinfo dinfo;
899 + ssize_t size;
900 +
901 + spin_lock(&dq_data_lock);
902 + info->dqi_flags &= ~DQF_INFO_DIRTY;
903 + dinfo.dqi_bgrace = cpu_to_le32(info->dqi_bgrace);
904 + dinfo.dqi_igrace = cpu_to_le32(info->dqi_igrace);
905 + spin_unlock(&dq_data_lock);
906 + dinfo.dqi_syncms = cpu_to_le32(oinfo->dqi_syncms);
907 + dinfo.dqi_blocks = cpu_to_le32(oinfo->dqi_gi.dqi_blocks);
908 + dinfo.dqi_free_blk = cpu_to_le32(oinfo->dqi_gi.dqi_free_blk);
909 + dinfo.dqi_free_entry = cpu_to_le32(oinfo->dqi_gi.dqi_free_entry);
910 + size = sb->s_op->quota_write(sb, type, (char *)&dinfo,
911 + sizeof(struct ocfs2_global_disk_dqinfo),
912 + OCFS2_GLOBAL_INFO_OFF);
913 + if (size != sizeof(struct ocfs2_global_disk_dqinfo)) {
914 + mlog(ML_ERROR, "Cannot write global quota info structure\n");
915 + if (size >= 0)
916 + size = -EIO;
917 + return size;
918 + }
919 + return 0;
920 +}
921 +
922 +int ocfs2_global_write_info(struct super_block *sb, int type)
923 +{
924 + int err;
925 + struct ocfs2_mem_dqinfo *info = sb_dqinfo(sb, type)->dqi_priv;
926 +
927 + err = ocfs2_qinfo_lock(info, 1);
928 + if (err < 0)
929 + return err;
930 + err = __ocfs2_global_write_info(sb, type);
931 + ocfs2_qinfo_unlock(info, 1);
932 + return err;
933 +}
934 +
935 +/* Read in information from global quota file and acquire a reference to it.
936 + * dquot_acquire() has already started the transaction and locked quota file */
937 +int ocfs2_global_read_dquot(struct dquot *dquot)
938 +{
939 + int err, err2, ex = 0;
940 + struct ocfs2_mem_dqinfo *info =
941 + sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
942 +
943 + err = ocfs2_qinfo_lock(info, 0);
944 + if (err < 0)
945 + goto out;
946 + err = qtree_read_dquot(&info->dqi_gi, dquot);
947 + if (err < 0)
948 + goto out_qlock;
949 + OCFS2_DQUOT(dquot)->dq_use_count++;
950 + OCFS2_DQUOT(dquot)->dq_origspace = dquot->dq_dqb.dqb_curspace;
951 + OCFS2_DQUOT(dquot)->dq_originodes = dquot->dq_dqb.dqb_curinodes;
952 + if (!dquot->dq_off) { /* No real quota entry? */
953 + /* Upgrade to exclusive lock for allocation */
954 + err = ocfs2_qinfo_lock(info, 1);
955 + if (err < 0)
956 + goto out_qlock;
957 + ex = 1;
958 + }
959 + err = qtree_write_dquot(&info->dqi_gi, dquot);
960 + if (ex && info_dirty(sb_dqinfo(dquot->dq_sb, dquot->dq_type))) {
961 + err2 = __ocfs2_global_write_info(dquot->dq_sb, dquot->dq_type);
962 + if (!err)
963 + err = err2;
964 + }
965 +out_qlock:
966 + if (ex)
967 + ocfs2_qinfo_unlock(info, 1);
968 + ocfs2_qinfo_unlock(info, 0);
969 +out:
970 + if (err < 0)
971 + mlog_errno(err);
972 + return err;
973 +}
974 +
975 +/* Sync local information about quota modifications with global quota file.
976 + * Caller must have started the transaction and obtained exclusive lock for
977 + * global quota file inode */
978 +int __ocfs2_sync_dquot(struct dquot *dquot, int freeing)
979 +{
980 + int err, err2;
981 + struct super_block *sb = dquot->dq_sb;
982 + int type = dquot->dq_type;
983 + struct ocfs2_mem_dqinfo *info = sb_dqinfo(sb, type)->dqi_priv;
984 + struct ocfs2_global_disk_dqblk dqblk;
985 + s64 spacechange, inodechange;
986 + time_t olditime, oldbtime;
987 +
988 + err = sb->s_op->quota_read(sb, type, (char *)&dqblk,
989 + sizeof(struct ocfs2_global_disk_dqblk),
990 + dquot->dq_off);
991 + if (err != sizeof(struct ocfs2_global_disk_dqblk)) {
992 + if (err >= 0) {
993 + mlog(ML_ERROR, "Short read from global quota file "
994 + "(%u read)\n", err);
995 + err = -EIO;
996 + }
997 + goto out;
998 + }
999 +
1000 + /* Update space and inode usage. Get also other information from
1001 + * global quota file so that we don't overwrite any changes there.
1002 + * We are */
1003 + spin_lock(&dq_data_lock);
1004 + spacechange = dquot->dq_dqb.dqb_curspace -
1005 + OCFS2_DQUOT(dquot)->dq_origspace;
1006 + inodechange = dquot->dq_dqb.dqb_curinodes -
1007 + OCFS2_DQUOT(dquot)->dq_originodes;
1008 + olditime = dquot->dq_dqb.dqb_itime;
1009 + oldbtime = dquot->dq_dqb.dqb_btime;
1010 + ocfs2_global_disk2memdqb(dquot, &dqblk);
1011 + mlog(0, "Syncing global dquot %d space %lld+%lld, inodes %lld+%lld\n",
1012 + dquot->dq_id, dquot->dq_dqb.dqb_curspace, spacechange,
1013 + dquot->dq_dqb.dqb_curinodes, inodechange);
1014 + if (!test_bit(DQ_LASTSET_B + QIF_SPACE_B, &dquot->dq_flags))
1015 + dquot->dq_dqb.dqb_curspace += spacechange;
1016 + if (!test_bit(DQ_LASTSET_B + QIF_INODES_B, &dquot->dq_flags))
1017 + dquot->dq_dqb.dqb_curinodes += inodechange;
1018 + /* Now merge grace time changes... */
1019 + if (!test_bit(DQ_LASTSET_B + QIF_BTIME_B, &dquot->dq_flags) &&
1020 + oldbtime > 0) {
1021 + if (dquot->dq_dqb.dqb_btime > 0)
1022 + dquot->dq_dqb.dqb_btime =
1023 + min(dquot->dq_dqb.dqb_btime, oldbtime);
1024 + else
1025 + dquot->dq_dqb.dqb_btime = oldbtime;
1026 + }
1027 + if (!test_bit(DQ_LASTSET_B + QIF_ITIME_B, &dquot->dq_flags) &&
1028 + olditime > 0) {
1029 + if (dquot->dq_dqb.dqb_itime > 0)
1030 + dquot->dq_dqb.dqb_itime =
1031 + min(dquot->dq_dqb.dqb_itime, olditime);
1032 + else
1033 + dquot->dq_dqb.dqb_itime = olditime;
1034 + }
1035 + /* All information is properly updated, clear the flags */
1036 + __clear_bit(DQ_LASTSET_B + QIF_SPACE_B, &dquot->dq_flags);
1037 + __clear_bit(DQ_LASTSET_B + QIF_INODES_B, &dquot->dq_flags);
1038 + __clear_bit(DQ_LASTSET_B + QIF_BLIMITS_B, &dquot->dq_flags);
1039 + __clear_bit(DQ_LASTSET_B + QIF_ILIMITS_B, &dquot->dq_flags);
1040 + __clear_bit(DQ_LASTSET_B + QIF_BTIME_B, &dquot->dq_flags);
1041 + __clear_bit(DQ_LASTSET_B + QIF_ITIME_B, &dquot->dq_flags);
1042 + OCFS2_DQUOT(dquot)->dq_origspace = dquot->dq_dqb.dqb_curspace;
1043 + OCFS2_DQUOT(dquot)->dq_originodes = dquot->dq_dqb.dqb_curinodes;
1044 + spin_unlock(&dq_data_lock);
1045 + err = ocfs2_qinfo_lock(info, freeing);
1046 + if (err < 0) {
1047 + mlog(ML_ERROR, "Failed to lock quota info, loosing quota write"
1048 + " (type=%d, id=%u)\n", dquot->dq_type,
1049 + (unsigned)dquot->dq_id);
1050 + goto out;
1051 + }
1052 + if (freeing)
1053 + OCFS2_DQUOT(dquot)->dq_use_count--;
1054 + err = qtree_write_dquot(&info->dqi_gi, dquot);
1055 + if (err < 0)
1056 + goto out_qlock;
1057 + if (freeing && !OCFS2_DQUOT(dquot)->dq_use_count) {
1058 + err = qtree_release_dquot(&info->dqi_gi, dquot);
1059 + if (info_dirty(sb_dqinfo(sb, type))) {
1060 + err2 = __ocfs2_global_write_info(sb, type);
1061 + if (!err)
1062 + err = err2;
1063 + }
1064 + }
1065 +out_qlock:
1066 + ocfs2_qinfo_unlock(info, freeing);
1067 +out:
1068 + if (err < 0)
1069 + mlog_errno(err);
1070 + return err;
1071 +}
1072 +
1073 +/*
1074 + * Wrappers for generic quota functions
1075 + */
1076 +
1077 +static int ocfs2_write_dquot(struct dquot *dquot)
1078 +{
1079 + handle_t *handle;
1080 + struct ocfs2_super *osb = OCFS2_SB(dquot->dq_sb);
1081 + int status = 0;
1082 +
1083 + mlog_entry("id=%u, type=%d", dquot->dq_id, dquot->dq_type);
1084 +
1085 + handle = ocfs2_start_trans(osb, OCFS2_QWRITE_CREDITS);
1086 + if (IS_ERR(handle)) {
1087 + status = PTR_ERR(handle);
1088 + mlog_errno(status);
1089 + goto out;
1090 + }
1091 + status = dquot_commit(dquot);
1092 + ocfs2_commit_trans(osb, handle);
1093 +out:
1094 + mlog_exit(status);
1095 + return status;
1096 +}
1097 +
1098 +int ocfs2_calc_qdel_credits(struct super_block *sb, int type)
1099 +{
1100 + struct ocfs2_mem_dqinfo *oinfo;
1101 + int features[MAXQUOTAS] = { OCFS2_FEATURE_RO_COMPAT_USRQUOTA,
1102 + OCFS2_FEATURE_RO_COMPAT_GRPQUOTA };
1103 +
1104 + if (!OCFS2_HAS_RO_COMPAT_FEATURE(sb, features[type]))
1105 + return 0;
1106 +
1107 + oinfo = sb_dqinfo(sb, type)->dqi_priv;
1108 + /* We modify tree, leaf block, global info, local chunk header,
1109 + * global and local inode */
1110 + return oinfo->dqi_gi.dqi_qtree_depth + 2 + 1 +
1111 + 2 * OCFS2_INODE_UPDATE_CREDITS;
1112 +}
1113 +
1114 +static int ocfs2_release_dquot(struct dquot *dquot)
1115 +{
1116 + handle_t *handle;
1117 + struct ocfs2_mem_dqinfo *oinfo =
1118 + sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
1119 + struct ocfs2_super *osb = OCFS2_SB(dquot->dq_sb);
1120 + int status = 0;
1121 +
1122 + mlog_entry("id=%u, type=%d", dquot->dq_id, dquot->dq_type);
1123 +
1124 + status = ocfs2_lock_global_qf(oinfo, 1);
1125 + if (status < 0)
1126 + goto out;
1127 + handle = ocfs2_start_trans(osb,
1128 + ocfs2_calc_qdel_credits(dquot->dq_sb, dquot->dq_type));
1129 + if (IS_ERR(handle)) {
1130 + status = PTR_ERR(handle);
1131 + mlog_errno(status);
1132 + goto out_ilock;
1133 + }
1134 + status = dquot_release(dquot);
1135 + ocfs2_commit_trans(osb, handle);
1136 +out_ilock:
1137 + ocfs2_unlock_global_qf(oinfo, 1);
1138 +out:
1139 + mlog_exit(status);
1140 + return status;
1141 +}
1142 +
1143 +int ocfs2_calc_qinit_credits(struct super_block *sb, int type)
1144 +{
1145 + struct ocfs2_mem_dqinfo *oinfo;
1146 + struct ocfs2_dinode *lfe, *gfe;
1147 + int features[MAXQUOTAS] = { OCFS2_FEATURE_RO_COMPAT_USRQUOTA,
1148 + OCFS2_FEATURE_RO_COMPAT_GRPQUOTA };
1149 +
1150 + if (!OCFS2_HAS_RO_COMPAT_FEATURE(sb, features[type]))
1151 + return 0;
1152 +
1153 + oinfo = sb_dqinfo(sb, type)->dqi_priv;
1154 + gfe = (struct ocfs2_dinode *)oinfo->dqi_gqi_bh->b_data;
1155 + lfe = (struct ocfs2_dinode *)oinfo->dqi_lqi_bh->b_data;
1156 + /* We can extend local file + global file. In local file we
1157 + * can modify info, chunk header block and dquot block. In
1158 + * global file we can modify info, tree and leaf block */
1159 + return ocfs2_calc_extend_credits(sb, &gfe->id2.i_list, 0) +
1160 + ocfs2_calc_extend_credits(sb, &lfe->id2.i_list, 0) +
1161 + 3 + oinfo->dqi_gi.dqi_qtree_depth + 2;
1162 +}
1163 +
1164 +static int ocfs2_acquire_dquot(struct dquot *dquot)
1165 +{
1166 + handle_t *handle;
1167 + struct ocfs2_mem_dqinfo *oinfo =
1168 + sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
1169 + struct ocfs2_super *osb = OCFS2_SB(dquot->dq_sb);
1170 + int status = 0;
1171 +
1172 + mlog_entry("id=%u, type=%d", dquot->dq_id, dquot->dq_type);
1173 + /* We need an exclusive lock, because we're going to update use count
1174 + * and instantiate possibly new dquot structure */
1175 + status = ocfs2_lock_global_qf(oinfo, 1);
1176 + if (status < 0)
1177 + goto out;
1178 + handle = ocfs2_start_trans(osb,
1179 + ocfs2_calc_qinit_credits(dquot->dq_sb, dquot->dq_type));
1180 + if (IS_ERR(handle)) {
1181 + status = PTR_ERR(handle);
1182 + mlog_errno(status);
1183 + goto out_ilock;
1184 + }
1185 + status = dquot_acquire(dquot);
1186 + ocfs2_commit_trans(osb, handle);
1187 +out_ilock:
1188 + ocfs2_unlock_global_qf(oinfo, 1);
1189 +out:
1190 + mlog_exit(status);
1191 + return status;
1192 +}
1193 +
1194 +static int ocfs2_mark_dquot_dirty(struct dquot *dquot)
1195 +{
1196 + unsigned long mask = (1 << (DQ_LASTSET_B + QIF_ILIMITS_B)) |
1197 + (1 << (DQ_LASTSET_B + QIF_BLIMITS_B)) |
1198 + (1 << (DQ_LASTSET_B + QIF_INODES_B)) |
1199 + (1 << (DQ_LASTSET_B + QIF_SPACE_B)) |
1200 + (1 << (DQ_LASTSET_B + QIF_BTIME_B)) |
1201 + (1 << (DQ_LASTSET_B + QIF_ITIME_B));
1202 + int sync = 0;
1203 + int status;
1204 + struct super_block *sb = dquot->dq_sb;
1205 + int type = dquot->dq_type;
1206 + struct ocfs2_mem_dqinfo *oinfo = sb_dqinfo(sb, type)->dqi_priv;
1207 + handle_t *handle;
1208 + struct ocfs2_super *osb = OCFS2_SB(sb);
1209 +
1210 + mlog_entry("id=%u, type=%d", dquot->dq_id, type);
1211 + dquot_mark_dquot_dirty(dquot);
1212 +
1213 + /* In case user set some limits, sync dquot immediately to global
1214 + * quota file so that information propagates quicker */
1215 + spin_lock(&dq_data_lock);
1216 + if (dquot->dq_flags & mask)
1217 + sync = 1;
1218 + spin_unlock(&dq_data_lock);
1219 + if (!sync) {
1220 + status = ocfs2_write_dquot(dquot);
1221 + goto out;
1222 + }
1223 + status = ocfs2_lock_global_qf(oinfo, 1);
1224 + if (status < 0)
1225 + goto out;
1226 + handle = ocfs2_start_trans(osb, OCFS2_QSYNC_CREDITS);
1227 + if (IS_ERR(handle)) {
1228 + status = PTR_ERR(handle);
1229 + mlog_errno(status);
1230 + goto out_ilock;
1231 + }
1232 + status = ocfs2_sync_dquot(dquot);
1233 + if (status < 0) {
1234 + mlog_errno(status);
1235 + goto out_trans;
1236 + }
1237 + /* Now write updated local dquot structure */
1238 + status = dquot_commit(dquot);
1239 +out_trans:
1240 + ocfs2_commit_trans(osb, handle);
1241 +out_ilock:
1242 + ocfs2_unlock_global_qf(oinfo, 1);
1243 +out:
1244 + mlog_exit(status);
1245 + return status;
1246 +}
1247 +
1248 +/* This should happen only after set_dqinfo(). */
1249 +static int ocfs2_write_info(struct super_block *sb, int type)
1250 +{
1251 + handle_t *handle;
1252 + int status = 0;
1253 + struct ocfs2_mem_dqinfo *oinfo = sb_dqinfo(sb, type)->dqi_priv;
1254 +
1255 + mlog_entry_void();
1256 +
1257 + status = ocfs2_lock_global_qf(oinfo, 1);
1258 + if (status < 0)
1259 + goto out;
1260 + handle = ocfs2_start_trans(OCFS2_SB(sb), OCFS2_QINFO_WRITE_CREDITS);
1261 + if (IS_ERR(handle)) {
1262 + status = PTR_ERR(handle);
1263 + mlog_errno(status);
1264 + goto out_ilock;
1265 + }
1266 + status = dquot_commit_info(sb, type);
1267 + ocfs2_commit_trans(OCFS2_SB(sb), handle);
1268 +out_ilock:
1269 + ocfs2_unlock_global_qf(oinfo, 1);
1270 +out:
1271 + mlog_exit(status);
1272 + return status;
1273 +}
1274 +
1275 +/* This is difficult. We have to lock quota inode and start transaction
1276 + * in this function but we don't want to take the penalty of exlusive
1277 + * quota file lock when we are just going to use cached structures. So
1278 + * we just take read lock check whether we have dquot cached and if so,
1279 + * we don't have to take the write lock... */
1280 +static int ocfs2_dquot_initialize(struct inode *inode, int type)
1281 +{
1282 + handle_t *handle = NULL;
1283 + int status = 0;
1284 + struct super_block *sb = inode->i_sb;
1285 + struct ocfs2_mem_dqinfo *oinfo;
1286 + int exclusive = 0;
1287 + int cnt;
1288 + qid_t id;
1289 +
1290 + mlog_entry_void();
1291 +
1292 + for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
1293 + if (type != -1 && cnt != type)
1294 + continue;
1295 + oinfo = sb_dqinfo(sb, cnt)->dqi_priv;
1296 + status = ocfs2_lock_global_qf(oinfo, 0);
1297 + if (status < 0)
1298 + goto out;
1299 + /* This is just a performance optimization not a reliable test.
1300 + * Since we hold an inode lock, noone can actually release
1301 + * the structure until we are finished with initialization. */
1302 + if (inode->i_dquot[cnt] != NODQUOT) {
1303 + ocfs2_unlock_global_qf(oinfo, 0);
1304 + continue;
1305 + }
1306 + /* When we have inode lock, we know that no dquot_release() can
1307 + * run and thus we can safely check whether we need to
1308 + * read+modify global file to get quota information or whether
1309 + * our node already has it. */
1310 + if (cnt == USRQUOTA)
1311 + id = inode->i_uid;
1312 + else if (cnt == GRPQUOTA)
1313 + id = inode->i_gid;
1314 + else
1315 + BUG();
1316 + /* Obtain exclusion from quota off... */
1317 + down_write(&sb_dqopt(sb)->dqptr_sem);
1318 + exclusive = !dquot_is_cached(sb, id, cnt);
1319 + up_write(&sb_dqopt(sb)->dqptr_sem);
1320 + if (exclusive) {
1321 + status = ocfs2_lock_global_qf(oinfo, 1);
1322 + if (status < 0) {
1323 + exclusive = 0;
1324 + mlog_errno(status);
1325 + goto out_ilock;
1326 + }
1327 + handle = ocfs2_start_trans(OCFS2_SB(sb),
1328 + ocfs2_calc_qinit_credits(sb, cnt));
1329 + if (IS_ERR(handle)) {
1330 + status = PTR_ERR(handle);
1331 + mlog_errno(status);
1332 + goto out_ilock;
1333 + }
1334 + }
1335 + dquot_initialize(inode, cnt);
1336 + if (exclusive) {
1337 + ocfs2_commit_trans(OCFS2_SB(sb), handle);
1338 + ocfs2_unlock_global_qf(oinfo, 1);
1339 + }
1340 + ocfs2_unlock_global_qf(oinfo, 0);
1341 + }
1342 + mlog_exit(0);
1343 + return 0;
1344 +out_ilock:
1345 + if (exclusive)
1346 + ocfs2_unlock_global_qf(oinfo, 1);
1347 + ocfs2_unlock_global_qf(oinfo, 0);
1348 +out:
1349 + mlog_exit(status);
1350 + return status;
1351 +}
1352 +
1353 +static int ocfs2_dquot_drop_slow(struct inode *inode)
1354 +{
1355 + int status;
1356 + int cnt;
1357 + int got_lock[MAXQUOTAS] = {0, 0};
1358 + handle_t *handle;
1359 + struct super_block *sb = inode->i_sb;
1360 + struct ocfs2_mem_dqinfo *oinfo;
1361 +
1362 + for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
1363 + oinfo = sb_dqinfo(sb, cnt)->dqi_priv;
1364 + status = ocfs2_lock_global_qf(oinfo, 1);
1365 + if (status < 0)
1366 + goto out;
1367 + got_lock[cnt] = 1;
1368 + }
1369 + handle = ocfs2_start_trans(OCFS2_SB(sb),
1370 + ocfs2_calc_qinit_credits(sb, USRQUOTA) +
1371 + ocfs2_calc_qinit_credits(sb, GRPQUOTA));
1372 + if (IS_ERR(handle)) {
1373 + status = PTR_ERR(handle);
1374 + mlog_errno(status);
1375 + goto out;
1376 + }
1377 + dquot_drop(inode);
1378 + ocfs2_commit_trans(OCFS2_SB(sb), handle);
1379 +out:
1380 + for (cnt = 0; cnt < MAXQUOTAS; cnt++)
1381 + if (got_lock[cnt]) {
1382 + oinfo = sb_dqinfo(sb, cnt)->dqi_priv;
1383 + ocfs2_unlock_global_qf(oinfo, 1);
1384 + }
1385 + return status;
1386 +}
1387 +
1388 +/* See the comment before ocfs2_dquot_initialize. */
1389 +static int ocfs2_dquot_drop(struct inode *inode)
1390 +{
1391 + int status = 0;
1392 + struct super_block *sb = inode->i_sb;
1393 + struct ocfs2_mem_dqinfo *oinfo;
1394 + int exclusive = 0;
1395 + int cnt;
1396 + int got_lock[MAXQUOTAS] = {0, 0};
1397 +
1398 + mlog_entry_void();
1399 + for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
1400 + oinfo = sb_dqinfo(sb, cnt)->dqi_priv;
1401 + status = ocfs2_lock_global_qf(oinfo, 0);
1402 + if (status < 0)
1403 + goto out;
1404 + got_lock[cnt] = 1;
1405 + }
1406 + /* Lock against anyone releasing references so that when when we check
1407 + * we know we are not going to be last ones to release dquot */
1408 + down_write(&sb_dqopt(sb)->dqptr_sem);
1409 + /* Urgh, this is a terrible hack :( */
1410 + for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
1411 + if (inode->i_dquot[cnt] != NODQUOT &&
1412 + atomic_read(&inode->i_dquot[cnt]->dq_count) > 1) {
1413 + exclusive = 1;
1414 + break;
1415 + }
1416 + }
1417 + if (!exclusive)
1418 + dquot_drop_locked(inode);
1419 + up_write(&sb_dqopt(sb)->dqptr_sem);
1420 +out:
1421 + for (cnt = 0; cnt < MAXQUOTAS; cnt++)
1422 + if (got_lock[cnt]) {
1423 + oinfo = sb_dqinfo(sb, cnt)->dqi_priv;
1424 + ocfs2_unlock_global_qf(oinfo, 0);
1425 + }
1426 + /* In case we bailed out because we had to do expensive locking
1427 + * do it now... */
1428 + if (exclusive)
1429 + status = ocfs2_dquot_drop_slow(inode);
1430 + mlog_exit(status);
1431 + return status;
1432 +}
1433 +
1434 +static struct dquot *ocfs2_alloc_dquot(struct super_block *sb, int type)
1435 +{
1436 + struct ocfs2_dquot *dquot =
1437 + kmem_cache_zalloc(ocfs2_dquot_cachep, GFP_NOFS);
1438 +
1439 + if (!dquot)
1440 + return NULL;
1441 + return &dquot->dq_dquot;
1442 +}
1443 +
1444 +static void ocfs2_destroy_dquot(struct dquot *dquot)
1445 +{
1446 + kmem_cache_free(ocfs2_dquot_cachep, dquot);
1447 +}
1448 +
1449 +struct dquot_operations ocfs2_quota_operations = {
1450 + .initialize = ocfs2_dquot_initialize,
1451 + .drop = ocfs2_dquot_drop,
1452 + .alloc_space = dquot_alloc_space,
1453 + .alloc_inode = dquot_alloc_inode,
1454 + .free_space = dquot_free_space,
1455 + .free_inode = dquot_free_inode,
1456 + .transfer = dquot_transfer,
1457 + .write_dquot = ocfs2_write_dquot,
1458 + .acquire_dquot = ocfs2_acquire_dquot,
1459 + .release_dquot = ocfs2_release_dquot,
1460 + .mark_dirty = ocfs2_mark_dquot_dirty,
1461 + .write_info = ocfs2_write_info,
1462 + .alloc_dquot = ocfs2_alloc_dquot,
1463 + .destroy_dquot = ocfs2_destroy_dquot,
1464 +};
1465 Index: linux-2.6.27-ocfs2/fs/ocfs2/quota_local.c
1466 ===================================================================
1467 --- /dev/null
1468 +++ linux-2.6.27-ocfs2/fs/ocfs2/quota_local.c
1469 @@ -0,0 +1,843 @@
1470 +/*
1471 + * Implementation of operations over local quota file
1472 + */
1473 +
1474 +#include <linux/fs.h>
1475 +#include <linux/quota.h>
1476 +#include <linux/quotaops.h>
1477 +#include <linux/module.h>
1478 +
1479 +#define MLOG_MASK_PREFIX ML_QUOTA
1480 +#include <cluster/masklog.h>
1481 +
1482 +#include "ocfs2_fs.h"
1483 +#include "ocfs2.h"
1484 +#include "inode.h"
1485 +#include "alloc.h"
1486 +#include "file.h"
1487 +#include "buffer_head_io.h"
1488 +#include "journal.h"
1489 +#include "sysfile.h"
1490 +#include "dlmglue.h"
1491 +#include "quota.h"
1492 +
1493 +/* Number of local quota structures per block */
1494 +static inline unsigned int ol_quota_entries_per_block(struct super_block *sb)
1495 +{
1496 + return ((sb->s_blocksize - OCFS2_QBLK_RESERVED_SPACE) /
1497 + sizeof(struct ocfs2_local_disk_dqblk));
1498 +}
1499 +
1500 +/* Number of blocks with entries in one chunk */
1501 +static inline unsigned int ol_chunk_blocks(struct super_block *sb)
1502 +{
1503 + return ((sb->s_blocksize - sizeof(struct ocfs2_local_disk_chunk) -
1504 + OCFS2_QBLK_RESERVED_SPACE) << 3) /
1505 + ol_quota_entries_per_block(sb);
1506 +}
1507 +
1508 +/* Number of entries in a chunk bitmap */
1509 +static unsigned int ol_chunk_entries(struct super_block *sb)
1510 +{
1511 + return ol_chunk_blocks(sb) * ol_quota_entries_per_block(sb);
1512 +}
1513 +
1514 +/* Offset of the chunk in quota file */
1515 +static unsigned int ol_quota_chunk_block(struct super_block *sb, int c)
1516 +{
1517 + /* 1 block for local quota file info, 1 block per chunk for chunk info */
1518 + return 1 + (ol_chunk_blocks(sb) + 1) * c;
1519 +}
1520 +
1521 +/* Offset of the dquot structure in the quota file */
1522 +static loff_t ol_dqblk_off(struct super_block *sb, int c, int off)
1523 +{
1524 + int epb = ol_quota_entries_per_block(sb);
1525 +
1526 + return ((ol_quota_chunk_block(sb, c) + 1 + off / epb)
1527 + << sb->s_blocksize_bits) +
1528 + (off % epb) * sizeof(struct ocfs2_local_disk_dqblk);
1529 +}
1530 +
1531 +/* Compute block number from given offset */
1532 +static inline unsigned int ol_dqblk_file_block(struct super_block *sb, loff_t off)
1533 +{
1534 + return off >> sb->s_blocksize_bits;
1535 +}
1536 +
1537 +static inline unsigned int ol_dqblk_block_offset(struct super_block *sb, loff_t off)
1538 +{
1539 + return off & ((1 << sb->s_blocksize_bits) - 1);
1540 +}
1541 +
1542 +/* Compute offset in the chunk of a structure with the given offset */
1543 +static int ol_dqblk_chunk_off(struct super_block *sb, int c, loff_t off)
1544 +{
1545 + int epb = ol_quota_entries_per_block(sb);
1546 +
1547 + return ((off >> sb->s_blocksize_bits) -
1548 + ol_quota_chunk_block(sb, c) - 1) * epb
1549 + + ((unsigned int)(off & ((1 << sb->s_blocksize_bits) - 1))) /
1550 + sizeof(struct ocfs2_local_disk_dqblk);
1551 +}
1552 +
1553 +/* Write bufferhead into the fs */
1554 +static int ocfs2_modify_bh(struct inode *inode, struct buffer_head *bh,
1555 + void (*modify)(struct buffer_head *, void *), void *private)
1556 +{
1557 + struct super_block *sb = inode->i_sb;
1558 + handle_t *handle;
1559 + int status;
1560 +
1561 + handle = ocfs2_start_trans(OCFS2_SB(sb), 1);
1562 + if (IS_ERR(handle)) {
1563 + status = PTR_ERR(handle);
1564 + mlog_errno(status);
1565 + return status;
1566 + }
1567 + status = ocfs2_journal_access(handle, inode, bh,
1568 + OCFS2_JOURNAL_ACCESS_WRITE);
1569 + if (status < 0) {
1570 + mlog_errno(status);
1571 + ocfs2_commit_trans(OCFS2_SB(sb), handle);
1572 + return status;
1573 + }
1574 + lock_buffer(bh);
1575 + modify(bh, private);
1576 + unlock_buffer(bh);
1577 + status = ocfs2_journal_dirty(handle, bh);
1578 + if (status < 0) {
1579 + mlog_errno(status);
1580 + ocfs2_commit_trans(OCFS2_SB(sb), handle);
1581 + return status;
1582 + }
1583 + status = ocfs2_commit_trans(OCFS2_SB(sb), handle);
1584 + if (status < 0) {
1585 + mlog_errno(status);
1586 + return status;
1587 + }
1588 + return 0;
1589 +}
1590 +
1591 +/* Check whether we understand format of quota files */
1592 +static int ocfs2_local_check_quota_file(struct super_block *sb, int type)
1593 +{
1594 + unsigned int lmagics[MAXQUOTAS] = OCFS2_LOCAL_QMAGICS;
1595 + unsigned int lversions[MAXQUOTAS] = OCFS2_LOCAL_QVERSIONS;
1596 + unsigned int gmagics[MAXQUOTAS] = OCFS2_GLOBAL_QMAGICS;
1597 + unsigned int gversions[MAXQUOTAS] = OCFS2_GLOBAL_QVERSIONS;
1598 + unsigned int ino[MAXQUOTAS] = { USER_QUOTA_SYSTEM_INODE,
1599 + GROUP_QUOTA_SYSTEM_INODE };
1600 + struct buffer_head *bh;
1601 + struct inode *linode = sb_dqopt(sb)->files[type];
1602 + struct inode *ginode = NULL;
1603 + struct ocfs2_disk_dqheader *dqhead;
1604 + int status, ret = 0;
1605 +
1606 + /* First check whether we understand local quota file */
1607 + bh = ocfs2_bread(linode, 0, &status, 0);
1608 + if (!bh) {
1609 + mlog_errno(status);
1610 + mlog(ML_ERROR, "failed to read quota file header (type=%d)\n",
1611 + type);
1612 + goto out_err;
1613 + }
1614 + dqhead = (struct ocfs2_disk_dqheader *)(bh->b_data);
1615 + if (le32_to_cpu(dqhead->dqh_magic) != lmagics[type]) {
1616 + mlog(ML_ERROR, "quota file magic does not match (%u != %u),"
1617 + " type=%d\n", le32_to_cpu(dqhead->dqh_magic),
1618 + lmagics[type], type);
1619 + goto out_err;
1620 + }
1621 + if (le32_to_cpu(dqhead->dqh_version) != lversions[type]) {
1622 + mlog(ML_ERROR, "quota file version does not match (%u != %u),"
1623 + " type=%d\n", le32_to_cpu(dqhead->dqh_version),
1624 + lversions[type], type);
1625 + goto out_err;
1626 + }
1627 + brelse(bh);
1628 + bh = NULL;
1629 +
1630 + /* Next check whether we understand global quota file */
1631 + ginode = ocfs2_get_system_file_inode(OCFS2_SB(sb), ino[type],
1632 + OCFS2_INVALID_SLOT);
1633 + if (!ginode) {
1634 + mlog(ML_ERROR, "cannot get global quota file inode "
1635 + "(type=%d)\n", type);
1636 + goto out_err;
1637 + }
1638 + /* Since the header is read only, we don't care about locking */
1639 + bh = ocfs2_bread(ginode, 0, &status, 0);
1640 + if (!bh) {
1641 + mlog_errno(status);
1642 + mlog(ML_ERROR, "failed to read global quota file header "
1643 + "(type=%d)\n", type);
1644 + goto out_err;
1645 + }
1646 + dqhead = (struct ocfs2_disk_dqheader *)(bh->b_data);
1647 + if (le32_to_cpu(dqhead->dqh_magic) != gmagics[type]) {
1648 + mlog(ML_ERROR, "global quota file magic does not match "
1649 + "(%u != %u), type=%d\n",
1650 + le32_to_cpu(dqhead->dqh_magic), gmagics[type], type);
1651 + goto out_err;
1652 + }
1653 + if (le32_to_cpu(dqhead->dqh_version) != gversions[type]) {
1654 + mlog(ML_ERROR, "global quota file version does not match "
1655 + "(%u != %u), type=%d\n",
1656 + le32_to_cpu(dqhead->dqh_version), gversions[type],
1657 + type);
1658 + goto out_err;
1659 + }
1660 +
1661 + ret = 1;
1662 +out_err:
1663 + brelse(bh);
1664 + iput(ginode);
1665 + return ret;
1666 +}
1667 +
1668 +/* Release given list of quota file chunks */
1669 +static void ocfs2_release_local_quota_bitmaps(struct list_head *head)
1670 +{
1671 + struct ocfs2_quota_chunk *pos, *next;
1672 +
1673 + list_for_each_entry_safe(pos, next, head, qc_chunk) {
1674 + list_del(&pos->qc_chunk);
1675 + brelse(pos->qc_headerbh);
1676 + kmem_cache_free(ocfs2_qf_chunk_cachep, pos);
1677 + }
1678 +}
1679 +
1680 +/* Load quota bitmaps into memory */
1681 +static int ocfs2_load_local_quota_bitmaps(struct inode *inode,
1682 + struct ocfs2_local_disk_dqinfo *ldinfo,
1683 + struct list_head *head)
1684 +{
1685 + struct ocfs2_quota_chunk *newchunk;
1686 + int i, status;
1687 +
1688 + INIT_LIST_HEAD(head);
1689 + for (i = 0; i < le32_to_cpu(ldinfo->dqi_chunks); i++) {
1690 + newchunk = kmem_cache_alloc(ocfs2_qf_chunk_cachep, GFP_NOFS);
1691 + if (!newchunk) {
1692 + ocfs2_release_local_quota_bitmaps(head);
1693 + return -ENOMEM;
1694 + }
1695 + newchunk->qc_num = i;
1696 + newchunk->qc_headerbh = ocfs2_bread(inode,
1697 + ol_quota_chunk_block(inode->i_sb, i),
1698 + &status, 0);
1699 + if (!newchunk->qc_headerbh) {
1700 + mlog_errno(status);
1701 + kmem_cache_free(ocfs2_qf_chunk_cachep, newchunk);
1702 + ocfs2_release_local_quota_bitmaps(head);
1703 + return status;
1704 + }
1705 + list_add_tail(&newchunk->qc_chunk, head);
1706 + }
1707 + return 0;
1708 +}
1709 +
1710 +static void olq_update_info(struct buffer_head *bh, void *private)
1711 +{
1712 + struct mem_dqinfo *info = private;
1713 + struct ocfs2_mem_dqinfo *oinfo = info->dqi_priv;
1714 + struct ocfs2_local_disk_dqinfo *ldinfo;
1715 +
1716 + ldinfo = (struct ocfs2_local_disk_dqinfo *)(bh->b_data +
1717 + OCFS2_LOCAL_INFO_OFF);
1718 + spin_lock(&dq_data_lock);
1719 + ldinfo->dqi_flags = cpu_to_le32(info->dqi_flags & DQF_MASK);
1720 + ldinfo->dqi_chunks = cpu_to_le32(oinfo->dqi_chunks);
1721 + ldinfo->dqi_blocks = cpu_to_le32(oinfo->dqi_blocks);
1722 + spin_unlock(&dq_data_lock);
1723 +}
1724 +
1725 +/* Read information header from quota file */
1726 +static int ocfs2_local_read_info(struct super_block *sb, int type)
1727 +{
1728 + struct ocfs2_local_disk_dqinfo *ldinfo;
1729 + struct mem_dqinfo *info = sb_dqinfo(sb, type);
1730 + struct ocfs2_mem_dqinfo *oinfo;
1731 + struct inode *lqinode = sb_dqopt(sb)->files[type];
1732 + int status;
1733 + struct buffer_head *bh = NULL;
1734 + int locked = 0;
1735 +
1736 + info->dqi_maxblimit = 0x7fffffffffffffffLL;
1737 + info->dqi_maxilimit = 0x7fffffffffffffffLL;
1738 + oinfo = kmalloc(sizeof(struct ocfs2_mem_dqinfo), GFP_NOFS);
1739 + if (!oinfo) {
1740 + mlog(ML_ERROR, "failed to allocate memory for ocfs2 quota"
1741 + " info.");
1742 + goto out_err;
1743 + }
1744 + info->dqi_priv = oinfo;
1745 + oinfo->dqi_type = type;
1746 + INIT_LIST_HEAD(&oinfo->dqi_chunk);
1747 + oinfo->dqi_lqi_bh = NULL;
1748 + oinfo->dqi_ibh = NULL;
1749 +
1750 + status = ocfs2_global_read_info(sb, type);
1751 + if (status < 0)
1752 + goto out_err;
1753 +
1754 + status = ocfs2_inode_lock(lqinode, &oinfo->dqi_lqi_bh, 1);
1755 + if (status < 0) {
1756 + mlog_errno(status);
1757 + goto out_err;
1758 + }
1759 + locked = 1;
1760 +
1761 + /* Now read local header */
1762 + bh = ocfs2_bread(lqinode, 0, &status, 0);
1763 + if (!bh) {
1764 + mlog_errno(status);
1765 + mlog(ML_ERROR, "failed to read quota file info header "
1766 + "(type=%d)\n", type);
1767 + goto out_err;
1768 + }
1769 + ldinfo = (struct ocfs2_local_disk_dqinfo *)(bh->b_data +
1770 + OCFS2_LOCAL_INFO_OFF);
1771 + info->dqi_flags = le32_to_cpu(ldinfo->dqi_flags);
1772 + oinfo->dqi_chunks = le32_to_cpu(ldinfo->dqi_chunks);
1773 + oinfo->dqi_blocks = le32_to_cpu(ldinfo->dqi_blocks);
1774 + oinfo->dqi_ibh = bh;
1775 +
1776 + /* We crashed when using local quota file? */
1777 + if (!(info->dqi_flags & OLQF_CLEAN))
1778 + goto out_err; /* So far we just bail out. Later we should resync here */
1779 +
1780 + status = ocfs2_load_local_quota_bitmaps(sb_dqopt(sb)->files[type],
1781 + ldinfo,
1782 + &oinfo->dqi_chunk);
1783 + if (status < 0) {
1784 + mlog_errno(status);
1785 + goto out_err;
1786 + }
1787 +
1788 + /* Now mark quota file as used */
1789 + info->dqi_flags &= ~OLQF_CLEAN;
1790 + status = ocfs2_modify_bh(lqinode, bh, olq_update_info, info);
1791 + if (status < 0) {
1792 + mlog_errno(status);
1793 + goto out_err;
1794 + }
1795 +
1796 + return 0;
1797 +out_err:
1798 + if (oinfo) {
1799 + iput(oinfo->dqi_gqinode);
1800 + ocfs2_simple_drop_lockres(OCFS2_SB(sb), &oinfo->dqi_gqlock);
1801 + ocfs2_lock_res_free(&oinfo->dqi_gqlock);
1802 + brelse(oinfo->dqi_lqi_bh);
1803 + if (locked)
1804 + ocfs2_inode_unlock(lqinode, 1);
1805 + ocfs2_release_local_quota_bitmaps(&oinfo->dqi_chunk);
1806 + kfree(oinfo);
1807 + }
1808 + brelse(bh);
1809 + return -1;
1810 +}
1811 +
1812 +/* Write local info to quota file */
1813 +static int ocfs2_local_write_info(struct super_block *sb, int type)
1814 +{
1815 + struct mem_dqinfo *info = sb_dqinfo(sb, type);
1816 + struct buffer_head *bh = ((struct ocfs2_mem_dqinfo *)info->dqi_priv)
1817 + ->dqi_ibh;
1818 + int status;
1819 +
1820 + status = ocfs2_modify_bh(sb_dqopt(sb)->files[type], bh, olq_update_info,
1821 + info);
1822 + if (status < 0) {
1823 + mlog_errno(status);
1824 + return -1;
1825 + }
1826 +
1827 + return 0;
1828 +}
1829 +
1830 +/* Release info from memory */
1831 +static int ocfs2_local_free_info(struct super_block *sb, int type)
1832 +{
1833 + struct mem_dqinfo *info = sb_dqinfo(sb, type);
1834 + struct ocfs2_mem_dqinfo *oinfo = info->dqi_priv;
1835 + struct ocfs2_quota_chunk *chunk;
1836 + struct ocfs2_local_disk_chunk *dchunk;
1837 + int mark_clean = 1, len;
1838 + int status;
1839 +
1840 + iput(oinfo->dqi_gqinode);
1841 + ocfs2_simple_drop_lockres(OCFS2_SB(sb), &oinfo->dqi_gqlock);
1842 + ocfs2_lock_res_free(&oinfo->dqi_gqlock);
1843 + list_for_each_entry(chunk, &oinfo->dqi_chunk, qc_chunk) {
1844 + dchunk = (struct ocfs2_local_disk_chunk *)
1845 + (chunk->qc_headerbh->b_data);
1846 + if (chunk->qc_num < oinfo->dqi_chunks - 1) {
1847 + len = ol_chunk_entries(sb);
1848 + } else {
1849 + len = (oinfo->dqi_blocks -
1850 + ol_quota_chunk_block(sb, chunk->qc_num) - 1)
1851 + * ol_quota_entries_per_block(sb);
1852 + }
1853 + /* Not all entries free? Bug! */
1854 + if (le32_to_cpu(dchunk->dqc_free) != len) {
1855 + mlog(ML_ERROR, "releasing quota file with used "
1856 + "entries (type=%d)\n", type);
1857 + mark_clean = 0;
1858 + }
1859 + }
1860 + ocfs2_release_local_quota_bitmaps(&oinfo->dqi_chunk);
1861 +
1862 + if (!mark_clean)
1863 + goto out;
1864 +
1865 + /* Mark local file as clean */
1866 + info->dqi_flags |= OLQF_CLEAN;
1867 + status = ocfs2_modify_bh(sb_dqopt(sb)->files[type],
1868 + oinfo->dqi_ibh,
1869 + olq_update_info,
1870 + info);
1871 + if (status < 0) {
1872 + mlog_errno(status);
1873 + goto out;
1874 + }
1875 +
1876 +out:
1877 + ocfs2_inode_unlock(sb_dqopt(sb)->files[type], 1);
1878 + brelse(oinfo->dqi_ibh);
1879 + brelse(oinfo->dqi_lqi_bh);
1880 + kfree(oinfo);
1881 + return 0;
1882 +}
1883 +
1884 +static void olq_set_dquot(struct buffer_head *bh, void *private)
1885 +{
1886 + struct ocfs2_dquot *od = private;
1887 + struct ocfs2_local_disk_dqblk *dqblk;
1888 + struct super_block *sb = od->dq_dquot.dq_sb;
1889 +
1890 + dqblk = (struct ocfs2_local_disk_dqblk *)(bh->b_data
1891 + + ol_dqblk_block_offset(sb, od->dq_local_off));
1892 +
1893 + dqblk->dqb_id = cpu_to_le64(od->dq_dquot.dq_id);
1894 + spin_lock(&dq_data_lock);
1895 + dqblk->dqb_spacemod = cpu_to_le64(od->dq_dquot.dq_dqb.dqb_curspace -
1896 + od->dq_origspace);
1897 + dqblk->dqb_inodemod = cpu_to_le64(od->dq_dquot.dq_dqb.dqb_curinodes -
1898 + od->dq_originodes);
1899 + spin_unlock(&dq_data_lock);
1900 + mlog(0, "Writing local dquot %u space %lld inodes %lld\n",
1901 + od->dq_dquot.dq_id, dqblk->dqb_spacemod, dqblk->dqb_inodemod);
1902 +}
1903 +
1904 +/* Write dquot to local quota file */
1905 +static int ocfs2_local_write_dquot(struct dquot *dquot)
1906 +{
1907 + struct super_block *sb = dquot->dq_sb;
1908 + struct ocfs2_dquot *od = OCFS2_DQUOT(dquot);
1909 + struct buffer_head *bh;
1910 + int status;
1911 +
1912 + bh = ocfs2_bread(sb_dqopt(sb)->files[dquot->dq_type],
1913 + ol_dqblk_file_block(sb, od->dq_local_off),
1914 + &status, 0);
1915 + if (!bh) {
1916 + mlog_errno(status);
1917 + goto out;
1918 + }
1919 + status = ocfs2_modify_bh(sb_dqopt(sb)->files[dquot->dq_type], bh,
1920 + olq_set_dquot, od);
1921 + if (status < 0) {
1922 + mlog_errno(status);
1923 + goto out;
1924 + }
1925 +out:
1926 + brelse(bh);
1927 + return status;
1928 +}
1929 +
1930 +/* Find free entry in local quota file */
1931 +static struct ocfs2_quota_chunk *ocfs2_find_free_entry(struct super_block *sb,
1932 + int type,
1933 + int *offset)
1934 +{
1935 + struct mem_dqinfo *info = sb_dqinfo(sb, type);
1936 + struct ocfs2_mem_dqinfo *oinfo = info->dqi_priv;
1937 + struct ocfs2_quota_chunk *chunk;
1938 + struct ocfs2_local_disk_chunk *dchunk;
1939 + int found = 0, len;
1940 +
1941 + list_for_each_entry(chunk, &oinfo->dqi_chunk, qc_chunk) {
1942 + dchunk = (struct ocfs2_local_disk_chunk *)
1943 + chunk->qc_headerbh->b_data;
1944 + if (le32_to_cpu(dchunk->dqc_free) > 0) {
1945 + found = 1;
1946 + break;
1947 + }
1948 + }
1949 + if (!found)
1950 + return NULL;
1951 +
1952 + if (chunk->qc_num < oinfo->dqi_chunks - 1) {
1953 + len = ol_chunk_entries(sb);
1954 + } else {
1955 + len = (oinfo->dqi_blocks -
1956 + ol_quota_chunk_block(sb, chunk->qc_num) - 1)
1957 + * ol_quota_entries_per_block(sb);
1958 + }
1959 +
1960 + found = ocfs2_find_next_zero_bit(dchunk->dqc_bitmap, len, 0);
1961 + /* We failed? */
1962 + if (found == len) {
1963 + mlog(ML_ERROR, "Did not find empty entry in chunk %d with %u"
1964 + " entries free (type=%d)\n", chunk->qc_num,
1965 + le32_to_cpu(dchunk->dqc_free), type);
1966 + return ERR_PTR(-EIO);
1967 + }
1968 + *offset = found;
1969 + return chunk;
1970 +}
1971 +
1972 +/* Add new chunk to the local quota file */
1973 +static struct ocfs2_quota_chunk *ocfs2_local_quota_add_chunk(
1974 + struct super_block *sb,
1975 + int type,
1976 + int *offset)
1977 +{
1978 + struct mem_dqinfo *info = sb_dqinfo(sb, type);
1979 + struct ocfs2_mem_dqinfo *oinfo = info->dqi_priv;
1980 + struct inode *lqinode = sb_dqopt(sb)->files[type];
1981 + struct ocfs2_quota_chunk *chunk = NULL;
1982 + struct ocfs2_local_disk_chunk *dchunk;
1983 + int status;
1984 + handle_t *handle;
1985 + struct buffer_head *bh = NULL;
1986 + u64 p_blkno;
1987 +
1988 + /* We are protected by dqio_sem so no locking needed */
1989 + status = ocfs2_extend_no_holes(lqinode,
1990 + lqinode->i_size + 2 * sb->s_blocksize,
1991 + lqinode->i_size);
1992 + if (status < 0) {
1993 + mlog_errno(status);
1994 + goto out;
1995 + }
1996 + status = ocfs2_simple_size_update(lqinode, oinfo->dqi_lqi_bh,
1997 + lqinode->i_size + 2 * sb->s_blocksize);
1998 + if (status < 0) {
1999 + mlog_errno(status);
2000 + goto out;
2001 + }
2002 +
2003 + chunk = kmem_cache_alloc(ocfs2_qf_chunk_cachep, GFP_NOFS);
2004 + if (!chunk) {
2005 + status = -ENOMEM;
2006 + mlog_errno(status);
2007 + goto out;
2008 + }
2009 +
2010 + down_read(&OCFS2_I(lqinode)->ip_alloc_sem);
2011 + status = ocfs2_extent_map_get_blocks(lqinode, oinfo->dqi_blocks,
2012 + &p_blkno, NULL, NULL);
2013 + up_read(&OCFS2_I(lqinode)->ip_alloc_sem);
2014 + if (status < 0) {
2015 + mlog_errno(status);
2016 + goto out;
2017 + }
2018 + bh = sb_getblk(sb, p_blkno);
2019 + if (!bh) {
2020 + status = -ENOMEM;
2021 + mlog_errno(status);
2022 + goto out;
2023 + }
2024 + dchunk = (struct ocfs2_local_disk_chunk *)bh->b_data;
2025 +
2026 + handle = ocfs2_start_trans(OCFS2_SB(sb), 2);
2027 + if (IS_ERR(handle)) {
2028 + status = PTR_ERR(handle);
2029 + mlog_errno(status);
2030 + goto out;
2031 + }
2032 +
2033 + status = ocfs2_journal_access(handle, lqinode, bh,
2034 + OCFS2_JOURNAL_ACCESS_WRITE);
2035 + if (status < 0) {
2036 + mlog_errno(status);
2037 + goto out_trans;
2038 + }
2039 + lock_buffer(bh);
2040 + dchunk->dqc_free = ol_quota_entries_per_block(sb);
2041 + memset(dchunk->dqc_bitmap, 0,
2042 + sb->s_blocksize - sizeof(struct ocfs2_local_disk_chunk) -
2043 + OCFS2_QBLK_RESERVED_SPACE);
2044 + set_buffer_uptodate(bh);
2045 + unlock_buffer(bh);
2046 + status = ocfs2_journal_dirty(handle, bh);
2047 + if (status < 0) {
2048 + mlog_errno(status);
2049 + goto out_trans;
2050 + }
2051 +
2052 + oinfo->dqi_blocks += 2;
2053 + oinfo->dqi_chunks++;
2054 + status = ocfs2_local_write_info(sb, type);
2055 + if (status < 0) {
2056 + mlog_errno(status);
2057 + goto out_trans;
2058 + }
2059 + status = ocfs2_commit_trans(OCFS2_SB(sb), handle);
2060 + if (status < 0) {
2061 + mlog_errno(status);
2062 + goto out;
2063 + }
2064 +
2065 + list_add_tail(&chunk->qc_chunk, &oinfo->dqi_chunk);
2066 + chunk->qc_num = list_entry(chunk->qc_chunk.prev,
2067 + struct ocfs2_quota_chunk,
2068 + qc_chunk)->qc_num + 1;
2069 + chunk->qc_headerbh = bh;
2070 + *offset = 0;
2071 + return chunk;
2072 +out_trans:
2073 + ocfs2_commit_trans(OCFS2_SB(sb), handle);
2074 +out:
2075 + brelse(bh);
2076 + kmem_cache_free(ocfs2_qf_chunk_cachep, chunk);
2077 + return ERR_PTR(status);
2078 +}
2079 +
2080 +/* Find free entry in local quota file */
2081 +static struct ocfs2_quota_chunk *ocfs2_extend_local_quota_file(
2082 + struct super_block *sb,
2083 + int type,
2084 + int *offset)
2085 +{
2086 + struct mem_dqinfo *info = sb_dqinfo(sb, type);
2087 + struct ocfs2_mem_dqinfo *oinfo = info->dqi_priv;
2088 + struct ocfs2_quota_chunk *chunk;
2089 + struct inode *lqinode = sb_dqopt(sb)->files[type];
2090 + struct ocfs2_local_disk_chunk *dchunk;
2091 + int epb = ol_quota_entries_per_block(sb);
2092 + unsigned int chunk_blocks;
2093 + int status;
2094 + handle_t *handle;
2095 +
2096 + if (list_empty(&oinfo->dqi_chunk))
2097 + return ocfs2_local_quota_add_chunk(sb, type, offset);
2098 + /* Is the last chunk full? */
2099 + chunk = list_entry(oinfo->dqi_chunk.prev,
2100 + struct ocfs2_quota_chunk, qc_chunk);
2101 + chunk_blocks = oinfo->dqi_blocks -
2102 + ol_quota_chunk_block(sb, chunk->qc_num) - 1;
2103 + if (ol_chunk_blocks(sb) == chunk_blocks)
2104 + return ocfs2_local_quota_add_chunk(sb, type, offset);
2105 +
2106 + /* We are protected by dqio_sem so no locking needed */
2107 + status = ocfs2_extend_no_holes(lqinode,
2108 + lqinode->i_size + sb->s_blocksize,
2109 + lqinode->i_size);
2110 + if (status < 0) {
2111 + mlog_errno(status);
2112 + goto out;
2113 + }
2114 + status = ocfs2_simple_size_update(lqinode, oinfo->dqi_lqi_bh,
2115 + lqinode->i_size + sb->s_blocksize);
2116 + if (status < 0) {
2117 + mlog_errno(status);
2118 + goto out;
2119 + }
2120 + handle = ocfs2_start_trans(OCFS2_SB(sb), 2);
2121 + if (IS_ERR(handle)) {
2122 + status = PTR_ERR(handle);
2123 + mlog_errno(status);
2124 + goto out;
2125 + }
2126 + status = ocfs2_journal_access(handle, lqinode, chunk->qc_headerbh,
2127 + OCFS2_JOURNAL_ACCESS_WRITE);
2128 + if (status < 0) {
2129 + mlog_errno(status);
2130 + goto out_trans;
2131 + }
2132 +
2133 + dchunk = (struct ocfs2_local_disk_chunk *)chunk->qc_headerbh->b_data;
2134 + lock_buffer(chunk->qc_headerbh);
2135 + le32_add_cpu(&dchunk->dqc_free, ol_quota_entries_per_block(sb));
2136 + unlock_buffer(chunk->qc_headerbh);
2137 + status = ocfs2_journal_dirty(handle, chunk->qc_headerbh);
2138 + if (status < 0) {
2139 + mlog_errno(status);
2140 + goto out_trans;
2141 + }
2142 + oinfo->dqi_blocks++;
2143 + status = ocfs2_local_write_info(sb, type);
2144 + if (status < 0) {
2145 + mlog_errno(status);
2146 + goto out_trans;
2147 + }
2148 +
2149 + status = ocfs2_commit_trans(OCFS2_SB(sb), handle);
2150 + if (status < 0) {
2151 + mlog_errno(status);
2152 + goto out;
2153 + }
2154 + *offset = chunk_blocks * epb;
2155 + return chunk;
2156 +out_trans:
2157 + ocfs2_commit_trans(OCFS2_SB(sb), handle);
2158 +out:
2159 + return ERR_PTR(status);
2160 +}
2161 +
2162 +void olq_alloc_dquot(struct buffer_head *bh, void *private)
2163 +{
2164 + int *offset = private;
2165 + struct ocfs2_local_disk_chunk *dchunk;
2166 +
2167 + dchunk = (struct ocfs2_local_disk_chunk *)bh->b_data;
2168 + ocfs2_set_bit(*offset, dchunk->dqc_bitmap);
2169 + le32_add_cpu(&dchunk->dqc_free, -1);
2170 +}
2171 +
2172 +/* Create dquot in the local file for given id */
2173 +static int ocfs2_create_local_dquot(struct dquot *dquot)
2174 +{
2175 + struct super_block *sb = dquot->dq_sb;
2176 + int type = dquot->dq_type;
2177 + struct inode *lqinode = sb_dqopt(sb)->files[type];
2178 + struct ocfs2_quota_chunk *chunk;
2179 + struct ocfs2_dquot *od = OCFS2_DQUOT(dquot);
2180 + int offset;
2181 + int status;
2182 +
2183 + chunk = ocfs2_find_free_entry(sb, type, &offset);
2184 + if (!chunk) {
2185 + chunk = ocfs2_extend_local_quota_file(sb, type, &offset);
2186 + if (IS_ERR(chunk))
2187 + return PTR_ERR(chunk);
2188 + } else if (IS_ERR(chunk)) {
2189 + return PTR_ERR(chunk);
2190 + }
2191 + od->dq_local_off = ol_dqblk_off(sb, chunk->qc_num, offset);
2192 + od->dq_chunk = chunk;
2193 +
2194 + /* Initialize dquot structure on disk */
2195 + status = ocfs2_local_write_dquot(dquot);
2196 + if (status < 0) {
2197 + mlog_errno(status);
2198 + goto out;
2199 + }
2200 +
2201 + /* Mark structure as allocated */
2202 + status = ocfs2_modify_bh(lqinode, chunk->qc_headerbh, olq_alloc_dquot,
2203 + &offset);
2204 + if (status < 0) {
2205 + mlog_errno(status);
2206 + goto out;
2207 + }
2208 +out:
2209 + return status;
2210 +}
2211 +
2212 +/* Create entry in local file for dquot, load data from the global file */
2213 +static int ocfs2_local_read_dquot(struct dquot *dquot)
2214 +{
2215 + int status;
2216 +
2217 + mlog_entry("id=%u, type=%d\n", dquot->dq_id, dquot->dq_type);
2218 +
2219 + status = ocfs2_global_read_dquot(dquot);
2220 + if (status < 0) {
2221 + mlog_errno(status);
2222 + goto out_err;
2223 + }
2224 +
2225 + /* Now create entry in the local quota file */
2226 + status = ocfs2_create_local_dquot(dquot);
2227 + if (status < 0) {
2228 + mlog_errno(status);
2229 + goto out_err;
2230 + }
2231 + mlog_exit(0);
2232 + return 0;
2233 +out_err:
2234 + mlog_exit(status);
2235 + return status;
2236 +}
2237 +
2238 +/* Release dquot structure from local quota file. ocfs2_release_dquot() has
2239 + * already started a transaction and obtained exclusive lock for global
2240 + * quota file. */
2241 +static int ocfs2_local_release_dquot(struct dquot *dquot)
2242 +{
2243 + int status;
2244 + int type = dquot->dq_type;
2245 + struct ocfs2_dquot *od = OCFS2_DQUOT(dquot);
2246 + struct super_block *sb = dquot->dq_sb;
2247 + struct ocfs2_local_disk_chunk *dchunk;
2248 + int offset;
2249 + handle_t *handle = journal_current_handle();
2250 +
2251 + BUG_ON(!handle);
2252 + /* First write all local changes to global file */
2253 + status = ocfs2_global_release_dquot(dquot);
2254 + if (status < 0) {
2255 + mlog_errno(status);
2256 + goto out;
2257 + }
2258 +
2259 + status = ocfs2_journal_access(handle, sb_dqopt(sb)->files[type],
2260 + od->dq_chunk->qc_headerbh, OCFS2_JOURNAL_ACCESS_WRITE);
2261 + if (status < 0) {
2262 + mlog_errno(status);
2263 + goto out;
2264 + }
2265 + offset = ol_dqblk_chunk_off(sb, od->dq_chunk->qc_num,
2266 + od->dq_local_off);
2267 + dchunk = (struct ocfs2_local_disk_chunk *)
2268 + (od->dq_chunk->qc_headerbh->b_data);
2269 + /* Mark structure as freed */
2270 + lock_buffer(od->dq_chunk->qc_headerbh);
2271 + ocfs2_clear_bit(offset, dchunk->dqc_bitmap);
2272 + le32_add_cpu(&dchunk->dqc_free, 1);
2273 + unlock_buffer(od->dq_chunk->qc_headerbh);
2274 + status = ocfs2_journal_dirty(handle, od->dq_chunk->qc_headerbh);
2275 + if (status < 0) {
2276 + mlog_errno(status);
2277 + goto out;
2278 + }
2279 + status = 0;
2280 +out:
2281 + /* Clear the read bit so that next time someone uses this
2282 + * dquot he reads fresh info from disk and allocates local
2283 + * dquot structure */
2284 + clear_bit(DQ_READ_B, &dquot->dq_flags);
2285 + return status;
2286 +}
2287 +
2288 +static struct quota_format_ops ocfs2_format_ops = {
2289 + .check_quota_file = ocfs2_local_check_quota_file,
2290 + .read_file_info = ocfs2_local_read_info,
2291 + .write_file_info = ocfs2_global_write_info,
2292 + .free_file_info = ocfs2_local_free_info,
2293 + .read_dqblk = ocfs2_local_read_dquot,
2294 + .commit_dqblk = ocfs2_local_write_dquot,
2295 + .release_dqblk = ocfs2_local_release_dquot,
2296 +};
2297 +
2298 +static struct quota_format_type ocfs2_quota_format = {
2299 + .qf_fmt_id = QFMT_OCFS2,
2300 + .qf_ops = &ocfs2_format_ops,
2301 + .qf_owner = THIS_MODULE
2302 +};
2303 +
2304 +int init_ocfs2_quota_format(void)
2305 +{
2306 + return register_quota_format(&ocfs2_quota_format);
2307 +}
2308 +
2309 +void exit_ocfs2_quota_format(void)
2310 +{
2311 + unregister_quota_format(&ocfs2_quota_format);
2312 +}
2313 Index: linux-2.6.27-ocfs2/fs/ocfs2/super.c
2314 ===================================================================
2315 --- linux-2.6.27-ocfs2.orig/fs/ocfs2/super.c
2316 +++ linux-2.6.27-ocfs2/fs/ocfs2/super.c
2317 @@ -65,10 +65,13 @@
2318 #include "uptodate.h"
2319 #include "ver.h"
2320 #include "xattr.h"
2321 +#include "quota.h"
2322
2323 #include "buffer_head_io.h"
2324
2325 static struct kmem_cache *ocfs2_inode_cachep = NULL;
2326 +struct kmem_cache *ocfs2_dquot_cachep;
2327 +struct kmem_cache *ocfs2_qf_chunk_cachep;
2328
2329 /* OCFS2 needs to schedule several differnt types of work which
2330 * require cluster locking, disk I/O, recovery waits, etc. Since these
2331 @@ -137,6 +140,8 @@ static const struct super_operations ocf
2332 .put_super = ocfs2_put_super,
2333 .remount_fs = ocfs2_remount,
2334 .show_options = ocfs2_show_options,
2335 + .quota_read = ocfs2_quota_read,
2336 + .quota_write = ocfs2_quota_write,
2337 };
2338
2339 enum {
2340 @@ -1073,6 +1078,7 @@ static int ocfs2_show_options(struct seq
2341 static int __init ocfs2_init(void)
2342 {
2343 int status;
2344 + int added_format = 0;
2345
2346 mlog_entry_void();
2347
2348 @@ -1090,6 +1096,13 @@ static int __init ocfs2_init(void)
2349 goto leave;
2350 }
2351
2352 + status = init_ocfs2_quota_format();
2353 + if (status < 0) {
2354 + mlog_errno(status);
2355 + goto leave;
2356 + }
2357 + added_format = 1;
2358 +
2359 ocfs2_wq = create_singlethread_workqueue("ocfs2_wq");
2360 if (!ocfs2_wq) {
2361 status = -ENOMEM;
2362 @@ -1108,6 +1121,8 @@ leave:
2363 if (status < 0) {
2364 ocfs2_free_mem_caches();
2365 exit_ocfs2_uptodate_cache();
2366 + if (added_format)
2367 + exit_ocfs2_quota_format();
2368 }
2369
2370 mlog_exit(status);
2371 @@ -1127,6 +1142,8 @@ static void __exit ocfs2_exit(void)
2372 destroy_workqueue(ocfs2_wq);
2373 }
2374
2375 + exit_ocfs2_quota_format();
2376 +
2377 debugfs_remove(ocfs2_debugfs_root);
2378
2379 ocfs2_free_mem_caches();
2380 @@ -1242,8 +1259,27 @@ static int ocfs2_initialize_mem_caches(v
2381 (SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT|
2382 SLAB_MEM_SPREAD),
2383 ocfs2_inode_init_once);
2384 - if (!ocfs2_inode_cachep)
2385 + ocfs2_dquot_cachep = kmem_cache_create("ocfs2_dquot_cache",
2386 + sizeof(struct ocfs2_dquot),
2387 + 0,
2388 + (SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT|
2389 + SLAB_MEM_SPREAD),
2390 + NULL);
2391 + ocfs2_qf_chunk_cachep = kmem_cache_create("ocfs2_qf_chunk_cache",
2392 + sizeof(struct ocfs2_quota_chunk),
2393 + 0,
2394 + (SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD),
2395 + NULL);
2396 + if (!ocfs2_inode_cachep || !ocfs2_dquot_cachep ||
2397 + !ocfs2_qf_chunk_cachep) {
2398 + if (ocfs2_inode_cachep)
2399 + kmem_cache_destroy(ocfs2_inode_cachep);
2400 + if (ocfs2_dquot_cachep)
2401 + kmem_cache_destroy(ocfs2_dquot_cachep);
2402 + if (ocfs2_qf_chunk_cachep)
2403 + kmem_cache_destroy(ocfs2_qf_chunk_cachep);
2404 return -ENOMEM;
2405 + }
2406
2407 return 0;
2408 }
2409 @@ -1252,8 +1288,15 @@ static void ocfs2_free_mem_caches(void)
2410 {
2411 if (ocfs2_inode_cachep)
2412 kmem_cache_destroy(ocfs2_inode_cachep);
2413 -
2414 ocfs2_inode_cachep = NULL;
2415 +
2416 + if (ocfs2_dquot_cachep)
2417 + kmem_cache_destroy(ocfs2_dquot_cachep);
2418 + ocfs2_dquot_cachep = NULL;
2419 +
2420 + if (ocfs2_qf_chunk_cachep)
2421 + kmem_cache_destroy(ocfs2_qf_chunk_cachep);
2422 + ocfs2_qf_chunk_cachep = NULL;
2423 }
2424
2425 static int ocfs2_get_sector(struct super_block *sb,
2426 Index: linux-2.6.27-ocfs2/fs/ocfs2/dir.c
2427 ===================================================================
2428 --- linux-2.6.27-ocfs2.orig/fs/ocfs2/dir.c
2429 +++ linux-2.6.27-ocfs2/fs/ocfs2/dir.c
2430 @@ -82,8 +82,8 @@ static int ocfs2_do_extend_dir(struct su
2431 struct ocfs2_alloc_context *meta_ac,
2432 struct buffer_head **new_bh);
2433
2434 -static struct buffer_head *ocfs2_bread(struct inode *inode,
2435 - int block, int *err, int reada)
2436 +struct buffer_head *ocfs2_bread(struct inode *inode,
2437 + int block, int *err, int reada)
2438 {
2439 struct buffer_head *bh = NULL;
2440 int tmperr;
2441 Index: linux-2.6.27-ocfs2/fs/ocfs2/inode.h
2442 ===================================================================
2443 --- linux-2.6.27-ocfs2.orig/fs/ocfs2/inode.h
2444 +++ linux-2.6.27-ocfs2/fs/ocfs2/inode.h
2445 @@ -142,6 +142,8 @@ int ocfs2_mark_inode_dirty(handle_t *han
2446 struct buffer_head *bh);
2447 int ocfs2_aio_read(struct file *file, struct kiocb *req, struct iocb *iocb);
2448 int ocfs2_aio_write(struct file *file, struct kiocb *req, struct iocb *iocb);
2449 +struct buffer_head *ocfs2_bread(struct inode *inode,
2450 + int block, int *err, int reada);
2451
2452 void ocfs2_set_inode_flags(struct inode *inode);
2453 void ocfs2_get_inode_flags(struct ocfs2_inode_info *oi);