Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 9383e745e23602bc45f9c92184feea59 > files > 38

gfs2-utils-0.1.62-28.el5.src.rpm

commit aaaf96f17ca0167f3fad3f2f63b9258d2e3ffcc1
Author: Bob Peterson <bob@ganesha.peterson>
Date:   Fri Jan 22 15:07:19 2010 -0600

    lost+found link count and connections were not properly managed
    
    When the lost+found directory was created, function createi in
    libgfs2 incremented the di_nlink link count for the root directory,
    but fsck.gfs2 did not increment the nlink value in the hash
    table.  As a result, pass4 doesn't find and fix the discrepancy.
    Subsequent runs of fsck.gfs2 detect the problem, though.
    This patch adjusts for the new link and keeps everything sane.
    
    In a similar fashion, if the dinode being moved to lost+found
    happens to be a directory, the links were not properly adjusted
    for that directory's ".." dentry.  This patch also takes care of
    that so the links don't get off.
    
    rhbz#455300

diff --git a/gfs2/fsck/lost_n_found.c b/gfs2/fsck/lost_n_found.c
index d9bed19..7a4d4b3 100644
--- a/gfs2/fsck/lost_n_found.c
+++ b/gfs2/fsck/lost_n_found.c
@@ -40,6 +40,7 @@
 int add_inode_to_lf(struct gfs2_inode *ip){
 	char tmp_name[256];
 	__be32 inode_type;
+	struct dir_info *di;
 
 	if(!lf_dip) {
 		uint8_t q;
@@ -48,6 +49,13 @@ int add_inode_to_lf(struct gfs2_inode *ip){
 
 		lf_dip = createi(ip->i_sbd->md.rooti, "lost+found",
 				 S_IFDIR | 0700, 0);
+		/* createi will have incremented the di_nlink link count for
+		   the root directory.  We must increment the nlink value
+		   in the hash table to keep them in sync so that pass4 can
+		   detect and fix any discrepancies. */
+		set_link_count(ip->i_sbd->sd_sb.sb_root_dir.no_addr,
+			       ip->i_sbd->md.rooti->i_di.di_nlink);
+
 		q = block_type(lf_dip->i_di.di_num.no_addr);
 		if(q != gfs2_inode_dir) {
 			/* This is a new lost+found directory, so set its
@@ -72,6 +80,15 @@ int add_inode_to_lf(struct gfs2_inode *ip){
 				       ip->i_sbd->md.rooti->i_di.di_num.no_addr,
 				       "\"..\"");
 		}
+		log_info( _("lost+found directory is dinode %lld (0x%llx)\n"),
+			  (unsigned long long)lf_dip->i_di.di_num.no_addr,
+			  (unsigned long long)lf_dip->i_di.di_num.no_addr);
+		di = dirtree_find(lf_dip->i_di.di_num.no_addr);
+		if (di) {
+			log_info( _("Marking lost+found inode connected\n"));
+			di->checked = 1;
+			di = NULL;
+		}
 	}
 	if(ip->i_di.di_num.no_addr == lf_dip->i_di.di_num.no_addr) {
 		log_err( _("Trying to add lost+found to itself...skipping"));
@@ -84,6 +101,33 @@ int add_inode_to_lf(struct gfs2_inode *ip){
 			  (unsigned long long)ip->i_di.di_num.no_addr,
 			  (unsigned long long)ip->i_di.di_num.no_addr);
 
+		/* If there's a pre-existing .. directory entry, we have to
+		   back out the links. */
+		di = dirtree_find(ip->i_di.di_num.no_addr);
+		if (di && gfs2_check_range(ip->i_sbd, di->dotdot_parent) == 0){
+			struct gfs2_inode *dip;
+
+			log_debug(_("Directory %lld (0x%llx) already had a "
+				    "\"..\" link to %lld (0x%llx).\n"),
+				  (unsigned long long)ip->i_di.di_num.no_addr,
+				  (unsigned long long)ip->i_di.di_num.no_addr,
+				  (unsigned long long)di->dotdot_parent,
+				  (unsigned long long)di->dotdot_parent);
+			decrement_link(di->dotdot_parent,
+				       ip->i_di.di_num.no_addr,
+				       _(".. unlinked, moving to lost+found"));
+			dip = fsck_load_inode(ip->i_sbd, di->dotdot_parent);
+			dip->i_di.di_nlink--;
+			log_debug(_("Decrementing its links to %d\n"),
+				  dip->i_di.di_nlink);
+			bmodified(dip->i_bh);
+			fsck_inode_put(&dip);
+			di = NULL;
+		} else
+			log_debug(_("Couldn't find a valid \"..\" entry "
+				    "for orphan directory %lld (0x%llx)\n"),
+				  (unsigned long long)ip->i_di.di_num.no_addr,
+				  (unsigned long long)ip->i_di.di_num.no_addr);
 		if(gfs2_dirent_del(ip, "..", 2))
 			log_warn( _("add_inode_to_lf: Unable to remove "
 				    "\"..\" directory entry.\n"));