Skip to content

Commit bedb0f0

Browse files
Abhi DasAndreas Gruenbacher
authored andcommitted
gfs2: Recover statfs info in journal head
Apply the outstanding statfs changes in the journal head to the master statfs file. Zero out the local statfs file for good measure. Previously, statfs updates would be read in from the local statfs inode and synced to the master statfs inode during recovery. We now use the statfs updates in the journal head to update the master statfs inode instead of reading in from the local statfs inode. To preserve backward compatibility with kernels that can't do this, we still need to keep the local statfs inode up to date by writing changes to it. At some point in the future, we can do away with the local statfs inodes altogether and keep the statfs changes solely in the journal. Signed-off-by: Abhi Das <adas@redhat.com> Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
1 parent 97fd734 commit bedb0f0

3 files changed

Lines changed: 106 additions & 1 deletion

File tree

fs/gfs2/lops.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -823,7 +823,7 @@ static int buf_lo_scan_elements(struct gfs2_jdesc *jd, u32 start,
823823
*
824824
*/
825825

826-
static void gfs2_meta_sync(struct gfs2_glock *gl)
826+
void gfs2_meta_sync(struct gfs2_glock *gl)
827827
{
828828
struct address_space *mapping = gfs2_glock2aspace(gl);
829829
struct gfs2_sbd *sdp = gl->gl_name.ln_sbd;

fs/gfs2/lops.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ extern void gfs2_log_submit_bio(struct bio **biop, int opf);
2727
extern void gfs2_pin(struct gfs2_sbd *sdp, struct buffer_head *bh);
2828
extern int gfs2_find_jhead(struct gfs2_jdesc *jd,
2929
struct gfs2_log_header_host *head, bool keep_cache);
30+
extern void gfs2_meta_sync(struct gfs2_glock *gl);
3031

3132
static inline unsigned int buf_limit(struct gfs2_sbd *sdp)
3233
{

fs/gfs2/recovery.c

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,109 @@ static void gfs2_recovery_done(struct gfs2_sbd *sdp, unsigned int jid,
296296
sdp->sd_lockstruct.ls_ops->lm_recovery_result(sdp, jid, message);
297297
}
298298

299+
/**
300+
* update_statfs_inode - Update the master statfs inode or zero out the local
301+
* statfs inode for a given journal.
302+
* @jd: The journal
303+
* @head: If NULL, @inode is the local statfs inode and we need to zero it out.
304+
* Otherwise, it @head contains the statfs change info that needs to be
305+
* synced to the master statfs inode (pointed to by @inode).
306+
* @inode: statfs inode to update.
307+
*/
308+
static int update_statfs_inode(struct gfs2_jdesc *jd,
309+
struct gfs2_log_header_host *head,
310+
struct inode *inode)
311+
{
312+
struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode);
313+
struct gfs2_inode *ip;
314+
struct buffer_head *bh;
315+
struct gfs2_statfs_change_host sc;
316+
int error = 0;
317+
318+
BUG_ON(!inode);
319+
ip = GFS2_I(inode);
320+
321+
error = gfs2_meta_inode_buffer(ip, &bh);
322+
if (error)
323+
goto out;
324+
325+
spin_lock(&sdp->sd_statfs_spin);
326+
327+
if (head) { /* Update the master statfs inode */
328+
gfs2_statfs_change_in(&sc, bh->b_data + sizeof(struct gfs2_dinode));
329+
sc.sc_total += head->lh_local_total;
330+
sc.sc_free += head->lh_local_free;
331+
sc.sc_dinodes += head->lh_local_dinodes;
332+
gfs2_statfs_change_out(&sc, bh->b_data + sizeof(struct gfs2_dinode));
333+
334+
fs_info(sdp, "jid=%u: Updated master statfs Total:%lld, "
335+
"Free:%lld, Dinodes:%lld after change "
336+
"[%+lld,%+lld,%+lld]\n", jd->jd_jid, sc.sc_total,
337+
sc.sc_free, sc.sc_dinodes, head->lh_local_total,
338+
head->lh_local_free, head->lh_local_dinodes);
339+
} else { /* Zero out the local statfs inode */
340+
memset(bh->b_data + sizeof(struct gfs2_dinode), 0,
341+
sizeof(struct gfs2_statfs_change));
342+
/* If it's our own journal, reset any in-memory changes too */
343+
if (jd->jd_jid == sdp->sd_lockstruct.ls_jid) {
344+
memset(&sdp->sd_statfs_local, 0,
345+
sizeof(struct gfs2_statfs_change_host));
346+
}
347+
}
348+
spin_unlock(&sdp->sd_statfs_spin);
349+
350+
mark_buffer_dirty(bh);
351+
brelse(bh);
352+
gfs2_meta_sync(ip->i_gl);
353+
354+
out:
355+
return error;
356+
}
357+
358+
/**
359+
* recover_local_statfs - Update the master and local statfs changes for this
360+
* journal.
361+
*
362+
* Previously, statfs updates would be read in from the local statfs inode and
363+
* synced to the master statfs inode during recovery.
364+
*
365+
* We now use the statfs updates in the journal head to update the master statfs
366+
* inode instead of reading in from the local statfs inode. To preserve backward
367+
* compatibility with kernels that can't do this, we still need to keep the
368+
* local statfs inode up to date by writing changes to it. At some point in the
369+
* future, we can do away with the local statfs inodes altogether and keep the
370+
* statfs changes solely in the journal.
371+
*
372+
* @jd: the journal
373+
* @head: the journal head
374+
*
375+
* Returns: errno
376+
*/
377+
static void recover_local_statfs(struct gfs2_jdesc *jd,
378+
struct gfs2_log_header_host *head)
379+
{
380+
int error;
381+
struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode);
382+
383+
if (!head->lh_local_total && !head->lh_local_free
384+
&& !head->lh_local_dinodes) /* No change */
385+
goto zero_local;
386+
387+
/* First update the master statfs inode with the changes we
388+
* found in the journal. */
389+
error = update_statfs_inode(jd, head, sdp->sd_statfs_inode);
390+
if (error)
391+
goto out;
392+
393+
zero_local:
394+
/* Zero out the local statfs inode so any changes in there
395+
* are not re-recovered. */
396+
error = update_statfs_inode(jd, NULL,
397+
find_local_statfs_inode(sdp, jd->jd_jid));
398+
out:
399+
return;
400+
}
401+
299402
void gfs2_recover_func(struct work_struct *work)
300403
{
301404
struct gfs2_jdesc *jd = container_of(work, struct gfs2_jdesc, jd_work);
@@ -415,6 +518,7 @@ void gfs2_recover_func(struct work_struct *work)
415518
goto fail_gunlock_thaw;
416519
}
417520

521+
recover_local_statfs(jd, &head);
418522
clean_journal(jd, &head);
419523
up_read(&sdp->sd_log_flush_lock);
420524

0 commit comments

Comments
 (0)