3 * libjio - A library for Journaled I/O
4 * Alberto Bertogli (albertogli@telpin.com.ar)
25 /* fill a transaction structure from a mmapped transaction file */
26 static int fill_trans(unsigned char *map
, off_t len
, struct jtrans
*ts
)
30 struct joper
*op
, *tmp
;
32 if (len
< J_DISKHEADSIZE
)
37 ts
->id
= *( (uint32_t *) p
);
40 ts
->flags
= *( (uint32_t *) p
);
43 ts
->numops
= *( (uint32_t *) p
);
46 for (i
= 0; i
< ts
->numops
; i
++) {
47 if (len
< (p
- map
) + J_DISKOPHEADSIZE
)
50 op
= malloc(sizeof(struct joper
));
54 op
->len
= *( (uint32_t *) p
);
57 op
->plen
= *( (uint32_t *) p
);
60 op
->offset
= *( (uint64_t *) p
);
63 if (len
< (p
- map
) + op
->len
)
76 for(tmp
= ts
->op
; tmp
->next
!= NULL
; tmp
= tmp
->next
)
87 while (ts
->op
!= NULL
) {
95 /* check the journal and rollback incomplete transactions */
96 int jfsck(const char *name
, struct jfsck_result
*res
)
98 int fd
, tfd
, rv
, i
, ret
;
100 uint32_t csum1
, csum2
;
101 char jdir
[PATH_MAX
], jlockfile
[PATH_MAX
], tname
[PATH_MAX
];
104 struct jtrans
*curts
;
118 fd
= open(name
, O_RDWR
| O_SYNC
| O_LARGEFILE
);
125 fs
.name
= (char *) name
;
127 if (!get_jdir(name
, jdir
)) {
131 rv
= lstat(jdir
, &sinfo
);
132 if (rv
< 0 || !S_ISDIR(sinfo
.st_mode
)) {
137 fs
.jdirfd
= open(jdir
, O_RDONLY
);
143 /* open the lock file, which is only used to complete the jfs
145 snprintf(jlockfile
, PATH_MAX
, "%s/%s", jdir
, "lock");
146 rv
= open(jlockfile
, O_RDWR
| O_CREAT
, 0600);
153 fs
.jmap
= (unsigned int *) mmap(NULL
, sizeof(unsigned int),
154 PROT_READ
| PROT_WRITE
, MAP_SHARED
, fs
.jfd
, 0);
155 if (fs
.jmap
== MAP_FAILED
) {
167 /* loop for each file in the journal directory to find out the greater
168 * transaction number */
170 for (dent
= readdir(dir
); dent
!= NULL
; dent
= readdir(dir
)) {
171 /* see if the file is named like a transaction, ignore
172 * otherwise; as transactions are named as numbers > 0, a
173 * simple atoi() is enough testing */
174 rv
= atoi(dent
->d_name
);
181 /* rewrite the lockfile, writing the new maxtid on it, so that when we
182 * rollback a transaction it doesn't step over existing ones */
183 rv
= spwrite(fs
.jfd
, &maxtid
, sizeof(maxtid
), 0);
184 if (rv
!= sizeof(maxtid
)) {
189 /* we loop all the way up to the max transaction id */
190 for (i
= 1; i
<= maxtid
; i
++) {
191 curts
= malloc(sizeof(struct jtrans
));
197 jtrans_init(&fs
, curts
);
200 /* open the transaction file, using i as its name, so we are
201 * really looping in order (recovering transaction in a
202 * different order as they were applied means instant
204 if (!get_jtfile(name
, i
, tname
)) {
208 tfd
= open(tname
, O_RDWR
| O_SYNC
| O_LARGEFILE
, 0600);
214 /* try to lock the transaction file, if it's locked then it is
215 * currently being used so we skip it */
216 rv
= plockf(tfd
, F_TLOCKW
, 0, 0);
222 filelen
= lseek(tfd
, 0, SEEK_END
);
223 map
= mmap(0, filelen
, PROT_READ
, MAP_SHARED
, tfd
, 0);
224 if (map
== MAP_FAILED
) {
229 rv
= fill_trans(map
, filelen
, curts
);
235 /* verify the checksum */
236 csum1
= checksum_map(map
, filelen
- (sizeof(uint32_t)));
237 csum2
= * (uint32_t *) (map
+ filelen
- (sizeof(uint32_t)));
238 if (csum1
!= csum2
) {
243 /* remove flags from the transaction */
246 rv
= jtrans_commit(curts
);
260 munmap(map
, filelen
);
264 while (curts
->op
!= NULL
) {
265 tmpop
= curts
->op
->next
;
266 if (curts
->op
->pdata
)
267 free(curts
->op
->pdata
);
271 pthread_mutex_destroy(&(curts
->lock
));
287 munmap(fs
.jmap
, sizeof(unsigned int));
293 /* remove all the files in the journal directory (if any) */
294 int jfsck_cleanup(const char *name
)
296 char jdir
[PATH_MAX
], tfile
[PATH_MAX
*3];
300 if (!get_jdir(name
, jdir
))
304 if (dir
== NULL
&& errno
== ENOENT
)
305 /* it doesn't exist, so it's clean */
307 else if (dir
== NULL
)
310 for (dent
= readdir(dir
); dent
!= NULL
; dent
= readdir(dir
)) {
311 /* we only care about transactions (named as numbers > 0) and
312 * the lockfile (named "lock"); ignore everything else */
313 if (strcmp(dent
->d_name
, "lock") && atoi(dent
->d_name
) <= 0)
316 /* build the full path to the transaction file */
317 memset(tfile
, 0, PATH_MAX
* 3);
320 strcat(tfile
, dent
->d_name
);
322 /* the full filename is too large */
323 if (strlen(tfile
) > PATH_MAX
) {