Line data Source code
1 : #include "clusterautoconfig.h"
2 :
3 : #include <inttypes.h>
4 : #include <stdio.h>
5 : #include <stdlib.h>
6 : #include <string.h>
7 : #include <sys/stat.h>
8 : #include <unistd.h>
9 : #include <dirent.h>
10 : #include <libintl.h>
11 : #define _(String) gettext(String)
12 :
13 : #include <logging.h>
14 : #include "fsck.h"
15 : #include "libgfs2.h"
16 : #include "lost_n_found.h"
17 : #include "link.h"
18 : #include "metawalk.h"
19 : #include "util.h"
20 :
21 0 : static void add_dotdot(struct fsck_cx *cx, struct lgfs2_inode *ip)
22 : {
23 0 : struct lgfs2_sbd *sdp = ip->i_sbd;
24 : struct dir_info *di;
25 : struct lgfs2_inum no;
26 : int err;
27 :
28 0 : log_info(_("Adding .. entry to directory %"PRIu64" (0x%"PRIx64") pointing back to lost+found\n"),
29 : ip->i_num.in_addr, ip->i_num.in_addr);
30 :
31 : /* If there's a pre-existing .. directory entry, we have to
32 : back out the links. */
33 0 : di = dirtree_find(cx, ip->i_num.in_addr);
34 0 : if (di && valid_block(sdp, di->dotdot_parent.in_addr)) {
35 : struct lgfs2_inode *dip;
36 :
37 0 : log_debug(_("Directory (0x%"PRIx64") already had a '..' link to (0x%"PRIx64").\n"),
38 : ip->i_num.in_addr, di->dotdot_parent.in_addr);
39 0 : dip = fsck_load_inode(sdp, di->dotdot_parent.in_addr);
40 0 : if (dip->i_num.in_formal_ino == di->dotdot_parent.in_formal_ino) {
41 0 : decr_link_count(cx, di->dotdot_parent.in_addr, ip->i_num.in_addr,
42 0 : _(".. unlinked, moving to lost+found"));
43 0 : if (dip->i_nlink > 0) {
44 0 : dip->i_nlink--;
45 0 : set_di_nlink(cx, dip); /* keep inode tree in sync */
46 0 : log_debug(_("Decrementing its links to %d\n"),
47 : dip->i_nlink);
48 0 : lgfs2_bmodified(dip->i_bh);
49 0 : } else if (!dip->i_nlink) {
50 0 : log_debug(_("Its link count is zero.\n"));
51 : } else {
52 0 : log_debug(_("Its link count is %d! Changing it to 0.\n"),
53 : dip->i_nlink);
54 0 : dip->i_nlink = 0;
55 0 : set_di_nlink(cx, dip); /* keep inode tree in sync */
56 0 : lgfs2_bmodified(dip->i_bh);
57 : }
58 : } else {
59 0 : log_debug(_("Directory (0x%"PRIx64")'s link to parent "
60 : "(0x%"PRIx64") had a formal inode discrepancy: "
61 : "was 0x%"PRIx64", expected 0x%"PRIx64"\n"),
62 : ip->i_num.in_addr, di->dotdot_parent.in_addr,
63 : di->dotdot_parent.in_formal_ino,
64 : dip->i_num.in_formal_ino);
65 0 : log_debug(_("The parent directory was not changed.\n"));
66 : }
67 0 : fsck_inode_put(&dip);
68 0 : di = NULL;
69 : } else {
70 0 : if (di)
71 0 : log_debug(_("Couldn't find a valid '..' entry "
72 : "for orphan directory (0x%"PRIx64"): "
73 : "'..' = 0x%"PRIx64"\n"),
74 : ip->i_num.in_addr, di->dotdot_parent.in_addr);
75 : else
76 0 : log_debug(_("Couldn't find directory (0x%"PRIx64") "
77 : "in directory tree.\n"),
78 : ip->i_num.in_addr);
79 : }
80 0 : if (lgfs2_dirent_del(ip, "..", 2))
81 0 : log_warn( _("add_inode_to_lf: Unable to remove "
82 : "\"..\" directory entry.\n"));
83 :
84 0 : no = lf_dip->i_num;
85 0 : err = lgfs2_dir_add(ip, "..", 2, &no, DT_DIR);
86 0 : if (err) {
87 0 : log_crit(_("Error adding .. directory: %s\n"),
88 : strerror(errno));
89 0 : exit(FSCK_ERROR);
90 : }
91 0 : }
92 :
93 0 : void make_sure_lf_exists(struct fsck_cx *cx, struct lgfs2_inode *ip)
94 : {
95 : struct dir_info *di;
96 0 : struct lgfs2_sbd *sdp = ip->i_sbd;
97 : int root_entries;
98 :
99 0 : if (lf_dip)
100 0 : return;
101 :
102 0 : root_entries = sdp->md.rooti->i_entries;
103 0 : log_info( _("Locating/Creating lost+found directory\n"));
104 0 : lf_dip = lgfs2_createi(sdp->md.rooti, "lost+found", S_IFDIR|0700, 0);
105 0 : if (lf_dip == NULL) {
106 0 : log_crit(_("Error creating lost+found: %s\n"),
107 : strerror(errno));
108 0 : exit(FSCK_ERROR);
109 : }
110 :
111 : /* lgfs2_createi will have incremented the di_nlink link count for the root
112 : directory. We must set the nlink value in the hash table to keep
113 : them in sync so that pass4 can detect and fix any descrepancies. */
114 0 : set_di_nlink(cx, sdp->md.rooti);
115 :
116 0 : if (sdp->md.rooti->i_entries > root_entries) {
117 0 : struct lgfs2_inum no = lf_dip->i_num;
118 0 : lf_was_created = 1;
119 : /* This is a new lost+found directory, so set its block type
120 : and increment link counts for the directories */
121 : /* FIXME: i'd feel better about this if fs_mkdir returned
122 : whether it created a new directory or just found an old one,
123 : and we used that instead of the bitmap_type to run this */
124 0 : dirtree_insert(cx, no);
125 : /* Set the bitmap AFTER the dirtree insert so that function
126 : check_n_fix_bitmap will realize it's a dinode and adjust
127 : the rgrp counts properly. */
128 0 : fsck_bitmap_set(cx, ip, lf_dip->i_num.in_addr, _("lost+found dinode"), GFS2_BLKST_DINODE);
129 : /* root inode links to lost+found */
130 0 : no.in_addr = sdp->md.rooti->i_num.in_addr;
131 0 : no.in_formal_ino = sdp->md.rooti->i_num.in_formal_ino;
132 0 : incr_link_count(cx, no, lf_dip, _("root"));
133 : /* lost+found link for '.' from itself */
134 0 : no.in_addr = lf_dip->i_num.in_addr;
135 0 : no.in_formal_ino = lf_dip->i_num.in_formal_ino;
136 0 : incr_link_count(cx, no, lf_dip, "\".\"");
137 : /* lost+found link for '..' back to root */
138 0 : incr_link_count(cx, no, sdp->md.rooti, "\"..\"");
139 : }
140 0 : log_info(_("lost+found directory is dinode %"PRIu64" (0x%"PRIx64")\n"),
141 : lf_dip->i_num.in_addr, lf_dip->i_num.in_addr);
142 0 : di = dirtree_find(cx, lf_dip->i_num.in_addr);
143 0 : if (di) {
144 0 : log_info( _("Marking lost+found inode connected\n"));
145 0 : di->checked = 1;
146 0 : di = NULL;
147 : }
148 : }
149 :
150 : /* add_inode_to_lf - Add dir entry to lost+found for the inode
151 : * @ip: inode to add to lost + found
152 : *
153 : * This function adds an entry into the lost and found dir
154 : * for the given inode. The name of the entry will be
155 : * "lost_<ip->i_num.no_addr>".
156 : *
157 : * Returns: 0 on success, -1 on failure.
158 : */
159 0 : int add_inode_to_lf(struct fsck_cx *cx, struct lgfs2_inode *ip)
160 : {
161 : char tmp_name[256];
162 : unsigned inode_type;
163 : struct lgfs2_inum no;
164 0 : int err = 0;
165 : uint32_t mode;
166 :
167 0 : make_sure_lf_exists(cx, ip);
168 0 : if (ip->i_num.in_addr == lf_dip->i_num.in_addr) {
169 0 : log_err( _("Trying to add lost+found to itself...skipping"));
170 0 : return 0;
171 : }
172 :
173 0 : mode = ip->i_mode & S_IFMT;
174 :
175 0 : switch (mode) {
176 0 : case S_IFDIR:
177 0 : add_dotdot(cx, ip);
178 0 : sprintf(tmp_name, "lost_dir_%"PRIu64, ip->i_num.in_addr);
179 0 : inode_type = DT_DIR;
180 0 : break;
181 0 : case S_IFREG:
182 0 : sprintf(tmp_name, "lost_file_%"PRIu64, ip->i_num.in_addr);
183 0 : inode_type = DT_REG;
184 0 : break;
185 0 : case S_IFLNK:
186 0 : sprintf(tmp_name, "lost_link_%"PRIu64, ip->i_num.in_addr);
187 0 : inode_type = DT_LNK;
188 0 : break;
189 0 : case S_IFBLK:
190 0 : sprintf(tmp_name, "lost_blkdev_%"PRIu64, ip->i_num.in_addr);
191 0 : inode_type = DT_BLK;
192 0 : break;
193 0 : case S_IFCHR:
194 0 : sprintf(tmp_name, "lost_chrdev_%"PRIu64, ip->i_num.in_addr);
195 0 : inode_type = DT_CHR;
196 0 : break;
197 0 : case S_IFIFO:
198 0 : sprintf(tmp_name, "lost_fifo_%"PRIu64, ip->i_num.in_addr);
199 0 : inode_type = DT_FIFO;
200 0 : break;
201 0 : case S_IFSOCK:
202 0 : sprintf(tmp_name, "lost_socket_%"PRIu64, ip->i_num.in_addr);
203 0 : inode_type = DT_SOCK;
204 0 : break;
205 0 : default:
206 0 : sprintf(tmp_name, "lost_%"PRIu64, ip->i_num.in_addr);
207 0 : inode_type = DT_REG;
208 0 : break;
209 : }
210 :
211 0 : no = ip->i_num;
212 0 : err = lgfs2_dir_add(lf_dip, tmp_name, strlen(tmp_name), &no, inode_type);
213 0 : if (err) {
214 0 : log_crit(_("Error adding directory %s: %s\n"),
215 : tmp_name, strerror(errno));
216 0 : exit(FSCK_ERROR);
217 : }
218 :
219 : /* This inode is linked from lost+found */
220 0 : incr_link_count(cx, no, lf_dip, _("from lost+found"));
221 : /* If it's a directory, lost+found is back-linked to it via .. */
222 0 : if (mode == S_IFDIR) {
223 0 : no = lf_dip->i_num;
224 0 : incr_link_count(cx, no, ip, _("to lost+found"));
225 : }
226 0 : log_notice(_("Added inode #%"PRIu64" (0x%"PRIx64") to lost+found\n"),
227 : ip->i_num.in_addr, ip->i_num.in_addr);
228 0 : lgfs2_dinode_out(lf_dip, lf_dip->i_bh->b_data);
229 0 : lgfs2_bwrite(lf_dip->i_bh);
230 0 : return 0;
231 : }
|