aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2008-10-20 17:50:38 -0400
committerMark Fasheh <mfasheh@suse.com>2009-01-05 11:40:24 -0500
commit2205363dce7447b8e85f1ead14387664c1a98753 (patch)
tree729b2716f2e31bda2e035a11cc39aa5472dff2c4 /fs
parent171bf93ce11f4c9929fdce6ce63df8da2f3c4475 (diff)
ocfs2: Implement quota recovery
Implement functions for recovery after a crash. Functions just read local quota file and sync info to global quota file. Signed-off-by: Jan Kara <jack@suse.cz> Signed-off-by: Mark Fasheh <mfasheh@suse.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/ocfs2/journal.c108
-rw-r--r--fs/ocfs2/journal.h1
-rw-r--r--fs/ocfs2/ocfs2.h4
-rw-r--r--fs/ocfs2/quota.h21
-rw-r--r--fs/ocfs2/quota_global.c1
-rw-r--r--fs/ocfs2/quota_local.c425
6 files changed, 528 insertions, 32 deletions
diff --git a/fs/ocfs2/journal.c b/fs/ocfs2/journal.c
index 11a1178d5ee8..c60242018d9a 100644
--- a/fs/ocfs2/journal.c
+++ b/fs/ocfs2/journal.c
@@ -45,6 +45,7 @@
45#include "slot_map.h" 45#include "slot_map.h"
46#include "super.h" 46#include "super.h"
47#include "sysfile.h" 47#include "sysfile.h"
48#include "quota.h"
48 49
49#include "buffer_head_io.h" 50#include "buffer_head_io.h"
50 51
@@ -52,7 +53,7 @@ DEFINE_SPINLOCK(trans_inc_lock);
52 53
53static int ocfs2_force_read_journal(struct inode *inode); 54static int ocfs2_force_read_journal(struct inode *inode);
54static int ocfs2_recover_node(struct ocfs2_super *osb, 55static int ocfs2_recover_node(struct ocfs2_super *osb,
55 int node_num); 56 int node_num, int slot_num);
56static int __ocfs2_recovery_thread(void *arg); 57static int __ocfs2_recovery_thread(void *arg);
57static int ocfs2_commit_cache(struct ocfs2_super *osb); 58static int ocfs2_commit_cache(struct ocfs2_super *osb);
58static int ocfs2_wait_on_mount(struct ocfs2_super *osb); 59static int ocfs2_wait_on_mount(struct ocfs2_super *osb);
@@ -857,6 +858,7 @@ struct ocfs2_la_recovery_item {
857 int lri_slot; 858 int lri_slot;
858 struct ocfs2_dinode *lri_la_dinode; 859 struct ocfs2_dinode *lri_la_dinode;
859 struct ocfs2_dinode *lri_tl_dinode; 860 struct ocfs2_dinode *lri_tl_dinode;
861 struct ocfs2_quota_recovery *lri_qrec;
860}; 862};
861 863
862/* Does the second half of the recovery process. By this point, the 864/* Does the second half of the recovery process. By this point, the
@@ -877,6 +879,7 @@ void ocfs2_complete_recovery(struct work_struct *work)
877 struct ocfs2_super *osb = journal->j_osb; 879 struct ocfs2_super *osb = journal->j_osb;
878 struct ocfs2_dinode *la_dinode, *tl_dinode; 880 struct ocfs2_dinode *la_dinode, *tl_dinode;
879 struct ocfs2_la_recovery_item *item, *n; 881 struct ocfs2_la_recovery_item *item, *n;
882 struct ocfs2_quota_recovery *qrec;
880 LIST_HEAD(tmp_la_list); 883 LIST_HEAD(tmp_la_list);
881 884
882 mlog_entry_void(); 885 mlog_entry_void();
@@ -922,6 +925,16 @@ void ocfs2_complete_recovery(struct work_struct *work)
922 if (ret < 0) 925 if (ret < 0)
923 mlog_errno(ret); 926 mlog_errno(ret);
924 927
928 qrec = item->lri_qrec;
929 if (qrec) {
930 mlog(0, "Recovering quota files");
931 ret = ocfs2_finish_quota_recovery(osb, qrec,
932 item->lri_slot);
933 if (ret < 0)
934 mlog_errno(ret);
935 /* Recovery info is already freed now */
936 }
937
925 kfree(item); 938 kfree(item);
926 } 939 }
927 940
@@ -935,7 +948,8 @@ void ocfs2_complete_recovery(struct work_struct *work)
935static void ocfs2_queue_recovery_completion(struct ocfs2_journal *journal, 948static void ocfs2_queue_recovery_completion(struct ocfs2_journal *journal,
936 int slot_num, 949 int slot_num,
937 struct ocfs2_dinode *la_dinode, 950 struct ocfs2_dinode *la_dinode,
938 struct ocfs2_dinode *tl_dinode) 951 struct ocfs2_dinode *tl_dinode,
952 struct ocfs2_quota_recovery *qrec)
939{ 953{
940 struct ocfs2_la_recovery_item *item; 954 struct ocfs2_la_recovery_item *item;
941 955
@@ -950,6 +964,9 @@ static void ocfs2_queue_recovery_completion(struct ocfs2_journal *journal,
950 if (tl_dinode) 964 if (tl_dinode)
951 kfree(tl_dinode); 965 kfree(tl_dinode);
952 966
967 if (qrec)
968 ocfs2_free_quota_recovery(qrec);
969
953 mlog_errno(-ENOMEM); 970 mlog_errno(-ENOMEM);
954 return; 971 return;
955 } 972 }
@@ -958,6 +975,7 @@ static void ocfs2_queue_recovery_completion(struct ocfs2_journal *journal,
958 item->lri_la_dinode = la_dinode; 975 item->lri_la_dinode = la_dinode;
959 item->lri_slot = slot_num; 976 item->lri_slot = slot_num;
960 item->lri_tl_dinode = tl_dinode; 977 item->lri_tl_dinode = tl_dinode;
978 item->lri_qrec = qrec;
961 979
962 spin_lock(&journal->j_lock); 980 spin_lock(&journal->j_lock);
963 list_add_tail(&item->lri_list, &journal->j_la_cleanups); 981 list_add_tail(&item->lri_list, &journal->j_la_cleanups);
@@ -977,6 +995,7 @@ void ocfs2_complete_mount_recovery(struct ocfs2_super *osb)
977 ocfs2_queue_recovery_completion(journal, 995 ocfs2_queue_recovery_completion(journal,
978 osb->slot_num, 996 osb->slot_num,
979 osb->local_alloc_copy, 997 osb->local_alloc_copy,
998 NULL,
980 NULL); 999 NULL);
981 ocfs2_schedule_truncate_log_flush(osb, 0); 1000 ocfs2_schedule_truncate_log_flush(osb, 0);
982 1001
@@ -985,11 +1004,26 @@ void ocfs2_complete_mount_recovery(struct ocfs2_super *osb)
985 } 1004 }
986} 1005}
987 1006
1007void ocfs2_complete_quota_recovery(struct ocfs2_super *osb)
1008{
1009 if (osb->quota_rec) {
1010 ocfs2_queue_recovery_completion(osb->journal,
1011 osb->slot_num,
1012 NULL,
1013 NULL,
1014 osb->quota_rec);
1015 osb->quota_rec = NULL;
1016 }
1017}
1018
988static int __ocfs2_recovery_thread(void *arg) 1019static int __ocfs2_recovery_thread(void *arg)
989{ 1020{
990 int status, node_num; 1021 int status, node_num, slot_num;
991 struct ocfs2_super *osb = arg; 1022 struct ocfs2_super *osb = arg;
992 struct ocfs2_recovery_map *rm = osb->recovery_map; 1023 struct ocfs2_recovery_map *rm = osb->recovery_map;
1024 int *rm_quota = NULL;
1025 int rm_quota_used = 0, i;
1026 struct ocfs2_quota_recovery *qrec;
993 1027
994 mlog_entry_void(); 1028 mlog_entry_void();
995 1029
@@ -998,6 +1032,11 @@ static int __ocfs2_recovery_thread(void *arg)
998 goto bail; 1032 goto bail;
999 } 1033 }
1000 1034
1035 rm_quota = kzalloc(osb->max_slots * sizeof(int), GFP_NOFS);
1036 if (!rm_quota) {
1037 status = -ENOMEM;
1038 goto bail;
1039 }
1001restart: 1040restart:
1002 status = ocfs2_super_lock(osb, 1); 1041 status = ocfs2_super_lock(osb, 1);
1003 if (status < 0) { 1042 if (status < 0) {
@@ -1011,8 +1050,28 @@ restart:
1011 * clear it until ocfs2_recover_node() has succeeded. */ 1050 * clear it until ocfs2_recover_node() has succeeded. */
1012 node_num = rm->rm_entries[0]; 1051 node_num = rm->rm_entries[0];
1013 spin_unlock(&osb->osb_lock); 1052 spin_unlock(&osb->osb_lock);
1014 1053 mlog(0, "checking node %d\n", node_num);
1015 status = ocfs2_recover_node(osb, node_num); 1054 slot_num = ocfs2_node_num_to_slot(osb, node_num);
1055 if (slot_num == -ENOENT) {
1056 status = 0;
1057 mlog(0, "no slot for this node, so no recovery"
1058 "required.\n");
1059 goto skip_recovery;
1060 }
1061 mlog(0, "node %d was using slot %d\n", node_num, slot_num);
1062
1063 /* It is a bit subtle with quota recovery. We cannot do it
1064 * immediately because we have to obtain cluster locks from
1065 * quota files and we also don't want to just skip it because
1066 * then quota usage would be out of sync until some node takes
1067 * the slot. So we remember which nodes need quota recovery
1068 * and when everything else is done, we recover quotas. */
1069 for (i = 0; i < rm_quota_used && rm_quota[i] != slot_num; i++);
1070 if (i == rm_quota_used)
1071 rm_quota[rm_quota_used++] = slot_num;
1072
1073 status = ocfs2_recover_node(osb, node_num, slot_num);
1074skip_recovery:
1016 if (!status) { 1075 if (!status) {
1017 ocfs2_recovery_map_clear(osb, node_num); 1076 ocfs2_recovery_map_clear(osb, node_num);
1018 } else { 1077 } else {
@@ -1034,13 +1093,27 @@ restart:
1034 if (status < 0) 1093 if (status < 0)
1035 mlog_errno(status); 1094 mlog_errno(status);
1036 1095
1096 /* Now it is right time to recover quotas... We have to do this under
1097 * superblock lock so that noone can start using the slot (and crash)
1098 * before we recover it */
1099 for (i = 0; i < rm_quota_used; i++) {
1100 qrec = ocfs2_begin_quota_recovery(osb, rm_quota[i]);
1101 if (IS_ERR(qrec)) {
1102 status = PTR_ERR(qrec);
1103 mlog_errno(status);
1104 continue;
1105 }
1106 ocfs2_queue_recovery_completion(osb->journal, rm_quota[i],
1107 NULL, NULL, qrec);
1108 }
1109
1037 ocfs2_super_unlock(osb, 1); 1110 ocfs2_super_unlock(osb, 1);
1038 1111
1039 /* We always run recovery on our own orphan dir - the dead 1112 /* We always run recovery on our own orphan dir - the dead
1040 * node(s) may have disallowd a previos inode delete. Re-processing 1113 * node(s) may have disallowd a previos inode delete. Re-processing
1041 * is therefore required. */ 1114 * is therefore required. */
1042 ocfs2_queue_recovery_completion(osb->journal, osb->slot_num, NULL, 1115 ocfs2_queue_recovery_completion(osb->journal, osb->slot_num, NULL,
1043 NULL); 1116 NULL, NULL);
1044 1117
1045bail: 1118bail:
1046 mutex_lock(&osb->recovery_lock); 1119 mutex_lock(&osb->recovery_lock);
@@ -1055,6 +1128,9 @@ bail:
1055 1128
1056 mutex_unlock(&osb->recovery_lock); 1129 mutex_unlock(&osb->recovery_lock);
1057 1130
1131 if (rm_quota)
1132 kfree(rm_quota);
1133
1058 mlog_exit(status); 1134 mlog_exit(status);
1059 /* no one is callint kthread_stop() for us so the kthread() api 1135 /* no one is callint kthread_stop() for us so the kthread() api
1060 * requires that we call do_exit(). And it isn't exported, but 1136 * requires that we call do_exit(). And it isn't exported, but
@@ -1282,31 +1358,19 @@ done:
1282 * far less concerning. 1358 * far less concerning.
1283 */ 1359 */
1284static int ocfs2_recover_node(struct ocfs2_super *osb, 1360static int ocfs2_recover_node(struct ocfs2_super *osb,
1285 int node_num) 1361 int node_num, int slot_num)
1286{ 1362{
1287 int status = 0; 1363 int status = 0;
1288 int slot_num;
1289 struct ocfs2_dinode *la_copy = NULL; 1364 struct ocfs2_dinode *la_copy = NULL;
1290 struct ocfs2_dinode *tl_copy = NULL; 1365 struct ocfs2_dinode *tl_copy = NULL;
1291 1366
1292 mlog_entry("(node_num=%d, osb->node_num = %d)\n", 1367 mlog_entry("(node_num=%d, slot_num=%d, osb->node_num = %d)\n",
1293 node_num, osb->node_num); 1368 node_num, slot_num, osb->node_num);
1294
1295 mlog(0, "checking node %d\n", node_num);
1296 1369
1297 /* Should not ever be called to recover ourselves -- in that 1370 /* Should not ever be called to recover ourselves -- in that
1298 * case we should've called ocfs2_journal_load instead. */ 1371 * case we should've called ocfs2_journal_load instead. */
1299 BUG_ON(osb->node_num == node_num); 1372 BUG_ON(osb->node_num == node_num);
1300 1373
1301 slot_num = ocfs2_node_num_to_slot(osb, node_num);
1302 if (slot_num == -ENOENT) {
1303 status = 0;
1304 mlog(0, "no slot for this node, so no recovery required.\n");
1305 goto done;
1306 }
1307
1308 mlog(0, "node %d was using slot %d\n", node_num, slot_num);
1309
1310 status = ocfs2_replay_journal(osb, node_num, slot_num); 1374 status = ocfs2_replay_journal(osb, node_num, slot_num);
1311 if (status < 0) { 1375 if (status < 0) {
1312 if (status == -EBUSY) { 1376 if (status == -EBUSY) {
@@ -1342,7 +1406,7 @@ static int ocfs2_recover_node(struct ocfs2_super *osb,
1342 1406
1343 /* This will kfree the memory pointed to by la_copy and tl_copy */ 1407 /* This will kfree the memory pointed to by la_copy and tl_copy */
1344 ocfs2_queue_recovery_completion(osb->journal, slot_num, la_copy, 1408 ocfs2_queue_recovery_completion(osb->journal, slot_num, la_copy,
1345 tl_copy); 1409 tl_copy, NULL);
1346 1410
1347 status = 0; 1411 status = 0;
1348done: 1412done:
diff --git a/fs/ocfs2/journal.h b/fs/ocfs2/journal.h
index ee08e9c1fc12..37013bf9ce28 100644
--- a/fs/ocfs2/journal.h
+++ b/fs/ocfs2/journal.h
@@ -168,6 +168,7 @@ void ocfs2_recovery_thread(struct ocfs2_super *osb,
168 int node_num); 168 int node_num);
169int ocfs2_mark_dead_nodes(struct ocfs2_super *osb); 169int ocfs2_mark_dead_nodes(struct ocfs2_super *osb);
170void ocfs2_complete_mount_recovery(struct ocfs2_super *osb); 170void ocfs2_complete_mount_recovery(struct ocfs2_super *osb);
171void ocfs2_complete_quota_recovery(struct ocfs2_super *osb);
171 172
172static inline void ocfs2_start_checkpoint(struct ocfs2_super *osb) 173static inline void ocfs2_start_checkpoint(struct ocfs2_super *osb)
173{ 174{
diff --git a/fs/ocfs2/ocfs2.h b/fs/ocfs2/ocfs2.h
index f04b229fc757..6b25b4aa7205 100644
--- a/fs/ocfs2/ocfs2.h
+++ b/fs/ocfs2/ocfs2.h
@@ -206,6 +206,7 @@ enum ocfs2_mount_options
206struct ocfs2_journal; 206struct ocfs2_journal;
207struct ocfs2_slot_info; 207struct ocfs2_slot_info;
208struct ocfs2_recovery_map; 208struct ocfs2_recovery_map;
209struct ocfs2_quota_recovery;
209struct ocfs2_super 210struct ocfs2_super
210{ 211{
211 struct task_struct *commit_task; 212 struct task_struct *commit_task;
@@ -287,10 +288,11 @@ struct ocfs2_super
287 char *local_alloc_debug_buf; 288 char *local_alloc_debug_buf;
288#endif 289#endif
289 290
290 /* Next two fields are for local node slot recovery during 291 /* Next three fields are for local node slot recovery during
291 * mount. */ 292 * mount. */
292 int dirty; 293 int dirty;
293 struct ocfs2_dinode *local_alloc_copy; 294 struct ocfs2_dinode *local_alloc_copy;
295 struct ocfs2_quota_recovery *quota_rec;
294 296
295 struct ocfs2_alloc_stats alloc_stats; 297 struct ocfs2_alloc_stats alloc_stats;
296 char dev_str[20]; /* "major,minor" of the device */ 298 char dev_str[20]; /* "major,minor" of the device */
diff --git a/fs/ocfs2/quota.h b/fs/ocfs2/quota.h
index e2233d51507f..04872b45b990 100644
--- a/fs/ocfs2/quota.h
+++ b/fs/ocfs2/quota.h
@@ -33,6 +33,17 @@ struct ocfs2_dquot {
33 s64 dq_originodes; /* Last globally synced inode usage */ 33 s64 dq_originodes; /* Last globally synced inode usage */
34}; 34};
35 35
36/* Description of one chunk to recover in memory */
37struct ocfs2_recovery_chunk {
38 struct list_head rc_list; /* List of chunks */
39 int rc_chunk; /* Chunk number */
40 unsigned long *rc_bitmap; /* Bitmap of entries to recover */
41};
42
43struct ocfs2_quota_recovery {
44 struct list_head r_list[MAXQUOTAS]; /* List of chunks to recover */
45};
46
36/* In-memory structure with quota header information */ 47/* In-memory structure with quota header information */
37struct ocfs2_mem_dqinfo { 48struct ocfs2_mem_dqinfo {
38 unsigned int dqi_type; /* Quota type this structure describes */ 49 unsigned int dqi_type; /* Quota type this structure describes */
@@ -49,6 +60,10 @@ struct ocfs2_mem_dqinfo {
49 struct buffer_head *dqi_ibh; /* Buffer with information header */ 60 struct buffer_head *dqi_ibh; /* Buffer with information header */
50 struct qtree_mem_dqinfo dqi_gi; /* Info about global file */ 61 struct qtree_mem_dqinfo dqi_gi; /* Info about global file */
51 struct delayed_work dqi_sync_work; /* Work for syncing dquots */ 62 struct delayed_work dqi_sync_work; /* Work for syncing dquots */
63 struct ocfs2_quota_recovery *dqi_rec; /* Pointer to recovery
64 * information, in case we
65 * enable quotas on file
66 * needing it */
52}; 67};
53 68
54static inline struct ocfs2_dquot *OCFS2_DQUOT(struct dquot *dquot) 69static inline struct ocfs2_dquot *OCFS2_DQUOT(struct dquot *dquot)
@@ -67,6 +82,12 @@ extern struct kmem_cache *ocfs2_qf_chunk_cachep;
67 82
68extern struct qtree_fmt_operations ocfs2_global_ops; 83extern struct qtree_fmt_operations ocfs2_global_ops;
69 84
85struct ocfs2_quota_recovery *ocfs2_begin_quota_recovery(
86 struct ocfs2_super *osb, int slot_num);
87int ocfs2_finish_quota_recovery(struct ocfs2_super *osb,
88 struct ocfs2_quota_recovery *rec,
89 int slot_num);
90void ocfs2_free_quota_recovery(struct ocfs2_quota_recovery *rec);
70ssize_t ocfs2_quota_read(struct super_block *sb, int type, char *data, 91ssize_t ocfs2_quota_read(struct super_block *sb, int type, char *data,
71 size_t len, loff_t off); 92 size_t len, loff_t off);
72ssize_t ocfs2_quota_write(struct super_block *sb, int type, 93ssize_t ocfs2_quota_write(struct super_block *sb, int type,
diff --git a/fs/ocfs2/quota_global.c b/fs/ocfs2/quota_global.c
index adf53508bdb8..49b536a2190d 100644
--- a/fs/ocfs2/quota_global.c
+++ b/fs/ocfs2/quota_global.c
@@ -87,7 +87,6 @@ struct qtree_fmt_operations ocfs2_global_ops = {
87 .is_id = ocfs2_global_is_id, 87 .is_id = ocfs2_global_is_id,
88}; 88};
89 89
90
91struct buffer_head *ocfs2_read_quota_block(struct inode *inode, 90struct buffer_head *ocfs2_read_quota_block(struct inode *inode,
92 int block, int *err) 91 int block, int *err)
93{ 92{
diff --git a/fs/ocfs2/quota_local.c b/fs/ocfs2/quota_local.c
index 40e82b483136..b98562174cd0 100644
--- a/fs/ocfs2/quota_local.c
+++ b/fs/ocfs2/quota_local.c
@@ -49,14 +49,25 @@ static unsigned int ol_quota_chunk_block(struct super_block *sb, int c)
49 return 1 + (ol_chunk_blocks(sb) + 1) * c; 49 return 1 + (ol_chunk_blocks(sb) + 1) * c;
50} 50}
51 51
52/* Offset of the dquot structure in the quota file */ 52static unsigned int ol_dqblk_block(struct super_block *sb, int c, int off)
53static loff_t ol_dqblk_off(struct super_block *sb, int c, int off) 53{
54 int epb = ol_quota_entries_per_block(sb);
55
56 return ol_quota_chunk_block(sb, c) + 1 + off / epb;
57}
58
59static unsigned int ol_dqblk_block_off(struct super_block *sb, int c, int off)
54{ 60{
55 int epb = ol_quota_entries_per_block(sb); 61 int epb = ol_quota_entries_per_block(sb);
56 62
57 return ((ol_quota_chunk_block(sb, c) + 1 + off / epb) 63 return (off % epb) * sizeof(struct ocfs2_local_disk_dqblk);
58 << sb->s_blocksize_bits) + 64}
59 (off % epb) * sizeof(struct ocfs2_local_disk_dqblk); 65
66/* Offset of the dquot structure in the quota file */
67static loff_t ol_dqblk_off(struct super_block *sb, int c, int off)
68{
69 return (ol_dqblk_block(sb, c, off) << sb->s_blocksize_bits) +
70 ol_dqblk_block_off(sb, c, off);
60} 71}
61 72
62/* Compute block number from given offset */ 73/* Compute block number from given offset */
@@ -253,6 +264,379 @@ static void olq_update_info(struct buffer_head *bh, void *private)
253 spin_unlock(&dq_data_lock); 264 spin_unlock(&dq_data_lock);
254} 265}
255 266
267static int ocfs2_add_recovery_chunk(struct super_block *sb,
268 struct ocfs2_local_disk_chunk *dchunk,
269 int chunk,
270 struct list_head *head)
271{
272 struct ocfs2_recovery_chunk *rc;
273
274 rc = kmalloc(sizeof(struct ocfs2_recovery_chunk), GFP_NOFS);
275 if (!rc)
276 return -ENOMEM;
277 rc->rc_chunk = chunk;
278 rc->rc_bitmap = kmalloc(sb->s_blocksize, GFP_NOFS);
279 if (!rc->rc_bitmap) {
280 kfree(rc);
281 return -ENOMEM;
282 }
283 memcpy(rc->rc_bitmap, dchunk->dqc_bitmap,
284 (ol_chunk_entries(sb) + 7) >> 3);
285 list_add_tail(&rc->rc_list, head);
286 return 0;
287}
288
289static void free_recovery_list(struct list_head *head)
290{
291 struct ocfs2_recovery_chunk *next;
292 struct ocfs2_recovery_chunk *rchunk;
293
294 list_for_each_entry_safe(rchunk, next, head, rc_list) {
295 list_del(&rchunk->rc_list);
296 kfree(rchunk->rc_bitmap);
297 kfree(rchunk);
298 }
299}
300
301void ocfs2_free_quota_recovery(struct ocfs2_quota_recovery *rec)
302{
303 int type;
304
305 for (type = 0; type < MAXQUOTAS; type++)
306 free_recovery_list(&(rec->r_list[type]));
307 kfree(rec);
308}
309
310/* Load entries in our quota file we have to recover*/
311static int ocfs2_recovery_load_quota(struct inode *lqinode,
312 struct ocfs2_local_disk_dqinfo *ldinfo,
313 int type,
314 struct list_head *head)
315{
316 struct super_block *sb = lqinode->i_sb;
317 struct buffer_head *hbh;
318 struct ocfs2_local_disk_chunk *dchunk;
319 int i, chunks = le32_to_cpu(ldinfo->dqi_chunks);
320 int status = 0;
321
322 for (i = 0; i < chunks; i++) {
323 hbh = ocfs2_read_quota_block(lqinode,
324 ol_quota_chunk_block(sb, i),
325 &status);
326 if (!hbh) {
327 mlog_errno(status);
328 break;
329 }
330 dchunk = (struct ocfs2_local_disk_chunk *)hbh->b_data;
331 if (le32_to_cpu(dchunk->dqc_free) < ol_chunk_entries(sb))
332 status = ocfs2_add_recovery_chunk(sb, dchunk, i, head);
333 brelse(hbh);
334 if (status < 0)
335 break;
336 }
337 if (status < 0)
338 free_recovery_list(head);
339 return status;
340}
341
342static struct ocfs2_quota_recovery *ocfs2_alloc_quota_recovery(void)
343{
344 int type;
345 struct ocfs2_quota_recovery *rec;
346
347 rec = kmalloc(sizeof(struct ocfs2_quota_recovery), GFP_NOFS);
348 if (!rec)
349 return NULL;
350 for (type = 0; type < MAXQUOTAS; type++)
351 INIT_LIST_HEAD(&(rec->r_list[type]));
352 return rec;
353}
354
355/* Load information we need for quota recovery into memory */
356struct ocfs2_quota_recovery *ocfs2_begin_quota_recovery(
357 struct ocfs2_super *osb,
358 int slot_num)
359{
360 unsigned int feature[MAXQUOTAS] = { OCFS2_FEATURE_RO_COMPAT_USRQUOTA,
361 OCFS2_FEATURE_RO_COMPAT_GRPQUOTA};
362 unsigned int ino[MAXQUOTAS] = { LOCAL_USER_QUOTA_SYSTEM_INODE,
363 LOCAL_GROUP_QUOTA_SYSTEM_INODE };
364 struct super_block *sb = osb->sb;
365 struct ocfs2_local_disk_dqinfo *ldinfo;
366 struct inode *lqinode;
367 struct buffer_head *bh;
368 int type;
369 int status = 0;
370 struct ocfs2_quota_recovery *rec;
371
372 mlog(ML_NOTICE, "Beginning quota recovery in slot %u\n", slot_num);
373 rec = ocfs2_alloc_quota_recovery();
374 if (!rec)
375 return ERR_PTR(-ENOMEM);
376 /* First init... */
377
378 for (type = 0; type < MAXQUOTAS; type++) {
379 if (!OCFS2_HAS_RO_COMPAT_FEATURE(sb, feature[type]))
380 continue;
381 /* At this point, journal of the slot is already replayed so
382 * we can trust metadata and data of the quota file */
383 lqinode = ocfs2_get_system_file_inode(osb, ino[type], slot_num);
384 if (!lqinode) {
385 status = -ENOENT;
386 goto out;
387 }
388 status = ocfs2_inode_lock_full(lqinode, NULL, 1,
389 OCFS2_META_LOCK_RECOVERY);
390 if (status < 0) {
391 mlog_errno(status);
392 goto out_put;
393 }
394 /* Now read local header */
395 bh = ocfs2_read_quota_block(lqinode, 0, &status);
396 if (!bh) {
397 mlog_errno(status);
398 mlog(ML_ERROR, "failed to read quota file info header "
399 "(slot=%d type=%d)\n", slot_num, type);
400 goto out_lock;
401 }
402 ldinfo = (struct ocfs2_local_disk_dqinfo *)(bh->b_data +
403 OCFS2_LOCAL_INFO_OFF);
404 status = ocfs2_recovery_load_quota(lqinode, ldinfo, type,
405 &rec->r_list[type]);
406 brelse(bh);
407out_lock:
408 ocfs2_inode_unlock(lqinode, 1);
409out_put:
410 iput(lqinode);
411 if (status < 0)
412 break;
413 }
414out:
415 if (status < 0) {
416 ocfs2_free_quota_recovery(rec);
417 rec = ERR_PTR(status);
418 }
419 return rec;
420}
421
422/* Sync changes in local quota file into global quota file and
423 * reinitialize local quota file.
424 * The function expects local quota file to be already locked and
425 * dqonoff_mutex locked. */
426static int ocfs2_recover_local_quota_file(struct inode *lqinode,
427 int type,
428 struct ocfs2_quota_recovery *rec)
429{
430 struct super_block *sb = lqinode->i_sb;
431 struct ocfs2_mem_dqinfo *oinfo = sb_dqinfo(sb, type)->dqi_priv;
432 struct ocfs2_local_disk_chunk *dchunk;
433 struct ocfs2_local_disk_dqblk *dqblk;
434 struct dquot *dquot;
435 handle_t *handle;
436 struct buffer_head *hbh = NULL, *qbh = NULL;
437 int status = 0;
438 int bit, chunk;
439 struct ocfs2_recovery_chunk *rchunk, *next;
440 qsize_t spacechange, inodechange;
441
442 mlog_entry("ino=%lu type=%u", (unsigned long)lqinode->i_ino, type);
443
444 status = ocfs2_lock_global_qf(oinfo, 1);
445 if (status < 0)
446 goto out;
447
448 list_for_each_entry_safe(rchunk, next, &(rec->r_list[type]), rc_list) {
449 chunk = rchunk->rc_chunk;
450 hbh = ocfs2_read_quota_block(lqinode,
451 ol_quota_chunk_block(sb, chunk),
452 &status);
453 if (!hbh) {
454 mlog_errno(status);
455 break;
456 }
457 dchunk = (struct ocfs2_local_disk_chunk *)hbh->b_data;
458 for_each_bit(bit, rchunk->rc_bitmap, ol_chunk_entries(sb)) {
459 qbh = ocfs2_read_quota_block(lqinode,
460 ol_dqblk_block(sb, chunk, bit),
461 &status);
462 if (!qbh) {
463 mlog_errno(status);
464 break;
465 }
466 dqblk = (struct ocfs2_local_disk_dqblk *)(qbh->b_data +
467 ol_dqblk_block_off(sb, chunk, bit));
468 dquot = dqget(sb, le64_to_cpu(dqblk->dqb_id), type);
469 if (!dquot) {
470 status = -EIO;
471 mlog(ML_ERROR, "Failed to get quota structure "
472 "for id %u, type %d. Cannot finish quota "
473 "file recovery.\n",
474 (unsigned)le64_to_cpu(dqblk->dqb_id),
475 type);
476 goto out_put_bh;
477 }
478 handle = ocfs2_start_trans(OCFS2_SB(sb),
479 OCFS2_QSYNC_CREDITS);
480 if (IS_ERR(handle)) {
481 status = PTR_ERR(handle);
482 mlog_errno(status);
483 goto out_put_dquot;
484 }
485 mutex_lock(&sb_dqopt(sb)->dqio_mutex);
486 spin_lock(&dq_data_lock);
487 /* Add usage from quota entry into quota changes
488 * of our node. Auxiliary variables are important
489 * due to signedness */
490 spacechange = le64_to_cpu(dqblk->dqb_spacemod);
491 inodechange = le64_to_cpu(dqblk->dqb_inodemod);
492 dquot->dq_dqb.dqb_curspace += spacechange;
493 dquot->dq_dqb.dqb_curinodes += inodechange;
494 spin_unlock(&dq_data_lock);
495 /* We want to drop reference held by the crashed
496 * node. Since we have our own reference we know
497 * global structure actually won't be freed. */
498 status = ocfs2_global_release_dquot(dquot);
499 if (status < 0) {
500 mlog_errno(status);
501 goto out_commit;
502 }
503 /* Release local quota file entry */
504 status = ocfs2_journal_access(handle, lqinode,
505 qbh, OCFS2_JOURNAL_ACCESS_WRITE);
506 if (status < 0) {
507 mlog_errno(status);
508 goto out_commit;
509 }
510 lock_buffer(qbh);
511 WARN_ON(!ocfs2_test_bit(bit, dchunk->dqc_bitmap));
512 ocfs2_clear_bit(bit, dchunk->dqc_bitmap);
513 le32_add_cpu(&dchunk->dqc_free, 1);
514 unlock_buffer(qbh);
515 status = ocfs2_journal_dirty(handle, qbh);
516 if (status < 0)
517 mlog_errno(status);
518out_commit:
519 mutex_unlock(&sb_dqopt(sb)->dqio_mutex);
520 ocfs2_commit_trans(OCFS2_SB(sb), handle);
521out_put_dquot:
522 dqput(dquot);
523out_put_bh:
524 brelse(qbh);
525 if (status < 0)
526 break;
527 }
528 brelse(hbh);
529 list_del(&rchunk->rc_list);
530 kfree(rchunk->rc_bitmap);
531 kfree(rchunk);
532 if (status < 0)
533 break;
534 }
535 ocfs2_unlock_global_qf(oinfo, 1);
536out:
537 if (status < 0)
538 free_recovery_list(&(rec->r_list[type]));
539 mlog_exit(status);
540 return status;
541}
542
543/* Recover local quota files for given node different from us */
544int ocfs2_finish_quota_recovery(struct ocfs2_super *osb,
545 struct ocfs2_quota_recovery *rec,
546 int slot_num)
547{
548 unsigned int ino[MAXQUOTAS] = { LOCAL_USER_QUOTA_SYSTEM_INODE,
549 LOCAL_GROUP_QUOTA_SYSTEM_INODE };
550 struct super_block *sb = osb->sb;
551 struct ocfs2_local_disk_dqinfo *ldinfo;
552 struct buffer_head *bh;
553 handle_t *handle;
554 int type;
555 int status = 0;
556 struct inode *lqinode;
557 unsigned int flags;
558
559 mlog(ML_NOTICE, "Finishing quota recovery in slot %u\n", slot_num);
560 mutex_lock(&sb_dqopt(sb)->dqonoff_mutex);
561 for (type = 0; type < MAXQUOTAS; type++) {
562 if (list_empty(&(rec->r_list[type])))
563 continue;
564 mlog(0, "Recovering quota in slot %d\n", slot_num);
565 lqinode = ocfs2_get_system_file_inode(osb, ino[type], slot_num);
566 if (!lqinode) {
567 status = -ENOENT;
568 goto out;
569 }
570 status = ocfs2_inode_lock_full(lqinode, NULL, 1,
571 OCFS2_META_LOCK_NOQUEUE);
572 /* Someone else is holding the lock? Then he must be
573 * doing the recovery. Just skip the file... */
574 if (status == -EAGAIN) {
575 mlog(ML_NOTICE, "skipping quota recovery for slot %d "
576 "because quota file is locked.\n", slot_num);
577 status = 0;
578 goto out_put;
579 } else if (status < 0) {
580 mlog_errno(status);
581 goto out_put;
582 }
583 /* Now read local header */
584 bh = ocfs2_read_quota_block(lqinode, 0, &status);
585 if (!bh) {
586 mlog_errno(status);
587 mlog(ML_ERROR, "failed to read quota file info header "
588 "(slot=%d type=%d)\n", slot_num, type);
589 goto out_lock;
590 }
591 ldinfo = (struct ocfs2_local_disk_dqinfo *)(bh->b_data +
592 OCFS2_LOCAL_INFO_OFF);
593 /* Is recovery still needed? */
594 flags = le32_to_cpu(ldinfo->dqi_flags);
595 if (!(flags & OLQF_CLEAN))
596 status = ocfs2_recover_local_quota_file(lqinode,
597 type,
598 rec);
599 /* We don't want to mark file as clean when it is actually
600 * active */
601 if (slot_num == osb->slot_num)
602 goto out_bh;
603 /* Mark quota file as clean if we are recovering quota file of
604 * some other node. */
605 handle = ocfs2_start_trans(osb, 1);
606 if (IS_ERR(handle)) {
607 status = PTR_ERR(handle);
608 mlog_errno(status);
609 goto out_bh;
610 }
611 status = ocfs2_journal_access(handle, lqinode, bh,
612 OCFS2_JOURNAL_ACCESS_WRITE);
613 if (status < 0) {
614 mlog_errno(status);
615 goto out_trans;
616 }
617 lock_buffer(bh);
618 ldinfo->dqi_flags = cpu_to_le32(flags | OLQF_CLEAN);
619 unlock_buffer(bh);
620 status = ocfs2_journal_dirty(handle, bh);
621 if (status < 0)
622 mlog_errno(status);
623out_trans:
624 ocfs2_commit_trans(osb, handle);
625out_bh:
626 brelse(bh);
627out_lock:
628 ocfs2_inode_unlock(lqinode, 1);
629out_put:
630 iput(lqinode);
631 if (status < 0)
632 break;
633 }
634out:
635 mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex);
636 kfree(rec);
637 return status;
638}
639
256/* Read information header from quota file */ 640/* Read information header from quota file */
257static int ocfs2_local_read_info(struct super_block *sb, int type) 641static int ocfs2_local_read_info(struct super_block *sb, int type)
258{ 642{
@@ -262,6 +646,7 @@ static int ocfs2_local_read_info(struct super_block *sb, int type)
262 struct inode *lqinode = sb_dqopt(sb)->files[type]; 646 struct inode *lqinode = sb_dqopt(sb)->files[type];
263 int status; 647 int status;
264 struct buffer_head *bh = NULL; 648 struct buffer_head *bh = NULL;
649 struct ocfs2_quota_recovery *rec;
265 int locked = 0; 650 int locked = 0;
266 651
267 info->dqi_maxblimit = 0x7fffffffffffffffLL; 652 info->dqi_maxblimit = 0x7fffffffffffffffLL;
@@ -275,6 +660,7 @@ static int ocfs2_local_read_info(struct super_block *sb, int type)
275 info->dqi_priv = oinfo; 660 info->dqi_priv = oinfo;
276 oinfo->dqi_type = type; 661 oinfo->dqi_type = type;
277 INIT_LIST_HEAD(&oinfo->dqi_chunk); 662 INIT_LIST_HEAD(&oinfo->dqi_chunk);
663 oinfo->dqi_rec = NULL;
278 oinfo->dqi_lqi_bh = NULL; 664 oinfo->dqi_lqi_bh = NULL;
279 oinfo->dqi_ibh = NULL; 665 oinfo->dqi_ibh = NULL;
280 666
@@ -305,10 +691,27 @@ static int ocfs2_local_read_info(struct super_block *sb, int type)
305 oinfo->dqi_ibh = bh; 691 oinfo->dqi_ibh = bh;
306 692
307 /* We crashed when using local quota file? */ 693 /* We crashed when using local quota file? */
308 if (!(info->dqi_flags & OLQF_CLEAN)) 694 if (!(info->dqi_flags & OLQF_CLEAN)) {
309 goto out_err; /* So far we just bail out. Later we should resync here */ 695 rec = OCFS2_SB(sb)->quota_rec;
696 if (!rec) {
697 rec = ocfs2_alloc_quota_recovery();
698 if (!rec) {
699 status = -ENOMEM;
700 mlog_errno(status);
701 goto out_err;
702 }
703 OCFS2_SB(sb)->quota_rec = rec;
704 }
310 705
311 status = ocfs2_load_local_quota_bitmaps(sb_dqopt(sb)->files[type], 706 status = ocfs2_recovery_load_quota(lqinode, ldinfo, type,
707 &rec->r_list[type]);
708 if (status < 0) {
709 mlog_errno(status);
710 goto out_err;
711 }
712 }
713
714 status = ocfs2_load_local_quota_bitmaps(lqinode,
312 ldinfo, 715 ldinfo,
313 &oinfo->dqi_chunk); 716 &oinfo->dqi_chunk);
314 if (status < 0) { 717 if (status < 0) {
@@ -394,6 +797,12 @@ static int ocfs2_local_free_info(struct super_block *sb, int type)
394 } 797 }
395 ocfs2_release_local_quota_bitmaps(&oinfo->dqi_chunk); 798 ocfs2_release_local_quota_bitmaps(&oinfo->dqi_chunk);
396 799
800 /* dqonoff_mutex protects us against racing with recovery thread... */
801 if (oinfo->dqi_rec) {
802 ocfs2_free_quota_recovery(oinfo->dqi_rec);
803 mark_clean = 0;
804 }
805
397 if (!mark_clean) 806 if (!mark_clean)
398 goto out; 807 goto out;
399 808