00001
00002
00003
00004
00005
00006 #include <sys/types.h>
00007 #include <sys/stat.h>
00008 #include <fcntl.h>
00009 #include <unistd.h>
00010 #include <stdlib.h>
00011 #include <limits.h>
00012 #include <string.h>
00013 #include <stdio.h>
00014 #include <dirent.h>
00015 #include <errno.h>
00016 #include <sys/mman.h>
00017
00018 #include "libjio.h"
00019 #include "common.h"
00020 #include "journal.h"
00021 #include "trans.h"
00022
00023
00030 static int jfsck_cleanup(const char *name, const char *jdir)
00031 {
00032 char tfile[PATH_MAX*3];
00033 DIR *dir;
00034 struct dirent *dent;
00035
00036 dir = opendir(jdir);
00037 if (dir == NULL && errno == ENOENT)
00038
00039 return 0;
00040 else if (dir == NULL)
00041 return -1;
00042
00043 for (errno = 0, dent = readdir(dir); dent != NULL;
00044 errno = 0, dent = readdir(dir)) {
00045
00046
00047
00048 if (strcmp(dent->d_name, "lock"))
00049 continue;
00050
00051
00052 memset(tfile, 0, PATH_MAX * 3);
00053 strcat(tfile, jdir);
00054 strcat(tfile, "/");
00055 strcat(tfile, dent->d_name);
00056
00057 if (strlen(tfile) > PATH_MAX) {
00058 closedir(dir);
00059 return -1;
00060 }
00061
00062 if (unlink(tfile) != 0) {
00063 closedir(dir);
00064 return -1;
00065 }
00066 }
00067
00068 if (errno) {
00069 closedir(dir);
00070 return -1;
00071 }
00072
00073 if (closedir(dir) != 0)
00074 return -1;
00075
00076 if (rmdir(jdir) != 0)
00077 return -1;
00078
00079 return 0;
00080 }
00081
00082
00083 enum jfsck_return jfsck(const char *name, const char *jdir,
00084 struct jfsck_result *res, unsigned int flags)
00085 {
00086 int tfd, rv, i, ret;
00087 unsigned int maxtid;
00088 char jlockfile[PATH_MAX], tname[PATH_MAX], brokenname[PATH_MAX];
00089 struct stat sinfo;
00090 struct jfs fs;
00091 struct jtrans *curts;
00092 struct operation *tmpop;
00093 DIR *dir;
00094 struct dirent *dent;
00095 unsigned char *map;
00096 off_t filelen, lr;
00097
00098 tfd = -1;
00099 filelen = 0;
00100 dir = NULL;
00101 fs.fd = -1;
00102 fs.jfd = -1;
00103 fs.jdir = NULL;
00104 fs.jdirfd = -1;
00105 fs.jmap = MAP_FAILED;
00106 map = NULL;
00107 ret = 0;
00108
00109 res->total = 0;
00110 res->invalid = 0;
00111 res->in_progress = 0;
00112 res->broken = 0;
00113 res->corrupt = 0;
00114 res->reapplied = 0;
00115
00116 fs.fd = open(name, O_RDWR | O_SYNC);
00117 if (fs.fd < 0) {
00118 ret = J_EIO;
00119 if (errno == ENOENT)
00120 ret = J_ENOENT;
00121 goto exit;
00122 }
00123
00124 fs.name = (char *) name;
00125
00126 if (jdir == NULL) {
00127 fs.jdir = (char *) malloc(PATH_MAX);
00128 if (fs.jdir == NULL) {
00129 ret = J_ENOMEM;
00130 goto exit;
00131 }
00132
00133 if (!get_jdir(name, fs.jdir)) {
00134 ret = J_ENOMEM;
00135 goto exit;
00136 }
00137 } else {
00138 fs.jdir = strdup(jdir);
00139 if (fs.jdir == NULL) {
00140 ret = J_ENOMEM;
00141 goto exit;
00142 }
00143 }
00144
00145 rv = lstat(fs.jdir, &sinfo);
00146 if (rv < 0) {
00147 ret = J_EIO;
00148 if (errno == ENOENT)
00149 ret = J_ENOJOURNAL;
00150 goto exit;
00151 }
00152 if (!S_ISDIR(sinfo.st_mode)) {
00153 ret = J_ENOJOURNAL;
00154 goto exit;
00155 }
00156
00157 fs.jdirfd = open(fs.jdir, O_RDONLY);
00158 if (fs.jdirfd < 0) {
00159 ret = J_EIO;
00160 if (errno == ENOENT)
00161 ret = J_ENOJOURNAL;
00162 goto exit;
00163 }
00164
00165
00166
00167 snprintf(jlockfile, PATH_MAX, "%s/%s", fs.jdir, "lock");
00168 rv = open(jlockfile, O_RDWR | O_CREAT, 0600);
00169 if (rv < 0) {
00170 ret = J_EIO;
00171 if (errno == ENOENT)
00172 ret = J_ENOJOURNAL;
00173 goto exit;
00174 }
00175 fs.jfd = rv;
00176
00177 fs.jmap = (unsigned int *) mmap(NULL, sizeof(unsigned int),
00178 PROT_READ | PROT_WRITE, MAP_SHARED, fs.jfd, 0);
00179 if (fs.jmap == MAP_FAILED) {
00180 ret = J_EIO;
00181 goto exit;
00182 }
00183
00184 dir = opendir(fs.jdir);
00185 if (dir == NULL) {
00186 ret = J_EIO;
00187 if (errno == ENOENT)
00188 ret = J_ENOJOURNAL;
00189 goto exit;
00190 }
00191
00192
00193
00194 maxtid = 0;
00195 for (errno = 0, dent = readdir(dir); dent != NULL;
00196 errno = 0, dent = readdir(dir)) {
00197
00198
00199
00200 rv = atoi(dent->d_name);
00201 if (rv <= 0)
00202 continue;
00203 if (rv > maxtid)
00204 maxtid = rv;
00205 }
00206 if (errno) {
00207 ret = J_EIO;
00208 goto exit;
00209 }
00210
00211
00212
00213 rv = spwrite(fs.jfd, &maxtid, sizeof(maxtid), 0);
00214 if (rv != sizeof(maxtid)) {
00215 ret = J_ENOMEM;
00216 goto exit;
00217 }
00218
00219
00220 snprintf(brokenname, PATH_MAX, "%s/broken", fs.jdir);
00221 rv = access(brokenname, F_OK);
00222 if (rv == 0) {
00223 if (unlink(brokenname) != 0) {
00224 ret = J_EIO;
00225 goto exit;
00226 }
00227 } else if (errno != ENOENT) {
00228 ret = J_EIO;
00229 goto exit;
00230 }
00231
00232
00233 for (i = 1; i <= maxtid; i++) {
00234 curts = jtrans_new(&fs, 0);
00235 if (curts == NULL) {
00236 ret = J_ENOMEM;
00237 goto exit;
00238 }
00239
00240 curts->id = i;
00241
00242
00243
00244
00245
00246 get_jtfile(&fs, i, tname);
00247 tfd = open(tname, O_RDWR | O_SYNC, 0600);
00248 if (tfd < 0) {
00249 if (errno == ENOENT) {
00250 res->invalid++;
00251 goto nounlink_loop;
00252 } else {
00253 ret = J_EIO;
00254 goto exit;
00255 }
00256 }
00257
00258
00259
00260 lr = plockf(tfd, F_TLOCKW, 0, 0);
00261 if (lr == -1) {
00262 res->in_progress++;
00263 goto loop;
00264 }
00265
00266 filelen = lseek(tfd, 0, SEEK_END);
00267 if (filelen == 0) {
00268 res->broken++;
00269 goto loop;
00270 } else if (filelen < 0) {
00271 ret = J_EIO;
00272 goto exit;
00273 }
00274
00275
00276
00277 map = mmap((void *) 0, filelen, PROT_READ, MAP_SHARED, tfd, 0);
00278 if (map == MAP_FAILED) {
00279 map = NULL;
00280 ret = J_EIO;
00281 goto exit;
00282 }
00283
00284 rv = fill_trans(map, filelen, curts);
00285 if (rv == -1) {
00286 res->broken++;
00287 goto loop;
00288 } else if (rv == -2) {
00289 res->corrupt++;
00290 goto loop;
00291 }
00292
00293
00294
00295 curts->flags = 0;
00296
00297 rv = jtrans_commit(curts);
00298
00299 if (rv < 0) {
00300 ret = J_EIO;
00301 goto exit;
00302 }
00303 res->reapplied++;
00304
00305 loop:
00306 if (unlink(tname) != 0) {
00307 ret = J_EIO;
00308 goto exit;
00309 }
00310
00311 nounlink_loop:
00312 if (tfd >= 0) {
00313 close(tfd);
00314 tfd = -1;
00315 }
00316 if (map != NULL)
00317 munmap(map, filelen);
00318
00319 while (curts->op != NULL) {
00320 tmpop = curts->op->next;
00321 if (curts->op->pdata)
00322 free(curts->op->pdata);
00323 free(curts->op);
00324 curts->op = tmpop;
00325 }
00326 pthread_mutex_destroy(&(curts->lock));
00327 free(curts);
00328
00329 res->total++;
00330 }
00331
00332 if (flags & J_CLEANUP) {
00333 if (jfsck_cleanup(name, fs.jdir) < 0) {
00334 ret = J_ECLEANUP;
00335 }
00336 }
00337
00338 exit:
00339 if (fs.fd >= 0)
00340 close(fs.fd);
00341 if (fs.jfd >= 0)
00342 close(fs.jfd);
00343 if (fs.jdirfd >= 0)
00344 close(fs.jdirfd);
00345 if (fs.jdir)
00346 free(fs.jdir);
00347 if (dir != NULL)
00348 closedir(dir);
00349 if (fs.jmap != MAP_FAILED)
00350 munmap(fs.jmap, sizeof(unsigned int));
00351
00352 return ret;
00353 }
00354