| 0/0 |
2026/05/11 22:53 |
flow |
patching-compressed |
1h56m
Results: map[Fixes:map[Hash:1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 Title:Linux-2.6.12-rc2] KernelBranch:master KernelCommit:5d6919055dec134de3c40167a490f33c74c12581 KernelRepo:git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git PatchDescription:jfs: fix use-after-free in jfs_lazycommit during unmount
An analysis of a KASAN slab-use-after-free crash reveals a race
condition during the unmounting of a JFS filesystem. When a JFS
filesystem is unmounted, jfs_umount() calls jfs_flush_journal() to flush
all outstanding transactions to disk. jfs_flush_journal() waits until
the commit queue and the sync list are empty, but it does not wait for
the unlock queue to be processed by the jfs_lazycommit background
thread.
Because jfs_flush_journal() only waits for the commit queue to drain, it
can return while transactions are still sitting in the unlock queue or
are actively being processed by jfs_lazycommit. After
jfs_flush_journal() returns, jfs_umount() proceeds to tear down the
filesystem, freeing the allocation maps and the jfs_log structure.
Meanwhile, the jfs_lazycommit thread wakes up, pops the transaction from
the unlock queue, and accesses the now-freed allocation maps and log
structure, eventually causing a use-after-free crash in lmLogSync().
To fix this, introduce txLazyCommitWait() to ensure that jfs_lazycommit
has completely finished processing all transactions for the unmounting
superblock before jfs_umount() proceeds to free the filesystem
structures. This function synchronizes with lmPostGC() to ensure all
transactions removed from the commit queue have been added to the unlock
queue, and then waits until the unlock queue is empty and the lazycommit
thread is no longer active for the given superblock. Invoke this wait
function immediately after jfs_flush_journal() in both jfs_umount() and
jfs_umount_rw(). PatchDiff:diff --git a/fs/jfs/jfs_txnmgr.c b/fs/jfs/jfs_txnmgr.c
index 083dbbb0c..823250c3c 100644
--- a/fs/jfs/jfs_txnmgr.c
+++ b/fs/jfs/jfs_txnmgr.c
@@ -37,6 +37,7 @@
#include <linux/moduleparam.h>
#include <linux/kthread.h>
#include <linux/seq_file.h>
+#include <linux/delay.h>
#include "jfs_incore.h"
#include "jfs_inode.h"
#include "jfs_filsys.h"
@@ -2772,6 +2773,49 @@ int jfs_lazycommit(void *arg)
return 0;
}
+/*
+ * Wait for lazycommit thread to finish processing all transactions
+ * for the given superblock.
+ */
+void txLazyCommitWait(struct super_block *sb)
+{
+ struct jfs_sb_info *sbi = JFS_SBI(sb);
+ struct jfs_log *log = sbi->log;
+ unsigned long flags;
+ struct tblock *tblk;
+ int found;
+
+ if (!log)
+ return;
+
+ /*
+ * Synchronize with lmPostGC to ensure that all transactions
+ * removed from cqueue have been added to unlock_queue.
+ */
+ spin_lock_irqsave(&log->gclock, flags);
+ spin_unlock_irqrestore(&log->gclock, flags);
+
+ do {
+ found = 0;
+ LAZY_LOCK(flags);
+ if (sbi->commit_state & IN_LAZYCOMMIT)
+ found = 1;
+ else {
+ list_for_each_entry(tblk, &TxAnchor.unlock_queue,
+ cqueue) {
+ if (tblk->sb == sb) {
+ found = 1;
+ break;
+ }
+ }
+ }
+ LAZY_UNLOCK(flags);
+
+ if (found)
+ msleep(10);
+ } while (found);
+}
+
void txLazyUnlock(struct tblock * tblk)
{
unsigned long flags;
diff --git a/fs/jfs/jfs_txnmgr.h b/fs/jfs/jfs_txnmgr.h
index ba71eb5ce..3b3272ded 100644
--- a/fs/jfs/jfs_txnmgr.h
+++ b/fs/jfs/jfs_txnmgr.h
@@ -295,4 +295,5 @@ extern void txResume(struct super_block *);
extern void txLazyUnlock(struct tblock *);
extern int jfs_lazycommit(void *);
extern int jfs_sync(void *);
+extern void txLazyCommitWait(struct super_block *sb);
#endif /* _H_JFS_TXNMGR */
diff --git a/fs/jfs/jfs_umount.c b/fs/jfs/jfs_umount.c
index 18569f1ea..1aca20b1d 100644
--- a/fs/jfs/jfs_umount.c
+++ b/fs/jfs/jfs_umount.c
@@ -21,6 +21,7 @@
#include "jfs_dmap.h"
#include "jfs_imap.h"
#include "jfs_logmgr.h"
+#include "jfs_txnmgr.h"
#include "jfs_metapage.h"
#include "jfs_debug.h"
@@ -52,11 +53,13 @@ int jfs_umount(struct super_block *sb)
*
* if mounted read-write and log based recovery was enabled
*/
- if ((log = sbi->log))
+ if ((log = sbi->log)) {
/*
* Wait for outstanding transactions to be written to log:
*/
jfs_flush_journal(log, 2);
+ txLazyCommitWait(sb);
+ }
/*
* Hold log lock so write_special_inodes (lmLogSync) cannot see
@@ -142,6 +145,7 @@ int jfs_umount_rw(struct super_block *sb)
* remove file system from log active file system list.
*/
jfs_flush_journal(log, 2);
+ txLazyCommitWait(sb);
/*
* Make sure all metadata makes it to disk
Recipients:[map[Email:jfs-discussion@lists.sourceforge.net Name: To:true] map[Email:linux-kernel@vger.kernel.org Name: To:false] map[Email:shaggy@kernel.org Name:Dave Kleikamp To:true]]]
|
| 1/1 |
2026/05/11 22:53 |
action |
base-commit-picker |
0m
Results: map[KernelBranch:master KernelCommit:5d6919055dec134de3c40167a490f33c74c12581 KernelRepo:git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git]
|
| 2/1 |
2026/05/11 22:53 |
action |
syz-repro-to-c-repro |
0m
Results: map[SimplifiedCRepro:// autogenerated by syzkaller (https://github.com/google/syzkaller)
#define _GNU_SOURCE
#include <endian.h>
#include <errno.h>
#include <fcntl.h>
#include <setjmp.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>
#include <linux/loop.h>
#ifndef __NR_memfd_create
#define __NR_memfd_create 319
#endif
static unsigned long long procid;
//% This code is derived from puff.{c,h}, found in the zlib development. The
//% original files come with the following copyright notice:
//% Copyright (C) 2002-2013 Mark Adler, all rights reserved
//% version 2.3, 21 Jan 2013
//% This software is provided 'as-is', without any express or implied
//% warranty. In no event will the author be held liable for any damages
//% arising from the use of this software.
//% Permission is granted to anyone to use this software for any purpose,
//% including commercial applications, and to alter it and redistribute it
//% freely, subject to the following restrictions:
//% 1. The origin of this software must not be misrepresented; you must not
//% claim that you wrote the original software. If you use this software
//% in a product, an acknowledgment in the product documentation would be
//% appreciated but is not required.
//% 2. Altered source versions must be plainly marked as such, and must not be
//% misrepresented as being the original software.
//% 3. This notice may not be removed or altered from any source distribution.
//% Mark Adler madler@alumni.caltech.edu
//% BEGIN CODE DERIVED FROM puff.{c,h}
#define MAXBITS 15
#define MAXLCODES 286
#define MAXDCODES 30
#define MAXCODES (MAXLCODES + MAXDCODES)
#define FIXLCODES 288
struct puff_state {
unsigned char* out;
unsigned long outlen;
unsigned long outcnt;
const unsigned char* in;
unsigned long inlen;
unsigned long incnt;
int bitbuf;
int bitcnt;
jmp_buf env;
};
static int puff_bits(struct puff_state* s, int need)
{
long val = s->bitbuf;
while (s->bitcnt < need) {
if (s->incnt == s->inlen)
longjmp(s->env, 1);
val |= (long)(s->in[s->incnt++]) << s->bitcnt;
s->bitcnt += 8;
}
s->bitbuf = (int)(val >> need);
s->bitcnt -= need;
return (int)(val & ((1L << need) - 1));
}
static int puff_stored(struct puff_state* s)
{
s->bitbuf = 0;
s->bitcnt = 0;
if (s->incnt + 4 > s->inlen)
return 2;
unsigned len = s->in[s->incnt++];
len |= s->in[s->incnt++] << 8;
if (s->in[s->incnt++] != (~len & 0xff) ||
s->in[s->incnt++] != ((~len >> 8) & 0xff))
return -2;
if (s->incnt + len > s->inlen)
return 2;
if (s->outcnt + len > s->outlen)
return 1;
for (; len--; s->outcnt++, s->incnt++) {
if (s->in[s->incnt])
s->out[s->outcnt] = s->in[s->incnt];
}
return 0;
}
struct puff_huffman {
short* count;
short* symbol;
};
static int puff_decode(struct puff_state* s, const struct puff_huffman* h)
{
int first = 0;
int index = 0;
int bitbuf = s->bitbuf;
int left = s->bitcnt;
int code = first = index = 0;
int len = 1;
short* next = h->count + 1;
while (1) {
while (left--) {
code |= bitbuf & 1;
bitbuf >>= 1;
int count = *next++;
if (code - count < first) {
s->bitbuf = bitbuf;
s->bitcnt = (s->bitcnt - len) & 7;
return h->symbol[index + (code - first)];
}
index += count;
first += count;
first <<= 1;
code <<= 1;
len++;
}
left = (MAXBITS + 1) - len;
if (left == 0)
break;
if (s->incnt == s->inlen)
longjmp(s->env, 1);
bitbuf = s->in[s->incnt++];
if (left > 8)
left = 8;
}
return -10;
}
static int puff_construct(struct puff_huffman* h, const short* length, int n)
{
int len;
for (len = 0; len <= MAXBITS; len++)
h->count[len] = 0;
int symbol;
for (symbol = 0; symbol < n; symbol++)
(h->count[length[symbol]])++;
if (h->count[0] == n)
return 0;
int left = 1;
for (len = 1; len <= MAXBITS; len++) {
left <<= 1;
left -= h->count[len];
if (left < 0)
return left;
}
short offs[MAXBITS + 1];
offs[1] = 0;
for (len = 1; len < MAXBITS; len++)
offs[len + 1] = offs[len] + h->count[len];
for (symbol = 0; symbol < n; symbol++)
if (length[symbol] != 0)
h->symbol[offs[length[symbol]]++] = symbol;
return left;
}
static int puff_codes(struct puff_state* s,
const struct puff_huffman* lencode,
const struct puff_huffman* distcode)
{
static const short lens[29] = {
3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258};
static const short lext[29] = {
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0};
static const short dists[30] = {
1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
8193, 12289, 16385, 24577};
static const short dext[30] = {
0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
12, 12, 13, 13};
int symbol;
do {
symbol = puff_decode(s, lencode);
if (symbol < 0)
return symbol;
if (symbol < 256) {
if (s->outcnt == s->outlen)
return 1;
if (symbol)
s->out[s->outcnt] = symbol;
s->outcnt++;
} else if (symbol > 256) {
symbol -= 257;
if (symbol >= 29)
return -10;
int len = lens[symbol] + puff_bits(s, lext[symbol]);
symbol = puff_decode(s, distcode);
if (symbol < 0)
return symbol;
unsigned dist = dists[symbol] + puff_bits(s, dext[symbol]);
if (dist > s->outcnt)
return -11;
if (s->outcnt + len > s->outlen)
return 1;
while (len--) {
if (dist <= s->outcnt && s->out[s->outcnt - dist])
s->out[s->outcnt] = s->out[s->outcnt - dist];
s->outcnt++;
}
}
} while (symbol != 256);
return 0;
}
static int puff_fixed(struct puff_state* s)
{
static int virgin = 1;
static short lencnt[MAXBITS + 1], lensym[FIXLCODES];
static short distcnt[MAXBITS + 1], distsym[MAXDCODES];
static struct puff_huffman lencode, distcode;
if (virgin) {
lencode.count = lencnt;
lencode.symbol = lensym;
distcode.count = distcnt;
distcode.symbol = distsym;
short lengths[FIXLCODES];
int symbol;
for (symbol = 0; symbol < 144; symbol++)
lengths[symbol] = 8;
for (; symbol < 256; symbol++)
lengths[symbol] = 9;
for (; symbol < 280; symbol++)
lengths[symbol] = 7;
for (; symbol < FIXLCODES; symbol++)
lengths[symbol] = 8;
puff_construct(&lencode, lengths, FIXLCODES);
for (symbol = 0; symbol < MAXDCODES; symbol++)
lengths[symbol] = 5;
puff_construct(&distcode, lengths, MAXDCODES);
virgin = 0;
}
return puff_codes(s, &lencode, &distcode);
}
static int puff_dynamic(struct puff_state* s)
{
static const short order[19] =
{16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
int nlen = puff_bits(s, 5) + 257;
int ndist = puff_bits(s, 5) + 1;
int ncode = puff_bits(s, 4) + 4;
if (nlen > MAXLCODES || ndist > MAXDCODES)
return -3;
short lengths[MAXCODES];
int index;
for (index = 0; index < ncode; index++)
lengths[order[index]] = puff_bits(s, 3);
for (; index < 19; index++)
lengths[order[index]] = 0;
short lencnt[MAXBITS + 1], lensym[MAXLCODES];
struct puff_huffman lencode = {lencnt, lensym};
int err = puff_construct(&lencode, lengths, 19);
if (err != 0)
return -4;
index = 0;
while (index < nlen + ndist) {
int symbol;
int len;
symbol = puff_decode(s, &lencode);
if (symbol < 0)
return symbol;
if (symbol < 16)
lengths[index++] = symbol;
else {
len = 0;
if (symbol == 16) {
if (index == 0)
return -5;
len = lengths[index - 1];
symbol = 3 + puff_bits(s, 2);
} else if (symbol == 17)
symbol = 3 + puff_bits(s, 3);
else
symbol = 11 + puff_bits(s, 7);
if (index + symbol > nlen + ndist)
return -6;
while (symbol--)
lengths[index++] = len;
}
}
if (lengths[256] == 0)
return -9;
err = puff_construct(&lencode, lengths, nlen);
if (err && (err < 0 || nlen != lencode.count[0] + lencode.count[1]))
return -7;
short distcnt[MAXBITS + 1], distsym[MAXDCODES];
struct puff_huffman distcode = {distcnt, distsym};
err = puff_construct(&distcode, lengths + nlen, ndist);
if (err && (err < 0 || ndist != distcode.count[0] + distcode.count[1]))
return -8;
return puff_codes(s, &lencode, &distcode);
}
static int puff(
unsigned char* dest,
unsigned long* destlen,
const unsigned char* source,
unsigned long sourcelen)
{
struct puff_state s = {
.out = dest,
.outlen = *destlen,
.outcnt = 0,
.in = source,
.inlen = sourcelen,
.incnt = 0,
.bitbuf = 0,
.bitcnt = 0,
};
int err;
if (setjmp(s.env) != 0)
err = 2;
else {
int last;
do {
last = puff_bits(&s, 1);
int type = puff_bits(&s, 2);
err = type == 0 ? puff_stored(&s) : (type == 1 ? puff_fixed(&s) : (type == 2 ? puff_dynamic(&s) : -1));
if (err != 0)
break;
} while (!last);
}
*destlen = s.outcnt;
return err;
}
//% END CODE DERIVED FROM puff.{c,h}
#define ZLIB_HEADER_WIDTH 2
static int puff_zlib_to_file(const unsigned char* source, unsigned long sourcelen, int dest_fd)
{
if (sourcelen < ZLIB_HEADER_WIDTH)
return 0;
source += ZLIB_HEADER_WIDTH;
sourcelen -= ZLIB_HEADER_WIDTH;
const unsigned long max_destlen = 132 << 20;
void* ret = mmap(0, max_destlen, PROT_WRITE | PROT_READ, MAP_PRIVATE | MAP_ANON, -1, 0);
if (ret == MAP_FAILED)
return -1;
unsigned char* dest = (unsigned char*)ret;
unsigned long destlen = max_destlen;
int err = puff(dest, &destlen, source, sourcelen);
if (err) {
munmap(dest, max_destlen);
errno = -err;
return -1;
}
if (write(dest_fd, dest, destlen) != (ssize_t)destlen) {
munmap(dest, max_destlen);
return -1;
}
return munmap(dest, max_destlen);
}
static int setup_loop_device(unsigned char* data, unsigned long size, const char* loopname, int* loopfd_p)
{
int err = 0, loopfd = -1;
int memfd = syscall(__NR_memfd_create, "syzkaller", 0);
if (memfd == -1) {
err = errno;
goto error;
}
if (puff_zlib_to_file(data, size, memfd)) {
err = errno;
goto error_close_memfd;
}
loopfd = open(loopname, O_RDWR);
if (loopfd == -1) {
err = errno;
goto error_close_memfd;
}
if (ioctl(loopfd, LOOP_SET_FD, memfd)) {
if (errno != EBUSY) {
err = errno;
goto error_close_loop;
}
ioctl(loopfd, LOOP_CLR_FD, 0);
usleep(1000);
if (ioctl(loopfd, LOOP_SET_FD, memfd)) {
err = errno;
goto error_close_loop;
}
}
close(memfd);
*loopfd_p = loopfd;
return 0;
error_close_loop:
close(loopfd);
error_close_memfd:
close(memfd);
error:
errno = err;
return -1;
}
static void reset_loop_device(const char* loopname)
{
int loopfd = open(loopname, O_RDWR);
if (loopfd == -1) {
return;
}
if (ioctl(loopfd, LOOP_CLR_FD, 0)) {
}
close(loopfd);
}
static long syz_mount_image(
volatile long fsarg,
volatile long dir,
volatile long flags,
volatile long optsarg,
volatile long change_dir,
volatile unsigned long size,
volatile long image)
{
unsigned char* data = (unsigned char*)image;
int res = -1, err = 0, need_loop_device = !!size;
char* mount_opts = (char*)optsarg;
char* target = (char*)dir;
char* fs = (char*)fsarg;
char* source = NULL;
char loopname[64];
if (need_loop_device) {
int loopfd;
memset(loopname, 0, sizeof(loopname));
snprintf(loopname, sizeof(loopname), "/dev/loop%llu", procid);
if (setup_loop_device(data, size, loopname, &loopfd) == -1)
return -1;
close(loopfd);
source = loopname;
}
mkdir(target, 0777);
char opts[256];
memset(opts, 0, sizeof(opts));
if (strlen(mount_opts) > (sizeof(opts) - 32)) {
}
strncpy(opts, mount_opts, sizeof(opts) - 32);
if (strcmp(fs, "iso9660") == 0) {
flags |= MS_RDONLY;
} else if (strncmp(fs, "ext", 3) == 0) {
bool has_remount_ro = false;
char* remount_ro_start = strstr(opts, "errors=remount-ro");
if (remount_ro_start != NULL) {
char after = *(remount_ro_start + strlen("errors=remount-ro"));
char before = remount_ro_start == opts ? '\0' : *(remount_ro_start - 1);
has_remount_ro = ((before == '\0' || before == ',') && (after == '\0' || after == ','));
}
if (strstr(opts, "errors=panic") || !has_remount_ro)
strcat(opts, ",errors=continue");
} else if (strcmp(fs, "xfs") == 0) {
strcat(opts, ",nouuid");
} else if (strncmp(fs, "gfs2", 4) == 0 && (strstr(opts, "errors=panic") || strstr(opts, "debug"))) {
strcat(opts, ",errors=withdraw");
}
res = mount(source, target, fs, flags, opts);
if (res == -1) {
err = errno;
goto error_clear_loop;
}
res = open(target, O_RDONLY | O_DIRECTORY);
if (res == -1) {
err = errno;
goto error_clear_loop;
}
if (change_dir) {
res = chdir(target);
if (res == -1) {
err = errno;
}
}
error_clear_loop:
if (need_loop_device)
reset_loop_device(loopname);
errno = err;
return res;
}
int main(void)
{
syscall(__NR_mmap, /*addr=*/0x1ffffffff000ul, /*len=*/0x1000ul, /*prot=*/0ul, /*flags=MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE*/0x32ul, /*fd=*/(intptr_t)-1, /*offset=*/0ul);
syscall(__NR_mmap, /*addr=*/0x200000000000ul, /*len=*/0x1000000ul, /*prot=PROT_WRITE|PROT_READ|PROT_EXEC*/7ul, /*flags=MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE*/0x32ul, /*fd=*/(intptr_t)-1, /*offset=*/0ul);
syscall(__NR_mmap, /*addr=*/0x200001000000ul, /*len=*/0x1000ul, /*prot=*/0ul, /*flags=MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE*/0x32ul, /*fd=*/(intptr_t)-1, /*offset=*/0ul);
const char* reason;
(void)reason;
if (write(1, "executing program\n", sizeof("executing program\n") - 1)) {}
// syz_mount_image$jfs arguments: [
// fs: ptr[in, buffer] {
// buffer: {6a 66 73 00} (length 0x4)
// }
// dir: ptr[in, buffer] {
// buffer: {2e 2f 66 69 6c 65 30 00} (length 0x8)
// }
// flags: mount_flags = 0x1000002 (8 bytes)
// opts: ptr[in, fs_options[jfs_options]] {
// fs_options[jfs_options] {
// elems: array[fs_opt_elem[jfs_options]] {
// }
// common: array[fs_opt_elem[fs_options_common]] {
// }
// null: const = 0x0 (1 bytes)
// }
// }
// chdir: int8 = 0x1 (1 bytes)
// size: len = 0x6161 (8 bytes)
// img: ptr[in, buffer] {
// buffer: (compressed buffer with length 0x6160)
// }
// ]
// returns fd_dir
memcpy((void*)0x200000000000, "jfs\000", 4);
memcpy((void*)0x200000000180, "./file0\000", 8);
*(uint8_t*)0x2000000002c0 = 0;
memcpy((void*)0x20000000d680, "\x78\x9c\xec\xdd\x4b\x8f\x1c\x57\xd9\x07\xf0\xa7\xfa\x36\x17\xbf\x71\xac\x2c\xa2\xbc\x16\x42\x93\xc4\x5c\x42\x88\xaf\xc1\x18\x02\x24\x59\xc0\x82\x0d\x0b\xe4\x2d\xb2\x35\x99\x44\x16\x0e\x20\xdb\x20\x27\xb2\xf0\x44\xb3\x61\xc1\x87\x00\x21\xb1\x44\x88\x25\x2b\x3e\x40\x16\x6c\xd9\xf1\x01\xb0\x64\x23\x81\xb2\x4a\xa1\x9a\x39\x67\x5c\xd3\xe9\x76\x8f\xed\x4c\x57\xcf\x9c\xdf\x4f\x1a\x57\x3d\x7d\xaa\xa6\x4f\xf9\xdf\xd5\x97\xa9\xaa\x3e\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc4\x0f\x7f\xf0\xe3\x73\x55\x44\x5c\xf9\x55\xba\xe1\x44\xc4\xff\x45\x3f\xa2\x17\xb1\xd2\xd4\x6b\x11\xb1\xb2\x76\x22\x2f\x3f\x88\x88\x17\x62\xbb\x39\x9e\x8f\x88\xe1\x52\x44\x95\x1b\x9f\x8d\x78\x3d\x22\x3e\x3e\x1e\x71\xff\xc1\x9d\xf5\xe6\xa6\xf3\xfb\xec\xc7\xf7\xff\xfc\x8f\x3f\xfc\xe4\xd8\x8f\xfe\xfe\xa7\xe1\x99\xff\xfe\xe5\x56\xff\x8d\x69\xcb\xdd\xbe\xfd\xdb\xff\xfc\xf5\xee\x93\x6f\x2f\x00\x00\x00\x94\xa8\xae\xeb\xba\x4a\x1f\xf3\x4f\xa6\xcf\xf7\xbd\xae\x3b\x05\x00\xcc\x45\x7e\xfd\xaf\x93\x7c\xbb\x7a\xe1\xea\xcd\x05\xeb\x8f\x5a\xad\x56\xab\x0f\x61\xdd\x56\x4f\x76\xb7\x5d\x44\xc4\x66\x7b\x9d\xe6\x3d\x83\xc3\xf1\x00\x70\xc8\x6c\xc6\x27\x5d\x77\x81\x0e\xc9\xbf\x68\x83\x88\x38\xd6\x75\x27\x80\x85\x56\x75\xdd\x01\x0e\xc4\xfd\x07\x77\xd6\xab\x94\x6f\xd5\x7e\x3d\x58\xdb\x69\xcf\xe7\x82\xec\xc9\x7f\xb3\xda\xbd\xbe\x63\xda\x74\x96\xf1\x73\x4c\xe6\xf5\xf8\xda\x8a\x7e\x3c\x37\xa5\x3f\x2b\x73\xea\xc3\x22\xc9\xf9\xf7\xc6\xf3\xbf\xb2\xd3\x3e\x4a\xcb\x1d\x74\xfe\xf3\x32\x2d\xff\xd1\xce\xa5\x4f\xc5\xc9\xf9\xf7\xc7\xf3\x1f\x73\x74\xf2\xef\x4d\xcc\xbf\x54\x39\xff\xc1\x63\xe5\xdf\x97\x3f\x00\x00\x00\x00\x00\x2c\xb0\xfc\xf7\xff\x13\x1d\x1f\xff\x5d\x7a\xfa\x4d\xd9\x97\x47\x1d\xff\x5d\x9b\x53\x1f\x00\x00\x00\x00\x00\x00\x00\xe0\xf3\xf6\xb4\xe3\xff\xed\xaa\x8c\xff\x07\x00\x00\x00\x8b\xaa\xf9\xac\xde\xf8\xdd\xf1\x87\xb7\x4d\xfb\x2e\xb6\xe6\xf6\xcb\x55\xc4\x33\x63\xcb\x03\x85\x49\x17\xcb\xac\x76\xdd\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x28\xc9\x60\xe7\x1c\xde\xcb\x55\xc4\x30\x22\x9e\x59\x5d\xad\xeb\xba\xf9\x69\x1b\xaf\x1f\xd7\xd3\xae\x7f\xd8\x95\xbe\xfd\x50\xb2\xae\x9f\xe4\x01\x00\x60\xc7\xc7\xc7\xc7\xae\xe5\xaf\x22\x96\x23\xe2\x72\xfa\xae\xbf\xe1\xea\xea\x6a\x5d\x2f\xaf\xac\xd6\xab\xf5\xca\x52\x7e\x3f\x3b\x5a\x5a\xae\x57\x5a\x9f\x6b\xf3\xb4\xb9\x6d\x69\xb4\x8f\x37\xc4\x83\x51\xdd\xfc\xb2\xe5\xd6\x7a\x6d\xb3\x3e\x2f\xcf\x6a\x1f\xff\x7d\xcd\x7d\x8d\xea\xfe\x3e\x3a\x36\x1f\x1d\x06\x0e\x00\x11\xb1\xf3\x6a\x74\xdf\x2b\xd2\x11\x53\xd7\xcf\x46\xd7\xef\x72\x38\x1c\xec\xff\x47\x8f\xfd\x9f\xfd\xe8\xfa\x71\x0a\x00\x00\x00\x1c\xbc\xba\xae\xeb\x2a\x7d\x9d\xf7\xc9\x74\xcc\xbf\xd7\x75\xa7\x00\x80\xb9\xc8\xaf\xff\xe3\xc7\x05\xd4\x6a\xb5\x5a\xad\x56\x1f\xbd\xba\xad\x9e\xec\x6e\xbb\x88\x88\xcd\xf6\x3a\xcd\x7b\x06\xc3\xf1\x03\xc0\x21\xb3\x19\x9f\x74\xdd\x05\x3a\x24\xff\xa2\x0d\x22\xe2\x85\xae\x3b\x01\x2c\xb4\xaa\xeb\x0e\x70\x20\xee\x3f\xb8\xb3\x5e\xa5\x7c\xab\xf6\xeb\x41\x1a\xdf\x3d\x9f\x0b\xb2\x27\xff\xcd\x6a\x7b\xbd\xbc\xfe\xa4\xe9\x2c\xe3\xe7\x98\xcc\xeb\xf1\xb5\x15\xfd\x78\x6e\x4a\x7f\x9e\x9f\x53\x1f\x16\x49\xce\xbf\x37\x9e\xff\x95\x9d\xf6\x51\x5a\xee\xa0\xf3\x9f\x97\x69\xf9\x37\xdb\x79\xa2\x83\xfe\x74\x2d\xe7\xdf\x1f\xcf\x7f\xcc\xd1\xc9\xbf\x37\x31\xff\x52\xe5\xfc\x07\x8f\x95\x7f\x5f\xfe\x00\x00\x00\x00\x00\xb0\xc0\xf2\xdf\xff\x4f\x2c\xd4\xf1\xdf\xd1\x93\x6e\xce\x4c\x8f\x3a\xfe\xbb\x76\x60\xf7\x0a\x00\x00\x00\x00\x00\x00\x00\x07\xeb\xfe\x83\x3b\xeb\xf9\xba\xd7\x7c\xfc\xff\x0b\x13\x96\x73\xfd\xe7\xd1\x94\xf3\xaf\xe4\x5f\xa4\x9c\x7f\x6f\x2c\xff\xaf\x8e\x2d\xd7\x6f\xcd\xdf\x7b\xfb\x61\xfe\xff\x7e\x70\x67\xfd\x8f\xb7\xfe\xf5\xff\x79\xba\xdf\xfc\x97\xf2\x4c\x95\x1e\x59\x55\x7a\x44\x54\xe9\x9e\xaa\x41\x9a\x3e\xcd\xd6\x7d\xd6\xd6\xb0\x3f\x6a\xee\x69\x58\xf5\xfa\x83\x74\xce\x4f\x3d\x7c\x37\xae\xc5\xf5\xd8\x88\xb3\x7b\x96\xed\xa5\xff\x8f\x87\xed\xe7\xf6\xb4\x37\x3d\x1d\x6e\xb7\xd7\xfd\x9d\xf6\xf3\x7b\xda\x07\xbb\xed\x79\xfd\x0b\x7b\xda\x87\xe9\x4c\xa7\x7a\x25\xb7\x9f\x8e\xf5\xf8\x79\x5c\x8f\x77\xb6\xdb\x9b\xb6\xa5\x19\xdb\xbf\x3c\xa3\xbd\x9e\xd1\x9e\xf3\xef\xdb\xff\x8b\x94\xf3\x1f\xb4\x7e\x9a\xfc\x57\x53\x7b\x35\x36\x6d\xdc\xfb\xa8\xf7\x99\xfd\xbe\x3d\x9d\x74\x3f\x6f\x5d\xfb\xe2\x6f\xce\x1e\xfc\xe6\xcc\xb4\x15\xfd\xdd\x6d\x6b\x6b\xb6\xef\xa5\x0e\xfa\xb3\xfd\x7f\x72\x6c\x14\xbf\xbc\xb9\x71\xe3\xf4\xed\xab\xb7\x6e\xdd\x38\x17\x69\xb2\xe7\xd6\xf3\x91\x26\x9f\xb3\x9c\xff\x30\xfd\xec\x3e\xff\xbf\xbc\xd3\x9e\x9f\xf7\xdb\xfb\xeb\xbd\x8f\x46\x8f\x9d\xff\xa2\xd8\x8a\xc1\xd4\xfc\x5f\x6e\xcd\x37\xdb\xfb\xca\x9c\xfb\xd6\x85\x9c\xff\x28\xfd\xe4\xfc\xdf\x49\xed\x93\xf7\xff\xc3\x9c\xff\xf4\xfd\xff\xd5\x0e\xfa\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8f\x52\xd7\xf5\xf6\x25\xa2\x6f\x45\xc4\xc5\x74\xfd\x4f\x57\xd7\x66\x02\x00\xf3\x95\x5f\xff\xeb\x24\xdf\x3e\xaf\xba\x3f\xe7\xfb\x53\xab\x0f\x79\x5d\x2d\x58\x7f\xe6\x5a\x7f\x5a\x2f\x56\x7f\xd4\xea\xc3\x58\xb7\xd5\x93\xbd\xd9\x2e\x22\xe2\x6f\xed\x75\x9a\xf7\x0c\xbf\x9e\xf4\xcb\x00\x80\x45\xf6\x69\x44\xfc\xb3\xeb\x4e\xd0\x19\xf9\x17\x2c\x7f\xdf\x5f\x33\x3d\xd5\x75\x67\x80\xb9\xba\xf9\xc1\x87\x3f\xbd\x7a\xfd\xfa\xc6\x8d\x9b\x5d\xf7\x04\x00\x00\x00\x00\x00\x00\x00\x78\x52\x79\xfc\xcf\xb5\xd6\xf8\xcf\xa7\xea\xba\xbe\x3b\xb6\xdc\x9e\xf1\x5f\xdf\x8e\xb5\xa7\x1d\xff\x73\x90\x67\x76\x07\x18\x9d\x32\x50\x75\xff\xf1\xb7\xe9\x51\xb6\x7a\xa3\x7e\xaf\x35\xdc\xf8\x8b\x31\x6d\xfc\xef\xe1\xee\xdc\xa3\xc6\xff\x1e\xcc\xb8\xbf\xe1\x8c\xf6\xd1\x8c\xf6\xa5\x19\xed\xcb\x33\xda\x27\x5e\xe8\xd1\x92\xf3\x7f\xb1\x35\xde\xf9\xa9\x88\x38\x39\x36\xfc\x7a\x09\xe3\xbf\x8e\x8f\x79\x5f\x82\x9c\xff\x4b\xad\xc7\x73\x93\xff\x57\xc6\x96\x6b\xe7\x5f\xff\xfe\x30\xe7\xdf\xdb\x93\xff\x99\x5b\xef\xff\xe2\xcc\xcd\x0f\x3e\x7c\xed\xda\xfb\x57\xdf\xdb\x78\x6f\xe3\x67\x17\xce\x9d\x3b\x7b\xe1\xe2\xc5\x4b\x97\x2e\x9d\x79\xf7\xda\xf5\x8d\xb3\x3b\xff\x76\xd8\xe3\x83\x95\xf3\xcf\x63\x5f\x3b\x0f\xb4\x2c\x39\xff\x9c\xb9\xfc\xcb\x92\xf3\xff\x52\xaa\xe5\x5f\x96\x9c\xff\x97\x53\x2d\xff\xb2\xe4\xfc\xf3\xfb\x3d\xf9\x97\x25\xe7\x9f\x3f\xfb\xc8\xbf\x2c\x39\xff\x57\x52\x2d\xff\xb2\xe4\xfc\xbf\x96\x6a\xf9\x97\x25\xe7\xff\x6a\xaa\xe5\x5f\x96\x9c\xff\xd7\x53\x2d\xff\xb2\xe4\xfc\x5f\x4b\xb5\xfc\xcb\x92\xf3\x3f\x9d\x6a\xf9\x97\x25\xe7\x7f\x26\xd5\xfb\xcc\x7f\xe5\xa0\xfb\xc5\x7c\xe4\xfc\xf3\x11\x2e\xfb\x7f\x59\x72\xfe\xf9\xcc\x06\xf9\x97\x25\xe7\x7f\x3e\xd5\xf2\x2f\x4b\xce\xff\x42\xaa\xe5\x5f\x96\x9c\xff\xeb\xa9\x96\x7f\x59\x72\xfe\xdf\x48\xb5\xfc\xcb\x92\xf3\xbf\x98\x6a\xf9\x97\x25\xe7\xff\xcd\x54\xcb\xbf\x2c\x39\xff\x4b\xa9\x96\x7f\x59\x72\xfe\xdf\x4a\xb5\xfc\xcb\x92\xf3\xff\x76\xaa\xe5\x5f\x96\x9c\xff\x1b\xa9\x96\x7f\x59\x72\xfe\xdf\x49\xb5\xfc\xcb\x92\xf3\xff\x6e\xaa\xe5\x5f\x96\x9c\xff\xf7\x52\x2d\xff\xb2\xe4\xfc\xdf\x4c\xb5\xfc\xcb\xf2\xf0\xfb\xff\xcd\x98\x31\x63\x26\xcf\x74\xfd\xcc\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8c\x9b\xc7\xe9\xc4\x5d\x6f\x23\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf0\x3f\x76\xe0\x40\x00\x00\x00\x00\x00\xc8\xff\xb5\x11\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xb0\x03\x07\x02\x00\x00\x00\x00\x40\xfe\xaf\x8d\x50\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x85\xbd\x7b\x8b\x91\xeb\xae\xef\x00\x7e\x66\x6f\x5e\x3b\x90\x18\x08\xa9\x93\x9a\xb0\x76\x8c\x31\xce\x26\xbb\xbe\xc4\x17\x5a\x17\x13\xae\x0d\xb7\x92\x10\x0a\xbd\x60\xbb\xde\xb5\x59\xf0\x0d\xaf\x5d\x02\x8d\x6a\x47\x81\x12\x09\xa3\xa2\x8a\xb6\xe1\xa1\x2d\x20\xd4\xe6\xa5\xc2\xaa\x78\xa0\x15\xa0\x3c\xa0\x56\x95\x2a\x41\xfb\x40\x5f\x10\x15\x2a\x0f\x51\x15\x50\x40\xaa\xd4\x56\xc0\x56\x33\xe7\xff\xff\xef\xcc\xec\xec\xcc\xae\x77\xb2\x39\x73\xce\xe7\x23\x25\xbf\xec\xcc\x99\x39\x67\xce\xfc\x67\x76\xbf\x76\xbe\x3b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x34\xdb\xf6\x86\xd9\x4f\xd5\xb2\x2c\xab\xd5\x6a\xf9\x05\x9b\xb3\xec\x45\xf5\xb9\x71\x62\x73\xe3\x92\xd7\xbe\xb0\xc7\x07\x00\x00\x00\xac\xdd\xcf\x1b\xff\x7e\xee\x96\x74\xc1\xd1\x15\xdc\xa8\x69\x9b\x7f\xba\xf3\xdb\x5f\x5d\x58\x58\x58\xc8\xde\x37\xfc\xa7\xa3\x9f\x5b\x58\x48\x57\x4c\x64\xd9\xe8\x86\x2c\x6b\x5c\x17\x5d\xff\xc1\xfb\x6b\xcd\xdb\x04\x8f\x67\xe3\xb5\xa1\xa6\xaf\x87\x7a\xec\x7e\xb8\xc7\xf5\x23\x3d\xae\x1f\xed\x71\xfd\x58\x8f\xeb\x37\xf4\xb8\x7e\xbc\xc7\xf5\x4b\x4e\xc0\x12\x1b\xb3\x5a\xba\xb3\x1d\x8d\xff\xdc\x9c\x9f\xd2\xec\xd6\x6c\xb4\x71\xdd\x8e\x0e\xb7\x7a\xbc\xb6\x61\xa8\x7e\xee\xd2\x6d\xb3\x5a\xe3\x36\x0b\xa3\xa7\xb2\xb9\xec\x4c\x36\x9b\x4d\xb7\x6c\x9f\x6f\x5b\x6b\x6c\xff\xf5\x6d\xf5\x7d\xbd\x35\x8b\xfb\x1a\x6a\xda\xd7\xd6\xfa\x0a\xf9\xc9\xa3\x27\xe3\x31\xd4\xc2\x39\xde\xd1\xb2\xaf\xc5\xfb\x8c\x7e\xf4\xfa\x6c\xe2\xa7\x3f\x79\xf4\xe4\x5f\x5f\x7a\xf6\xf6\x4e\xb3\xe7\x69\x68\xb9\xbf\xfc\x38\x77\x6d\xaf\x1f\xe7\x27\xc2\x25\xf9\xb1\xd6\xb2\x0d\xe9\x9c\xc4\xe3\x1c\x6a\x3a\xce\xad\x1d\x9e\x93\xe1\x96\xe3\xac\x35\x6e\x57\xff\xef\xf6\xe3\x7c\x6e\x85\xc7\x39\xbc\x78\x98\xeb\xaa\xfd\x39\x1f\xcf\x86\x1a\xff\xfd\x9d\xc6\x79\x1a\xa9\x65\x1d\xce\xd3\xd6\x70\xd9\xff\xdc\x95\x65\xd9\xd5\xc5\xc3\x6e\xdf\x66\xc9\xbe\xb2\xa1\x6c\x53\xcb\x25\x43\x8b\xcf\xcf\x78\xbe\x22\xeb\xf7\x51\x5f\x4a\x2f\xcd\x46\x56\xb5\x4e\xb7\xad\x60\x9d\xd6\xe7\xcc\x8e\xd6\x75\xda\xfe\x9a\x88\xcf\xff\xb6\x70\xbb\x91\x65\x8e\xa1\xf9\x69\xfa\xd1\x63\x63\x4d\xcf\xfb\xcf\x16\x6e\x64\x9d\x46\xf5\x47\xbd\xdc\x6b\xa5\x7d\x0d\xf6\xfb\xb5\x52\x94\x35\x18\xd7\xc5\x77\x1a\x0f\xfa\x89\x8e\x6b\x70\x47\x78\xfc\x8f\xee\x5c\x7e\x0d\x76\x5c\x3b\x1d\xd6\x60\x7a\xdc\x4d\x6b\x70\x7b\xaf\x35\x38\x34\x36\xdc\x38\xe6\xf4\x24\xd4\x1a\xb7\x59\x5c\x83\x7b\x5a\xb6\x1f\x6e\xec\xa9\xd6\x98\xcf\xec\xec\xbe\x06\xa7\x2e\x9d\xbd\x30\x35\xff\xb1\x8f\xdf\x33\x77\xf6\xc4\xe9\xd9\xd3\xb3\xe7\xf6\xed\xd9\x33\xbd\xef\xc0\x81\x43\x87\x0e\x4d\x9d\x9a\x3b\x33\x3b\x9d\xff\xfb\x06\xcf\x76\xf1\x6d\xca\x86\xd2\x6b\x60\x7b\x38\x77\xf1\x35\xf0\xea\xb6\x6d\x9b\x97\xea\xc2\x17\xc7\x96\xbc\xff\xde\xe8\xeb\x70\xbc\xcb\xeb\x70\x73\xdb\xb6\xfd\x7e\x1d\x8e\xb4\x3f\xb8\xda\xfa\xbc\x20\x97\xae\xe9\xfc\xb5\xf1\x9e\xfa\x49\x1f\xbf\x36\x94\x2d\xf3\x1a\x6b\x3c\x3f\xbb\xd7\xfe\x3a\x4c\x8f\xbb\xe9\x75\x38\xd2\xf4\x3a\xec\xf8\x3d\xa5\xc3\xeb\x70\x64\x05\xaf\xc3\xfa\x36\x17\x76\xaf\xec\x67\x96\x91\xa6\x7f\x3a\x1d\xc3\xf2\xdf\x0b\xd6\xb6\x06\x37\x37\xad\xc1\xf6\x9f\x47\xda\xd7\x60\xbf\x7f\x1e\x29\xca\x1a\x1c\x0f\xeb\xe2\x7b\xbb\x97\xff\x5e\xb0\x35\x1c\xef\x13\x93\xab\xfd\x79\x64\x78\xc9\x1a\x4c\x0f\x37\xbc\xf7\xd4\x2f\x49\x3f\xef\x8f\x1f\x6a\x8c\x4e\xeb\xf2\x8e\xfa\x15\x37\x8d\x65\x97\xe7\x67\x2f\xde\xfb\xc8\x89\x4b\x97\x2e\xee\xc9\xc2\x58\x17\x2f\x6b\x5a\x2b\xed\xeb\x75\x53\xd3\x63\xca\x96\xac\xd7\xa1\x55\xaf\xd7\xa3\x73\x77\x3e\x71\x47\x87\xcb\x37\x87\x73\x35\x7e\x4f\xfd\x5f\xe3\xcb\x3e\x57\xf5\x6d\xf6\xdf\xdb\xfd\xb9\x6a\x7c\x77\xeb\x7c\x3e\x5b\x2e\xdd\x9b\x85\xd1\x67\xeb\x7d\x3e\x3b\x7d\x37\xaf\x9f\xcf\xb1\x2c\xfb\xfc\xb7\x1e\x7b\xf0\x1b\x8f\x7e\xfe\x0d\xcb\x9e\xcf\x7a\xde\xfc\xc4\xd4\xda\x7f\x16\x4f\xb9\xb4\xe9\xfd\x77\x74\x99\xf7\xdf\x98\xfb\x7f\x91\xef\x2f\xdd\xd5\xe3\xc3\xa3\x23\xf9\xeb\x77\x38\x9d\x9d\xd1\x96\xf7\xe3\xd6\xa7\x6a\xa4\xf1\xde\x55\x6b\xec\xfb\xb9\xa9\x95\xbd\x1f\x8f\x86\x7f\xd6\xfb\xfd\xf8\xd6\x2e\xef\xc7\x5b\xda\xb6\xed\xf7\xfb\xf1\x68\xfb\x83\x8b\xef\xc7\xb5\x5e\x7f\xda\xb1\x36\xed\xcf\xe7\x78\x58\x27\x67\xa6\xbb\xbf\x1f\xd7\xb7\xd9\xb2\x77\xb5\x6b\x72\xa4\xeb\xfb\xf1\x5d\x61\xd6\xc2\xf9\x7f\x4d\x48\x0a\x29\x17\x35\xad\x9d\xe5\xd6\x6d\xda\xd7\xc8\xc8\x68\x78\x5c\x23\x71\x0f\xad\xeb\x74\x5f\xcb\xf6\xa3\x21\x9b\xd5\xf7\xf5\xd4\xde\x1b\x5b\xa7\xbb\xee\xca\xef\x6b\x38\x3d\xba\x45\xeb\xb5\x4e\x27\xda\xb6\xed\xf7\x3a\x4d\x7f\xf6\xb5\xdc\x3a\xad\xf5\xfa\xd3\xb7\x1b\xd3\xfe\x7c\x8e\x87\x75\x71\xeb\xbe\xee\xeb\xb4\xbe\xcd\xd3\xfb\xd7\xfe\xde\xb9\x31\xfe\x67\xd3\x7b\xe7\x58\xaf\x35\x38\x3a\x3c\x56\x3f\xe6\xd1\xb4\x08\x1b\xef\xf7\xd9\xc2\xc6\xb8\x06\xef\xcd\x4e\x66\xe7\xb3\x33\xd9\x4c\xe3\xda\xb1\xc6\x7a\xaa\x35\xf6\x35\x79\xdf\xca\xd6\xe0\x58\xf8\x67\xbd\xdf\x2b\xb7\x74\x59\x83\xbb\xda\xb6\xed\xf7\x1a\x4c\xdf\xc7\x96\x5b\x7b\xb5\x91\xa5\x0f\xbe\x0f\xda\x9f\xcf\xf1\xb0\x2e\x9e\xbc\xaf\xfb\x1a\xac\x6f\xf3\xc6\x83\xfd\xfd\xd9\x75\x57\xb8\x24\x6d\xd3\xf4\xb3\x6b\xfb\x9f\xaf\x2d\xf7\x67\x5e\x77\xb4\x9d\xa6\xe7\x6b\xad\x8c\x84\xe3\xfc\xd6\xc1\xee\x7f\x36\x5b\xdf\xe6\xcc\xa1\xd5\xe6\xcc\xee\xe7\xe9\xee\x70\xc9\x4d\x1d\xce\x53\xfb\xeb\x77\xb9\xd7\xd4\x4c\xb6\x3e\xe7\x69\x4b\x38\xce\x67\x0f\x2d\x7f\x9e\xea\xc7\x53\xdf\xe6\x73\x87\x57\xb8\x9e\x8e\x66\x59\x76\xe5\x23\xf7\x37\xfe\xbc\x37\xfc\xfd\xca\xdf\x5d\xfe\xee\x57\x5b\xfe\xde\xa5\xd3\xdf\xe9\x5c\xf9\xc8\xfd\x3f\x7e\xf1\xa9\x7f\x5c\xcd\xf1\x03\x30\xf8\x7e\x91\x8f\x4d\xf9\xf7\xba\xa6\xbf\x99\x5a\xc9\xdf\xff\x03\x00\x00\x00\x03\x21\xe6\xfe\xa1\x30\x13\xf9\x1f\x00\x00\x00\x4a\x23\xe6\xfe\xf8\x7f\x85\x27\xf2\x3f\x00\x00\x00\x94\x46\xcc\xfd\x23\x61\x26\x15\xc9\xff\x5b\xde\xf8\xec\xdc\x2f\xae\x64\xa9\x99\xbf\x10\xc4\xeb\xd3\x69\x78\x20\xdf\x2e\x76\x5c\xa7\xc3\xd7\x13\x0b\x8b\xea\x97\xdf\xff\xe5\xd9\xff\xfe\x87\x2b\x2b\xdb\xf7\x50\x96\x65\x3f\x7b\xe0\x0f\x3a\x6e\xbf\xe5\x81\x78\x5c\xb9\x89\x70\x9c\xd7\xdf\xd4\x7a\xf9\x12\x5f\xbd\x67\x45\xfb\x3e\xfe\xf0\x95\xb4\xdf\xe6\xfe\xfa\x17\xc2\xfd\xc7\xc7\xb3\xd2\x65\xd0\xa9\x82\x3b\x9d\x65\xd9\xd7\x6f\xf9\x4c\x63\x3f\x13\xef\xbf\xd6\x98\x4f\x3f\x70\xbc\x31\x1f\xbc\xfa\xc4\xe3\xf5\x6d\x9e\x3b\x9c\x7f\x1d\x6f\xff\xcc\xcb\xf2\xed\xff\x22\x94\x7f\x8f\x9e\x3a\xd1\x72\xfb\x67\xc2\x79\xf8\x61\x98\xd3\x6f\xeb\x7c\x3e\xe2\xed\xbe\x72\xed\x35\x5b\x0f\xbe\x77\x71\x7f\xf1\x76\xb5\xed\x37\x37\x1e\xf6\x93\x1f\xc8\xef\x37\xfe\x9e\x9c\xcf\x3e\x9e\x6f\x1f\xcf\xf3\x72\xc7\xff\x8d\x4f\x3f\xf5\x95\xfa\xf6\x8f\xbc\xaa\xf3\xf1\x5f\x19\xea\x7c\xfc\x4f\x85\xfb\xfd\x72\x98\xff\xfb\x8a\x7c\xfb\xe6\xe7\xa0\xfe\x75\xbc\xdd\x27\xc3\xf1\xc7\xfd\xc5\xdb\xdd\xfb\xa5\x6f\x76\x3c\xfe\xeb\x9f\xca\xb7\xbf\xf0\xe6\x7c\xbb\xe3\x61\xc6\xfd\xef\x0a\x5f\xef\x78\xf3\xb3\x73\xcd\xe7\xeb\x91\xda\x89\x96\xc7\x95\xbd\x25\xdf\x2e\xee\x7f\xfa\xbb\x7f\xdc\xb8\x3e\xde\x5f\xbc\xff\xf6\xe3\x1f\x3f\x76\xad\xe5\x7c\xb4\xaf\x8f\xa7\xff\x2d\xbf\x9f\xa9\xb6\xed\xe3\xe5\x71\x3f\xd1\xdf\xb7\xed\xbf\x7e\x3f\xcd\xeb\x33\xee\xff\xa9\x3f\x3a\xde\x72\x9e\x7b\xed\xff\xfa\x83\xcf\xbc\xa2\x7e\xbf\xed\xfb\xbf\xbb\x6d\xbb\x0b\x1f\xd9\xdd\xd8\xff\xe2\xfd\xb5\xfe\xc6\xa6\xbf\xfc\xe4\x67\x3a\xee\x2f\x1e\xcf\xd1\xbf\xbd\xd0\xf2\x78\x8e\xbe\x3b\xbc\x8e\xc3\xfe\x9f\xfc\x40\x58\x8f\xe1\xfa\xff\xbb\x9e\xdf\x5f\xfb\x6f\x57\x38\xfe\xee\xd6\xf7\x9f\xb8\xfd\x17\x36\x5f\x69\x79\x3c\xd1\x5b\x7f\x9a\xef\xff\xfa\xeb\x4e\x37\xe6\x86\xf1\x8d\x9b\x6e\x7a\xd1\x8b\x6f\xbe\xfa\xca\xfa\xb9\xcb\xb2\xef\x6c\xc8\xef\xaf\xd7\xfe\x4f\xff\xd5\xf9\x96\xe3\xff\xe2\x6d\xf9\xf9\x88\xd7\xc7\x8e\x7e\xfb\xfe\x97\x13\xf7\x7f\xf1\xa3\x93\xe7\xce\xcf\x5f\x9e\x9b\x49\x67\xf5\xd1\x5b\x1a\xbf\x3b\xe7\xed\xf9\xf1\xc4\xe3\xbd\x25\xbc\xb7\xb6\x7f\x7d\xec\xfc\xa5\x0f\xce\x5e\x9c\x98\x9e\x98\xce\xb2\x89\xf2\xfe\x0a\xbd\x1b\xf6\xa5\x30\x7f\x9c\x8f\xab\xdd\xb7\x5e\x58\xf2\x0e\xba\xfb\xe1\xf0\x7c\xde\xf1\xe7\x5f\xdf\xb4\xf3\x5f\x3f\x1d\x2f\xff\xf7\xf7\xe4\x97\x5f\x7b\x5b\xfe\x7d\xeb\xd5\x61\xbb\xcf\x86\xcb\x37\x87\xe7\x6f\x75\xfb\x5f\xea\xc9\x6d\xb7\x35\x5e\xdf\xb5\xa7\xc3\x11\x2e\x2c\xfd\x7d\xc1\x6b\xb1\x75\xc7\x7f\x1d\x5a\xd1\x86\xe1\xf1\xb7\xff\x5c\x10\xd7\xfb\x85\x97\x7f\xb0\x71\x1e\xea\xd7\x35\xbe\x6f\xc4\xd7\xf5\x1a\x8f\xff\xfb\x33\xf9\xfd\x7c\x2d\x9c\xd7\x85\xf0\x9b\x99\xb7\xdf\xb6\xb8\xbf\xe6\xed\xe3\xef\x46\xb8\xf6\x50\xfe\x7a\x5f\xf3\xf9\x0b\x6f\x73\xf1\x79\xfd\x9b\xf0\x7c\xbf\xe3\x87\xf9\xfd\xc7\xe3\x8a\x8f\xf7\xfb\xe1\xe7\x98\x6f\x6e\x69\x7d\xbf\x8b\xeb\xe3\x6b\x57\x86\xda\xef\xbf\xf1\x5b\x3c\xae\x86\xf7\x93\xec\x6a\x7e\x7d\xdc\x2a\x9e\xef\x6b\xcf\xdd\xd6\xf1\xf0\xe2\xef\x21\xc9\xae\xde\xde\xf8\xfa\x4f\xd2\xfd\xdc\xbe\xaa\x87\xb9\x9c\xf9\x8f\xcd\x4f\x9d\x99\x3b\x77\xf9\x91\xa9\x4b\xb3\xf3\x97\xa6\xe6\x3f\xf6\xf1\x63\x67\xcf\x5f\x3e\x77\xe9\x58\xe3\x77\x79\x1e\xfb\x50\xaf\xdb\x2f\xbe\x3f\x6d\x6a\xbc\x3f\xcd\xcc\x1e\xd8\x9f\x35\xde\xad\xce\xe7\xe3\x79\xf6\x42\x1f\xff\x85\x87\x4f\xce\x1c\x9c\xde\x39\x33\x7b\xea\xc4\xe5\x53\x97\x1e\xbe\x30\x7b\xf1\xf4\xc9\xf9\xf9\x93\xb3\x33\xf3\x3b\x4f\x9c\x3a\x35\xfb\xd1\x5e\xb7\x9f\x9b\x39\xb2\x67\xef\xe1\x7d\x07\xf7\x4e\x9e\x9e\x9b\x39\x72\xe8\xf0\xe1\x7d\x87\x27\xe7\xce\x9d\xaf\x1f\x46\x7e\x50\x3d\x1c\x98\xfe\xf0\xe4\xb9\x8b\xc7\x1a\x37\x99\x3f\xb2\xff\xf0\x9e\xfb\xee\xdb\x3f\x3d\x79\xf6\xfc\xcc\xec\x91\x83\xd3\xd3\x93\x97\x7b\xdd\xbe\xf1\xbd\x69\xb2\x7e\xeb\xdf\x9f\xbc\x38\x7b\xe6\xc4\xa5\xb9\xb3\xb3\x93\xf3\x73\x1f\x9f\x3d\xb2\xe7\xf0\x81\x03\x7b\x7b\xfe\x36\xc0\xb3\x17\x4e\xcd\x4f\x4c\x5d\xbc\x7c\x6e\xea\xf2\xfc\xec\xc5\xa9\xfc\xb1\x4c\x5c\x6a\x5c\x5c\xff\xde\xd7\xeb\xf6\x94\xd3\xfc\x7f\xe4\x3f\xcf\xb6\xab\xe5\xbf\x88\x2f\x7b\xd7\xdd\x07\xd2\xef\x67\xad\xfb\xf2\x63\xcb\xde\x55\xbe\x49\xdb\x2f\x10\x7d\x36\xfc\x2e\x9a\x7f\x7e\xc9\x85\x43\x2b\xf9\x3a\xe6\xfe\xd1\x30\x93\x8a\xe4\x7f\x00\x00\x00\xa8\x82\x98\xfb\xc7\xc2\x4c\xe4\x7f\x00\x00\x00\x28\x8d\x98\xfb\x37\x84\x99\xc8\xff\x00\x00\x00\x50\x1a\x31\xf7\x8f\x87\x99\x54\x24\xff\x97\xae\xff\xbf\xe5\xca\x8a\xf6\xaf\xff\xaf\xff\xdf\x7c\xbe\xf4\xff\x2b\xd6\xff\x7f\xa8\x68\xfd\xff\xfc\xfd\x42\xff\xbf\x3f\xd6\xda\xbf\xd7\xff\x0f\xf4\xff\xf5\xff\xf5\xff\xf5\xff\xf5\xff\xe9\x83\xa2\xf5\xff\x63\xee\xdf\x98\x65\x95\xcc\xff\x00\x00\x00\x50\x05\x31\xf7\x6f\x0a\x33\x91\xff\x01\x00\x00\xa0\x34\x62\xee\xbf\x29\xcc\x44\xfe\x07\x00\x00\x80\xd2\x88\xb9\xff\x45\x61\x26\x15\xc9\xff\xfa\xff\xfa\xff\xfa\xff\xfa\xff\xfa\xff\x9d\xf7\xaf\xff\x3f\x98\xf4\xff\xbb\xd3\xff\xef\x41\xff\x7f\x2a\xab\x56\xff\xff\x6a\x3f\x8f\x5f\xff\x5f\xff\x9f\xa5\x8a\xd6\xff\x8f\xb9\xff\xc5\x61\x26\x15\xc9\xff\x00\x00\x00\x50\x05\x31\xf7\xdf\x1c\x66\x22\xff\x03\x00\x00\x40\x69\xc4\xdc\x7f\x4b\x98\x89\xfc\x0f\x00\x00\x00\xa5\x11\x73\xff\xe6\x30\x93\x8a\xe4\x7f\xfd\x7f\xfd\x7f\xfd\x7f\xfd\x7f\xfd\xff\xce\xfb\xd7\xff\x1f\x4c\xfa\xff\xdd\xe9\xff\xf7\xa0\xff\xef\xf3\xff\xf5\xff\xf5\xff\xe9\xab\xa2\xf5\xff\x63\xee\x7f\x49\x98\x49\x45\xf2\x3f\x00\x00\x00\x54\x41\xcc\xfd\x2f\x0d\x33\x91\xff\x01\x00\x00\xa0\x78\x46\x6e\xec\x66\x31\xf7\xbf\x2c\xcc\x64\x49\xfe\xbf\xc1\x1d\x00\x00\x00\x00\x2f\xb8\x98\xfb\x6f\xcd\xda\x8a\xe0\x15\xf9\xfb\x7f\xfd\x7f\xfd\xff\xe2\xf7\xff\x37\xa4\xeb\xf4\xff\xf5\xff\xb3\x42\xf6\xff\x87\x33\xfd\xff\xe2\xd0\xff\xef\x4e\xff\xbf\x07\xfd\x7f\xfd\x7f\xfd\x7f\xfd\x7f\xfa\xaa\x68\xfd\xff\x46\xee\xcf\xc6\xb3\x97\x87\x99\x54\x24\xff\x03\x00\x00\x40\x15\xc4\xdc\x7f\x5b\x98\x89\xfc\x0f\x00\x00\x00\xa5\x11\x73\xff\x2f\x85\x99\xc8\xff\x00\x00\x00\x50\x1a\x31\xf7\x6f\x09\x33\xa9\x48\xfe\xd7\xff\xd7\xff\x2f\x7e\xff\xdf\xe7\xff\xeb\xff\x17\xbd\xff\xef\xf3\xff\x8b\x44\xff\xbf\x3b\xfd\xff\x1e\xf4\xff\xf5\xff\xf5\xff\xf5\xff\xe9\xab\xa2\xf5\xff\x63\xee\xbf\x3d\xcc\xa4\x22\xf9\x1f\x00\x00\x00\xaa\x20\xe6\xfe\x3b\xc2\x4c\xe4\x7f\x00\x00\x00\x28\x8d\x98\xfb\x7f\x39\xcc\x44\xfe\x07\x00\x00\x80\xd2\x88\xb9\x7f\x6b\x98\x49\x45\xf2\xbf\xfe\x7f\xc1\xfb\xff\xb1\x39\xaa\xff\xaf\xff\xaf\xff\xaf\xff\xaf\xff\xbf\x22\xfa\xff\xdd\xe9\xff\xf7\xa0\xff\xaf\xff\xaf\xff\xaf\xff\x4f\x5f\x15\xad\xff\x1f\x73\xff\x2b\xc2\x4c\x2a\x92\xff\x01\x00\x00\xa0\x0a\x62\xee\xbf\x33\xcc\x44\xfe\x07\x00\x00\x80\xd2\x88\xb9\xff\x95\x61\x26\xf2\x3f\x00\x00\x00\x94\x46\xcc\xfd\x13\x61\x26\x15\xc9\xff\xfa\xff\x05\xef\xff\xe7\x3d\xf8\x31\x9f\xff\xaf\xff\xaf\xff\xaf\xff\xaf\xff\xbf\x32\xfa\xff\xdd\xe9\xff\xf7\xa0\xff\xaf\xff\xaf\xff\xaf\xff\x4f\x5f\x15\xad\xff\x1f\x73\xff\xb6\x30\x93\x8a\xe4\x7f\x00\x00\x00\xa8\x82\x98\xfb\xb7\x87\x99\xc8\xff\x00\x00\x00\x50\x1a\x31\xf7\xdf\x15\x66\x22\xff\x03\x00\x00\x40\x69\xc4\xdc\xbf\x23\xcc\xa4\x22\xf9\x5f\xff\x7f\x20\xfa\xff\x99\xfe\xbf\xfe\xbf\xfe\xbf\xfe\xbf\xfe\xff\xca\xe8\xff\x77\xa7\xff\xdf\x83\xfe\xbf\xfe\xbf\xfe\xbf\xfe\x3f\x7d\x55\xb4\xfe\x7f\xcc\xfd\xaf\x0a\x33\xa9\x48\xfe\x07\x00\x00\x80\x2a\x88\xb9\x7f\x67\x98\x89\xfc\x0f\x00\x00\x00\xa5\x11\x73\xff\xab\xc3\x4c\xe4\x7f\x00\x00\x00\x28\x8d\x98\xfb\x77\x85\x99\x54\x24\xff\xeb\xff\xeb\xff\xeb\xff\xeb\xff\xeb\xff\x77\xde\xbf\xfe\xff\x60\xd2\xff\xef\x4e\xff\xbf\x07\xfd\x7f\xfd\x7f\xfd\x7f\xfd\x7f\xfa\xaa\x68\xfd\xff\x98\xfb\x5f\x13\x66\x52\x91\xfc\x0f\x00\x00\x00\x55\x10\x73\xff\xee\x30\x13\xf9\x1f\x00\x00\x00\x4a\x23\xe6\xfe\xbb\xc3\x4c\xe4\x7f\x00\x00\x00\x28\x8d\x98\xfb\x27\xc3\x4c\x2a\x92\xff\xf5\xff\xf5\xff\xf5\xff\xf5\xff\xf5\xff\x3b\xef\x5f\xff\x7f\x30\xe9\xff\x77\xa7\xff\xdf\x83\xfe\xbf\xfe\xbf\xfe\xbf\xfe\x3f\x7d\x55\xb4\xfe\x7f\xcc\xfd\xf7\x84\x99\x54\x24\xff\x03\x00\x00\x40\x15\xc4\xdc\x7f\x6f\x98\x89\xfc\x0f\x00\x00\x00\xa5\x11\x73\xff\x54\x98\x89\xfc\x0f\x00\x00\x00\xa5\x11\x73\xff\x74\x98\x49\x45\xf2\xbf\xfe\xbf\xfe\xbf\xfe\xbf\xfe\xff\xaa\xfa\xff\xaf\x5c\xbc\x5f\xfd\xff\x9c\xfe\x7f\xb1\xe8\xff\x77\xa7\xff\xdf\x83\xfe\xbf\xfe\xff\x0b\xde\xff\x1f\xd5\xff\xa7\x54\x8a\xd6\xff\x8f\xb9\x7f\x4f\x98\x49\x45\xf2\x3f\x00\x00\x00\x54\x41\xcc\xfd\x7b\xc3\x4c\xe4\x7f\x00\x00\x00\x28\x8d\x98\xfb\xf7\x85\x99\xc8\xff\x00\x00\x00\x50\x1a\x31\xf7\xef\x0f\x33\xa9\x48\xfe\xd7\xff\xd7\xff\xd7\xff\xd7\xff\xf7\xf9\xff\x9d\xf7\xaf\xff\x3f\x98\xf4\xff\xbb\xeb\x7f\xff\x3f\x3e\x44\xfd\x7f\xfd\x7f\xfd\x7f\x9f\xff\xaf\xff\xcf\x52\x45\xeb\xff\xc7\xdc\x7f\x5f\x98\x49\x45\xf2\x3f\x00\x00\x00\x54\x41\xcc\xfd\x07\xc2\x4c\xe4\x7f\x00\x00\x00\x28\x8d\x98\xfb\x0f\x86\x99\xc8\xff\x00\x00\x00\x50\x1a\x31\xf7\x1f\x0a\x33\xa9\x48\xfe\xd7\xff\xd7\xff\xd7\xff\xd7\xff\xd7\xff\xef\xbc\x7f\xfd\xff\xc1\xa4\xff\xdf\x9d\xcf\xff\xef\x41\xff\x5f\xff\x5f\xff\x5f\xff\x9f\x35\x7a\xe8\x0f\x9b\xbf\x2a\x5a\xff\x3f\xe6\xfe\xc3\x61\x26\x15\xc9\xff\x00\x00\x00\x50\x05\x31\xf7\xbf\x36\xcc\x44\xfe\x07\x00\x00\x80\xd2\x88\xb9\xff\x57\xc2\x4c\xe4\x7f\x00\x00\x00\x28\x8d\x98\xfb\x7f\x35\xcc\xa4\x22\xf9\x5f\xff\x5f\xff\x5f\xff\x5f\xff\x5f\xff\xbf\xf3\xfe\xf5\xff\x07\x93\xfe\x7f\x77\xfa\xff\x3d\xe8\xff\xeb\xff\xeb\xff\xeb\xff\xd3\x57\x45\xeb\xff\xc7\xdc\x7f\x24\xcc\xa4\x22\xf9\x1f\x00\x00\x00\xaa\x20\xe6\xfe\x5f\x0b\x33\x91\xff\x01\x00\x00\xa0\x34\x62\xee\x7f\x5d\x98\x89\xfc\x0f\x00\x00\x00\xa5\x11\x73\xff\xd1\x30\x93\x8a\xe4\x7f\xfd\x7f\xfd\x7f\xfd\x7f\xfd\x7f\xfd\xff\xce\xfb\x5f\xef\xfe\xff\x58\xbc\x5f\xfd\xff\x35\xd1\xff\xef\x4e\xff\xbf\x07\xfd\x7f\xfd\x7f\xfd\x7f\xfd\x7f\xfa\xaa\x68\xfd\xff\x98\xfb\x5f\x1f\x66\x52\x91\xfc\x0f\x00\x00\x00\x55\x10\x73\xff\xfd\x61\x26\xf2\x3f\x00\x00\x00\x94\x46\xcc\xfd\x6f\x08\x33\x91\xff\x01\x00\x00\xa0\x34\x62\xee\x7f\x63\x98\x49\x45\xf2\xbf\xfe\xbf\xfe\xbf\xfe\xbf\xfe\xbf\xfe\x7f\xe7\xfd\xfb\xfc\xff\xc1\xa4\xff\xdf\x9d\xfe\x7f\x0f\xfa\xff\xfa\xff\xfa\xff\xfa\xff\xf4\x55\xd1\xfa\xff\x31\xf7\xbf\x29\xcc\xa4\x22\xf9\x1f\x00\x00\x00\xaa\x20\xe6\xfe\x37\x87\x99\xc8\xff\x00\x00\x00\x50\x1a\x31\xf7\xbf\x25\xcc\x44\xfe\x07\x00\x00\x80\xd2\x88\xb9\xff\xad\x61\x26\x15\xc9\xff\xfa\xff\xfa\xff\xfa\xff\xfa\xff\xfa\xff\x9d\xf7\xaf\xff\x3f\x98\xf4\xff\xbb\xd3\xff\xef\x41\xff\x5f\xff\x5f\xff\x5f\xff\x9f\xbe\x2a\x5a\xff\x3f\xe6\xfe\x5f\x0f\x33\xa9\x48\xfe\x07\x00\x00\x80\x2a\x88\xb9\xff\x81\x30\x13\xf9\x1f\x00\x00\x00\x4a\x23\xe6\xfe\xb7\x85\x99\xc8\xff\x00\x00\x00\x50\x1a\x31\xf7\xbf\x3d\xcc\xa4\x22\xf9\x5f\xff\x5f\xff\x5f\xff\x5f\xff\x5f\xff\xbf\xf3\xfe\xf5\xff\x07\x93\xfe\x7f\x77\x03\xd6\xff\xff\xf9\xcd\xe1\x72\xfd\xff\x9c\xfe\x7f\xb1\x8f\x7f\xb5\xfd\xff\x91\xb6\xaf\x9f\x97\xfe\xff\x0f\x96\xeb\xff\x2f\x6c\x68\xbf\xbd\xfe\x3f\xcf\x87\xa2\xf5\xff\x63\xee\x7f\x47\x98\x49\x45\xf2\x3f\x00\x00\x00\x54\x41\xcc\xfd\xef\x0c\x33\x91\xff\x01\x00\x00\xa0\x34\x62\xee\x7f\x57\x98\x89\xfc\x0f\x00\x00\x00\xa5\x11\x73\xff\x6f\x84\x99\x54\x24\xff\xeb\xff\xd7\x8f\x63\xb1\xbd\xac\xff\xaf\xff\xdf\xb8\x40\xff\x5f\xff\x5f\xff\x7f\x60\xe9\xff\x77\x37\x60\xfd\x7f\x9f\xff\xdf\x46\xff\xbf\xd8\xc7\xef\xf3\xff\xf5\xff\x59\xaa\x68\xfd\xff\x98\xfb\xdf\x1d\x66\x52\x91\xfc\x0f\x00\x00\x00\x55\x10\x73\xff\x83\x61\x26\xf2\x3f\x00\x00\x00\x94\x46\xcc\xfd\x0f\x85\x99\xc8\xff\x00\x00\x00\x50\x1a\x31\xf7\xbf\x27\xcc\xa4\x22\xf9\x5f\xff\xdf\xe7\xff\xeb\xff\xeb\xff\xeb\xff\x77\xde\xbf\xfe\xff\x60\xd2\xff\xef\x4e\xff\xbf\x07\xfd\x7f\xfd\xff\xa2\xf5\xff\xff\x53\xff\x9f\xc1\x56\xb4\xfe\x7f\xcc\xfd\x0f\x87\x99\x54\x24\xff\x03\x00\x00\x40\x15\xc4\xdc\xff\xde\x30\x13\xf9\x1f\x00\x00\x00\x4a\x23\xe6\xfe\xdf\x0c\x33\x91\xff\x01\x00\x00\xa0\x34\x62\xee\x7f\x5f\x98\x49\x45\xf2\xbf\xfe\xff\xa0\xf4\xff\x27\x06\xb4\xff\xff\x98\xfe\xff\xf3\xd8\xff\xbf\xf3\xe6\x7c\x3b\xfd\x7f\xfd\x7f\x16\xe9\xff\x77\xa7\xff\xdf\x83\xfe\xbf\xfe\x7f\xd1\xfa\xff\x3e\xff\x9f\x01\x57\xb4\xfe\x7f\xcc\xfd\xef\x0f\x33\x59\x79\xfe\x1f\x5f\xf1\x96\x00\x00\x00\xc0\x0b\x22\xe6\xfe\xdf\x0a\x33\xa9\xc8\xdf\xff\x03\x00\x00\x40\x15\xc4\xdc\xff\xdb\x61\x26\xf2\x3f\x00\x00\x00\x94\x46\xcc\xfd\xbf\x13\x66\x52\x91\xfc\xaf\xff\x3f\x28\xfd\x7f\x9f\xff\x9f\xe9\xff\xfb\xfc\xff\xb6\xc7\xa3\xff\xaf\xff\xdf\xc9\xfa\xf5\xff\xe3\x3b\x8f\xfe\xbf\xfe\xbf\xfe\x7f\xa4\xff\xaf\xff\xaf\xff\x4f\xbb\xa2\xf5\xff\x63\xee\xff\xdd\x30\x93\x8a\xe4\x7f\x00\x00\x00\xa8\x82\x98\xfb\x3f\x10\x66\x22\xff\x03\x00\x00\xc0\x40\xe8\xf4\xff\x64\xb7\x8b\xb9\xff\x58\x98\x89\xfc\x0f\x00\x00\x00\xa5\x11\x73\xff\xf1\x30\x93\x8a\xe4\x7f\xfd\x7f\xfd\x7f\xfd\xff\x82\xf6\xff\xff\x6c\xfb\xbf\x7c\xef\xdb\xef\x3c\xbe\x47\xff\x5f\xff\x5f\xff\x7f\x55\xd6\xf5\xf3\xff\xeb\x2f\x7e\x9f\xff\xaf\xff\xaf\xff\x9f\xe8\xff\xeb\xff\xeb\xff\xd3\xae\x68\xfd\xff\x98\xfb\x4f\x84\x99\x54\x24\xff\x03\x00\x00\x40\x15\xc4\xdc\xff\x7b\x61\x26\xf2\x3f\x00\x00\x00\x94\x46\xcc\xfd\x27\xc3\x4c\xe4\x7f\x00\x00\x00\x28\x8d\x98\xfb\x67\xc2\x4c\x2a\x92\xff\xf5\xff\xf5\xff\xf5\xff\x0b\xda\xff\x1f\xe0\xcf\xff\x8f\xe7\x43\xff\xbf\x55\xdf\xfa\xff\xf1\x4d\x57\xff\xbf\xa3\x75\xed\xff\xbf\x77\xb1\x27\xae\xff\xbf\xda\xfe\xff\x58\xc7\x4b\xf5\xff\xf5\xff\x07\xf9\xf8\xf5\xff\xf5\xff\x59\xaa\x68\xfd\xff\x98\xfb\x67\xc3\x4c\x2a\x92\xff\x01\x00\x00\xa0\x0a\x42\xee\x1f\x3a\x95\xcf\xc5\x2b\xe4\x7f\x00\x00\x00\x28\x8d\x98\xfb\x4f\x87\x99\xc8\xff\x00\x00\x00\x50\x1a\x31\xf7\x7f\x30\xcc\xa4\x22\xf9\x5f\xff\x5f\xff\x5f\xff\x5f\xff\xdf\xe7\xff\x77\xde\x7f\xb7\xfe\x7f\x6d\xc4\xe7\xff\x17\x95\xfe\x7f\x77\xc5\xe9\xff\x77\xa6\xff\xaf\xff\x3f\xc8\xc7\xaf\xff\xaf\xff\xcf\x52\x45\xeb\xff\xc7\xdc\x3f\x17\x66\x52\x91\xfc\x0f\x00\x00\x00\x55\x10\x73\xff\x87\xc2\x4c\xe4\x7f\x00\x00\x00\x28\x8d\x98\xfb\x3f\x1c\x66\x22\xff\x03\x00\x00\x40\x69\xc4\xdc\x7f\x26\xcc\xa4\x22\xf9\x5f\xff\x5f\xff\x5f\xff\x5f\xff\x5f\xff\xbf\xf3\xfe\x0b\xfb\xf9\xff\xfa\xff\x5d\xe9\xff\x77\xa7\xff\xdf\x83\xfe\xbf\xfe\xbf\xfe\xbf\xfe\x3f\x7d\x55\xb4\xfe\x7f\xcc\xfd\x67\xc3\x4c\x2a\x92\xff\x01\x00\x00\xa0\x0a\x62\xee\x3f\x17\x66\x22\xff\x03\x00\x00\x40\x69\xc4\xdc\x7f\x3e\xcc\x44\xfe\x07\x00\xfe\x9f\xbd\x3b\x69\xb2\xac\xac\xf6\x38\x7c\xf2\xde\x22\xaa\x2a\xb8\x83\x3b\x73\xe0\xc4\x08\x87\x7e\x04\x06\x3a\xd6\x0f\xe0\xc0\x89\x03\x8d\x30\x1c\xd8\xa1\x62\x4f\x61\xdf\xa2\xa8\xd8\x2b\x8a\x7d\x83\x0d\x08\x22\x2a\xf6\x1d\xd8\xa1\xd8\x83\x8a\x7d\xdf\x60\x87\xa8\x51\x86\x59\x6b\xad\xca\x66\xe7\x3e\x99\x59\x27\x33\xf7\x7e\xdf\xe7\x19\xb0\xee\x4d\x49\xf6\x91\xa8\x00\xfe\x54\xfd\xdc\x00\x40\x33\x72\xf7\x3f\x2a\x6e\xe9\x64\xff\xeb\xff\xf5\xff\xcd\xf6\xff\xf7\xd5\xff\xef\xf4\x7c\xfd\xbf\xfe\xbf\x65\xfa\xff\x71\xfa\xff\x25\xf4\xff\xfa\x7f\xfd\xbf\xfe\x9f\x95\x9a\x5a\xff\x9f\xbb\xff\xd1\x71\x4b\x27\xfb\x1f\x00\x00\x00\x7a\x90\xbb\xff\x31\x71\x8b\xfd\x0f\x00\x00\x00\xcd\xc8\xdd\x7f\x61\xdc\x62\xff\x03\x00\x00\x40\x33\x72\xf7\x3f\x36\x6e\xe9\x64\xff\x6f\xe9\xff\xd7\x16\x7d\xf6\xff\x99\xf1\xea\xff\x5b\xea\xff\xbd\xff\x7f\xc7\xe7\xeb\xff\xf5\xff\x2d\x3b\xdc\xfe\xff\x92\xff\xfe\x95\x4f\xff\xaf\xff\xd7\xff\x07\xfd\xff\xae\xfa\xff\xe3\x3b\x7d\xbf\xfe\x9f\x16\x4d\xad\xff\xcf\xdd\xff\xb8\xb8\xa5\x93\xfd\x0f\x00\x00\x00\x3d\xc8\xdd\xff\xf8\xb8\xc5\xfe\x07\x00\x00\x80\x66\xe4\xee\xbf\x28\x6e\xb1\xff\x01\x00\x00\xa0\x19\xb9\xfb\x9f\x10\xb7\x74\xb2\xff\x57\xf7\xfe\xff\x93\xeb\x5f\x9f\x69\xff\x5f\xf4\xff\xfa\xff\xf5\x2f\xe8\xff\xf5\xff\xfa\xff\xd9\xf2\xfe\xff\x71\x3d\xf5\xff\x17\xde\x7a\xfe\x23\xee\xbc\xee\x9e\xd7\xef\xe5\xf9\xfa\x7f\xfd\xbf\xf7\xff\xeb\xff\x59\xad\xa9\xf5\xff\xb9\xfb\x9f\x18\xb7\x74\xb2\xff\x01\x00\x00\xa0\x07\xb9\xfb\x9f\x14\xb7\xd8\xff\x00\x00\x00\xd0\x8c\xdc\xfd\x4f\x8e\x5b\xec\x7f\x00\x00\x00\x68\x46\xee\xfe\xa7\xc4\x2d\x9d\xec\xff\xd5\xf5\xff\xb3\x7e\xff\x7f\xd1\xff\xeb\xff\xd7\xbf\xa0\xff\xd7\xff\xeb\xff\x67\x4b\xff\x3f\xae\xa7\xfe\x7f\x3f\xcf\xd7\xff\xeb\xff\xf5\xff\xfa\x7f\x56\x6b\x6a\xfd\x7f\xee\xfe\xa7\xc6\x2d\x9d\xec\x7f\x00\x00\x00\xe8\x41\xee\xfe\xa7\xc5\x2d\xf6\x3f\x00\x00\x00\x34\x23\x77\xff\xc5\x71\x8b\xfd\x0f\x00\x00\x00\xcd\xc8\xdd\x7f\x2a\x6e\xe9\x64\xff\xeb\xff\x0f\xbe\xff\xff\xb7\xfe\x5f\xff\x1f\x57\xff\xaf\xff\xd7\xff\x1f\x3c\xfd\xff\x38\xfd\xff\x12\xfa\x7f\xfd\xbf\xfe\x5f\xff\xcf\x4a\x4d\xad\xff\xcf\xdd\x7f\x49\xdc\xd2\xc9\xfe\x07\x00\x00\x80\x1e\xe4\xee\x7f\x7a\xdc\x62\xff\x03\x00\x00\x40\x33\x72\xf7\x3f\x23\x6e\xb1\xff\x01\x00\x00\xa0\x19\xb9\xfb\x9f\x19\xb7\x74\xb2\xff\xf5\xff\xde\xff\xaf\xff\xd7\xff\xeb\xff\x87\x9f\xaf\xff\x9f\x27\xfd\xff\x38\xfd\xff\x12\xfa\xff\x73\xed\xe7\xcf\xd3\xff\xeb\xff\xf5\xff\x6c\xb4\xc7\xfe\xff\xee\x91\xbf\x6c\xaf\xa4\xff\xcf\xdd\xff\xac\xb8\xa5\x93\xfd\x0f\x00\x00\x00\x3d\xc8\xdd\xff\xec\xb8\xc5\xfe\x07\x00\x00\x80\x66\xe4\xee\x7f\x4e\xdc\x62\xff\x03\x00\x00\x40\x33\x72\xf7\x3f\x37\x6e\xe9\x64\xff\xeb\xff\xf5\xff\xfa\x7f\xfd\xff\xbe\xfb\xff\xed\x3f\xf4\xd6\xe9\xff\x87\xe9\xff\x0f\x87\xfe\x7f\xdc\x64\xfa\xff\xb5\x63\x83\x5f\xd6\xff\xcf\xbe\xff\xf7\xfe\x7f\xfd\xbf\xfe\x9f\x4d\xa6\xf6\xfe\xff\xdc\xfd\xcf\x8b\x5b\x3a\xd9\xff\x00\x00\x00\xd0\x83\xdc\xfd\xcf\x8f\x5b\x46\xf6\xff\x9e\xff\x65\x3e\x00\x00\x00\x70\xa4\x72\xf7\xbf\x20\x6e\xf1\xf3\xff\x00\x00\x00\x30\x7b\x59\x9d\xe5\xee\x7f\x61\xdc\xd2\xc9\xfe\xd7\xff\xeb\xff\xf5\xff\xfa\x7f\xef\xff\x1f\x7e\xfe\x58\xff\x7f\xfd\x86\xcf\xa7\xff\x9f\x16\xfd\xff\xb8\xc9\xf4\xff\x3b\xd0\xff\xeb\xff\xe7\xfc\xf9\xf5\xff\xfa\x7f\xb6\x9b\x5a\xff\x9f\xbb\xff\x45\x71\x4b\x27\xfb\x1f\x00\x00\x00\x7a\x90\xbb\xff\xd2\xb8\xc5\xfe\x07\x00\x00\x80\x66\xe4\xee\x7f\x71\xdc\x62\xff\x03\x00\x00\x40\x33\x72\xf7\xbf\x24\x6e\xe9\x64\xff\x0f\xf7\xff\x67\xff\x73\xfd\xff\xee\xe8\xff\x37\x7f\x7e\xfd\xff\xf0\x8f\x8f\x55\xf5\xff\xf9\x47\xd4\xff\x8f\xf6\xff\xf7\xf3\xfe\xff\x3e\xe9\xff\xc7\x1d\x7e\xff\x7f\x5c\xff\xbf\xf9\x8f\xaf\xff\x3f\x40\x47\xfd\xf9\x1b\xef\xff\x4f\x2e\xfb\x7e\xfd\x3f\x43\xa6\xd6\xff\xe7\xee\xbf\x2c\x6e\xe9\x64\xff\x03\x00\x00\x40\x0f\x72\xf7\xbf\x34\x6e\xb1\xff\x01\x00\x00\xa0\x19\xb9\xfb\x5f\x16\xb7\xd8\xff\x00\x00\x00\xd0\x8c\xdc\xfd\x2f\x8f\x5b\x3a\xd9\xff\xde\xff\xaf\xff\xd7\xff\xcf\xaf\xff\xf7\xfe\xff\x33\x8e\xf2\xfd\xff\x8b\x43\xef\xff\x8f\xe9\xff\x77\x49\xff\x3f\xce\xfb\xff\x97\xd0\xff\xeb\xff\xf5\xff\xde\xff\xcf\x4a\x4d\xad\xff\xcf\xdd\x7f\x79\xdc\xd2\xc9\xfe\x07\x00\x00\x80\x1e\x5c\x7e\xd7\x62\x7d\xf7\xbf\x62\xb1\xb0\xff\x01\x00\x00\x60\x8e\x36\xfe\xda\x81\xad\xbf\xa0\x34\xe4\xee\x7f\x65\xdc\x62\xff\x03\x00\x00\x40\x33\x72\xf7\xbf\x2a\x6e\xe9\x64\xff\xeb\xff\xf5\xff\xfa\x7f\xfd\xbf\xfe\x7f\xf8\xf9\xd3\xea\xff\xbd\xff\x7f\xb7\xf4\xff\xe3\xf4\xff\x4b\xe8\xff\x0f\xa2\x9f\x3f\xd6\x58\xff\x7f\xc5\x4e\xdf\x3f\x85\xfe\xff\x62\xfd\x3f\x13\xb3\xa9\xff\xbf\xf1\xec\xd7\x8f\xaa\xff\xcf\xdd\xff\xea\xb8\xa5\x93\xfd\x0f\x00\x00\x00\x3d\xc8\xdd\xff\x9a\xb8\xc5\xfe\x07\x00\x00\x80\x66\xe4\xee\x7f\x6d\xdc\x62\xff\x03\x00\x00\x40\x33\x72\xf7\xbf\x2e\x6e\xe9\x64\xff\x1f\x78\xff\x7f\x72\xe7\x67\xeb\xff\xf5\xff\xfa\x7f\xfd\xbf\xfe\x5f\xff\xbf\x6a\xfa\xff\x71\xfa\xff\x25\xf4\xff\xde\xff\xef\xfd\xff\xfa\x7f\x56\x6a\x53\xff\xbf\xc1\x51\xf5\xff\xb9\xfb\x5f\x1f\xb7\x74\xb2\xff\x01\x00\x00\xa0\x07\xb9\xfb\xdf\x10\xb7\xd8\xff\x00\x00\x00\xd0\x8c\xdc\xfd\x57\xc4\x2d\xf6\x3f\x00\x00\x00\x34\x23\x77\xff\x1b\xe3\x96\x4e\xf6\xbf\xf7\xff\xeb\xff\xf5\xff\xfa\x7f\xfd\xff\xf0\xf3\xf5\xff\xf3\xa4\xff\x1f\xa7\xff\x5f\x42\xff\xaf\xff\xd7\xff\xeb\xff\x59\xa9\xa9\xf5\xff\xb9\xfb\xdf\x14\xb7\x74\xb2\xff\x01\x00\x00\xa0\x07\xb9\xfb\xaf\x8c\x5b\xec\x7f\x00\x00\x00\x68\x46\xee\xfe\x37\xc7\x2d\xf6\x3f\x00\x00\x00\x34\x23\x77\xff\x5b\xe2\x96\x4e\xf6\xbf\xfe\xff\x60\xfb\xff\xfc\xba\xfe\x5f\xff\xbf\xd0\xff\xeb\xff\xf5\xff\x87\xa2\xdb\xfe\x7f\x6d\xe8\xef\x44\xdb\xed\xd0\xff\xdf\xfc\xb0\x53\x0f\xd8\xfc\x15\xfd\xbf\xfe\x5f\xff\xaf\xff\xd7\xff\xb3\x02\x93\xe8\xff\x4f\x9f\xfd\xa7\xcb\xdc\xfd\x6f\x8d\x5b\x3a\xd9\xff\x00\x00\x00\xd0\x83\xdc\xfd\x6f\x8b\x5b\xec\x7f\x00\x00\x00\x68\x46\xee\xfe\xb7\xc7\x2d\xf6\x3f\x00\x00\x00\x34\x23\x77\xff\x3b\xe2\x96\x3d\xee\xff\xff\x5f\xe9\xa7\x3a\x3c\xfa\x7f\xef\xff\xd7\xff\xeb\xff\xf5\xff\xc3\xcf\xd7\xff\xcf\x53\xb7\xfd\xff\x2e\x79\xff\xff\x12\xfa\x7f\xfd\xbf\xfe\x5f\xff\xcf\x4a\x4d\xa2\xff\xdf\xf0\xff\xe7\xee\x7f\x67\xdc\xe2\xe7\xff\x01\x00\x00\xa0\x19\xb9\xfb\xdf\x15\xb7\xd8\xff\x00\x00\x00\xd0\x8c\xdc\xfd\xef\x8e\x5b\xec\x7f\x00\x00\x00\x68\x46\xee\xfe\xf7\xc4\x2d\x9d\xec\x7f\xfd\xbf\xfe\x5f\xff\xaf\xff\xd7\xff\x0f\x3f\x7f\xbf\xfd\xff\x89\xc5\x30\xfd\xff\xe1\xd0\xff\x8f\xd3\xff\x2f\xa1\xff\xd7\xff\xeb\xff\xf5\xff\xac\xd4\xd4\xfa\xff\xdc\xfd\x57\xc5\x2d\x9d\xec\x7f\x00\x00\x00\xe8\x41\xee\xfe\xf7\xc6\x2d\xf6\x3f\x00\x00\x00\x34\x23\x77\xff\xfb\xe2\x16\xfb\x1f\x00\x00\x00\x9a\x91\xbb\xff\xfd\x71\x4b\x27\xfb\x5f\xff\xaf\xff\xd7\xff\xeb\xff\xf5\xff\xc3\xcf\xf7\xfe\xff\x79\xd2\xff\x8f\xd3\xff\x2f\x16\x8b\xab\x47\x3e\xc0\x50\xff\x7f\xfa\xb8\xfe\x5f\xff\xaf\xff\xd7\xff\xb3\x4f\x53\xeb\xff\x73\xf7\x7f\x20\x6e\xe9\x64\xff\x03\x00\x00\x40\x0f\x72\xf7\x5f\x1d\xb7\xd8\xff\x00\x00\x00\xd0\x8c\xdc\xfd\xd7\xc4\x2d\xf6\x3f\x00\x00\x00\x34\x23\x77\xff\x07\xe3\x96\x4e\xf6\xbf\xfe\x5f\xff\xaf\xff\xd7\xff\xeb\xff\x87\x9f\xaf\xff\x9f\x27\xfd\xff\x38\xfd\xff\x12\xde\xff\xaf\xff\xd7\xff\xeb\xff\x59\xa9\xa9\xf5\xff\xb9\xfb\xaf\x8d\x5b\x3a\xd9\xff\x00\x00\x00\xd0\x83\xdc\xfd\xd7\xc5\x2d\xf6\x3f\x00\x00\x00\x34\x23\x77\xff\x87\xe2\x16\xfb\x1f\x00\x00\x00\x9a\x91\xbb\xff\xfa\xb8\xa5\x93\xfd\xaf\xff\xd7\xff\xeb\xff\xf5\xff\xfa\xff\xe1\xe7\xeb\xff\xe7\xe9\xe0\xfa\xff\x85\xfe\x5f\xff\xaf\xff\x5f\x42\xff\xaf\xff\xd7\xff\xb3\xd5\xd4\xfa\xff\xdc\xfd\x1f\x8e\x5b\x3a\xd9\xff\x00\x00\x00\xd0\x83\xdc\xfd\x37\xc4\x2d\xf6\x3f\x00\x00\x00\x34\x23\x77\xff\x47\xe2\x16\xfb\x1f\x00\x00\x00\x9a\x91\xbb\xff\xa3\x71\x4b\x27\xfb\x5f\xff\xaf\xff\xd7\xff\xeb\xff\xf5\xff\xc3\xcf\xd7\xff\xcf\x93\xf7\xff\x8f\xd3\xff\x2f\xa1\xff\xd7\xff\xeb\xff\xf5\xff\xac\xd4\xd4\xfa\xff\xdc\xfd\x1f\x8b\x5b\x3a\xd9\xff\x00\x00\x00\xd0\x83\xdc\xfd\x37\xc6\x2d\xf6\x3f\x00\x00\x00\x34\x23\x77\xff\xc7\xe3\x16\xfb\x1f\x00\x00\x00\x9a\x91\xbb\xff\x13\x71\x4b\x27\xfb\x5f\xff\xaf\xff\xdf\xdc\xff\x2f\x16\xfa\x7f\xfd\xbf\xfe\xff\x8c\x43\xe8\xff\x4f\x2c\xf4\xff\x2b\xa7\xff\x1f\xa7\xff\x5f\x42\xff\xdf\x66\xff\xff\x3f\x8b\x86\xfa\xff\x93\x3b\x7e\xbf\xfe\x9f\x29\x9a\x5a\xff\x9f\xbb\xff\x93\x71\x4b\x27\xfb\x1f\x00\x00\x00\x7a\x90\xbb\xff\x53\x71\x8b\xfd\x0f\x00\x00\x00\xcd\xc8\xdd\xff\xe9\xb8\xc5\xfe\x07\x00\x00\x80\x66\xe4\xee\xff\x4c\xdc\xd2\xc9\xfe\x9f\x7f\xff\x7f\x7c\xcb\x37\xea\xff\x17\x8b\xc5\x6d\x17\x79\xff\xbf\xfe\x7f\xe4\xf9\xfa\xff\xc9\xf4\xff\xf5\x67\x55\xff\xbf\x3a\xfa\xff\x71\xfa\xff\x25\xf4\xff\x6d\xf6\xff\xde\xff\xaf\xff\xe7\xc8\x4c\xad\xff\xcf\xdd\xff\xd9\xb8\xa5\x93\xfd\x0f\x00\x00\x00\x3d\xc8\xdd\xff\xb9\xb8\xc5\xfe\x07\x00\x00\x80\x66\xe4\xee\xff\x7c\xdc\x62\xff\x03\x00\x00\x40\x33\x72\xf7\x7f\x21\x6e\xe9\x64\xff\xcf\xbf\xff\xdf\xfa\x8d\xfa\xff\xc5\x39\xbd\xff\x5f\xff\xbf\xfe\x05\xfd\xbf\xfe\x5f\xff\x3f\x5b\xfa\xff\x71\xfa\xff\x25\xf4\xff\x4b\xfb\xf9\xb5\x1d\xfe\xb9\x67\xa1\xff\xd7\xff\xeb\xff\x19\x30\xb5\xfe\x3f\x77\xff\x17\xe3\x96\x4e\xf6\x3f\x00\x00\x00\xf4\x20\x77\xff\x4d\x71\x8b\xfd\x0f\x00\x00\x00\xcd\xc8\xdd\x7f\x73\xdc\x62\xff\x03\x00\x00\x40\x33\x72\xf7\x7f\x29\x6e\xe9\x64\xff\xeb\xff\xf5\xff\xfa\xff\x79\xf6\xff\x27\xf4\xff\xfa\x7f\xfd\xff\xa0\xa9\xf4\xff\x17\x5c\x70\xff\x5b\xf4\xff\xfa\xff\x16\xfb\xff\x31\xfa\x7f\xfd\xbf\xfe\x9f\xad\xa6\xd6\xff\xe7\xee\xff\x72\xdc\xd2\xc9\xfe\x07\x00\x00\x80\x1e\xe4\xee\xff\x4a\xdc\x62\xff\x03\x00\x00\x40\x33\x72\xf7\x7f\x35\x6e\xb1\xff\x01\x00\x00\xa0\x19\xb9\xfb\xbf\x16\xb7\x74\xb2\xff\xb7\xf7\xff\xe7\x2d\xce\x14\xaa\x67\x0c\xf5\xff\xd1\xa8\xe9\xff\x37\xd0\xff\x6f\xfe\xfc\xfa\xff\xe1\x1f\x1f\xde\xff\xaf\xff\xd7\xff\x1f\xbc\xa9\xf4\xff\xde\xff\xbf\xbf\xcf\xaf\xff\xd7\xff\xcf\xf9\xf3\xef\xa9\xff\xbf\xd7\xf6\xef\xd7\xff\xd3\xa2\xa9\xf5\xff\xb9\xfb\x6f\x89\x5b\x3a\xd9\xff\x00\x00\x00\xd0\x83\xdc\xfd\x5f\x8f\x5b\xec\x7f\x00\x00\x00\x68\x46\xee\xfe\x6f\xc4\x2d\xf6\x3f\x00\x00\x00\x34\x23\x77\xff\xad\x71\x4b\x27\xfb\xdf\xfb\xff\xf5\xff\xfa\x7f\xfd\xbf\xfe\x7f\xf8\xf9\xfa\xff\x79\xd2\xff\x8f\xd3\xff\x2f\xa1\xff\xd7\xff\x7b\xff\xff\x23\x1f\xf2\xbf\xfa\x7f\x56\x67\x6a\xfd\x7f\xee\xfe\x6f\xc6\x2d\xeb\xc3\xef\xde\xff\xb7\xcf\xff\x9a\x00\x00\x00\xc0\x84\xe4\xee\xff\x56\xdc\xd2\xc9\xcf\xff\x03\x00\x00\x40\x0f\x72\xf7\x7f\x3b\x6e\xb1\xff\x01\x00\x00\xa0\x19\xb9\xfb\xbf\x13\xb7\x74\xb2\xff\xf5\xff\xfa\x7f\xfd\xbf\xfe\x5f\xff\x3f\xfc\x7c\xfd\xff\x3c\xe9\xff\xc7\xe9\xff\x97\xe8\xa7\xff\x3f\x31\xf4\xc5\xa3\xee\xe7\xcf\xd5\x51\x7f\xfe\x66\xfa\x7f\xef\xff\x67\x85\xa6\xd6\xff\xe7\xee\xff\x6e\xdc\xd2\xc9\xfe\x07\x00\x00\x80\x1e\xe4\xee\xff\x5e\xdc\x62\xff\x03\x00\x00\x40\x33\x72\xf7\x7f\x3f\x6e\xb1\xff\x01\x00\x00\xa0\x19\xb9\xfb\x6f\x8b\x5b\x3a\xd9\xff\xfa\x7f\xfd\x7f\xfb\xfd\xff\x83\xf5\xff\x5b\x9e\xaf\xff\xd7\xff\xb7\x4c\xff\x9f\x7f\x47\x1f\xa6\xff\x5f\xa2\x9f\xfe\x7f\xd0\x51\xf7\xf3\x73\xff\xfc\xfa\x7f\xfd\x3f\xdb\x4d\xad\xff\xcf\xdd\x7f\x7b\xdc\xd2\xc9\xfe\x07\x00\x00\x80\x1e\xe4\xee\xff\x41\xdc\x62\xff\x03\x00\x00\x40\x33\x72\xf7\xff\x30\x6e\xb1\xff\x01\x00\x00\xa0\x19\xb9\xfb\x7f\x14\xb7\x74\xb2\xff\xf5\xff\x7d\xf5\xff\x6b\x8b\x1e\xfb\x7f\xef\xff\xd7\xff\xeb\xff\x7b\x32\x9f\xfe\xff\xca\x63\x43\x5f\xf5\xfe\x7f\xfd\xbf\xfe\x7f\xbe\x9f\x5f\xff\xaf\xff\x67\xbb\xa9\xf5\xff\xb9\xfb\xef\x58\x3b\xd6\xe5\xfe\x07\x00\x00\x80\xb9\x7a\xe0\x7d\x1e\x7e\xfb\x6e\x7f\xdf\x3b\xd6\x7f\x7b\x62\xf1\xe3\xb8\xc5\xfe\x07\x00\x00\x80\x66\xe4\xee\xff\x49\xdc\x62\xff\x03\x00\x00\x40\x33\x72\xf7\xff\x34\x6e\xe9\x64\xff\xeb\xff\xfb\xea\xff\xfb\x7c\xff\xbf\xfe\x5f\xff\xaf\xff\xef\xc9\x7c\xfa\xff\x61\xfa\x7f\xfd\xbf\xfe\x7f\xbe\x9f\x5f\xff\xaf\xff\x67\xbb\xa9\xf5\xff\xb9\xfb\x7f\x16\xb7\x6c\x18\x7e\x83\xff\x03\x3d\x00\x00\x00\xc0\x6c\xe4\xee\xff\x79\xdc\xd2\xc9\xcf\xff\x03\x00\x00\x40\x0f\x72\xf7\xff\x22\x6e\xd9\xb6\xff\x4f\xef\xf2\x57\xb5\x03\x00\x00\x00\x53\x93\xbb\xff\x97\x71\x4b\x27\x3f\xff\xaf\xff\x9f\x78\xff\xbf\x38\xa0\xfe\x3f\x7e\x3f\xfd\xff\x19\xfa\x7f\xfd\xff\xd0\xf3\xf5\xff\xf3\xa4\xff\x1f\x77\x8e\xfd\xff\xe9\x35\xfd\xbf\xfe\x7f\x84\xfe\x5f\xff\xaf\xff\x67\xab\xa9\xf5\xff\xb9\xfb\x6f\xb8\x76\xd1\xe5\xfe\x07\x00\x00\x80\x46\x6d\xfa\x37\x0a\xbf\x5a\xff\xed\x89\xc5\xaf\xe3\x16\xfb\x1f\x00\x00\x00\x9a\x91\xbb\xff\x37\x71\x8b\xfd\x0f\x00\x00\x00\xcd\xc8\xdd\xff\xdb\xb8\xa5\x93\xfd\xaf\xff\x9f\x78\xff\xbf\xaf\xf7\xff\x9f\xac\xff\xcb\xfb\xff\x3b\xef\xff\x2f\x3d\x31\xf8\x7c\xfd\xbf\xfe\xbf\x65\xfa\xff\x71\xde\xff\xbf\x84\xfe\x5f\xff\xaf\xff\xd7\xff\xb3\x52\x7b\xe8\xff\xd7\x07\xe9\x41\xf7\xff\xb9\xfb\x7f\x17\xb7\x74\xb2\xff\x01\x00\x00\xa0\x07\xb9\xfb\x7f\x1f\xb7\xd8\xff\x00\x00\x00\xd0\x8c\xdc\xfd\x7f\x88\x5b\xec\x7f\x00\x00\x00\x68\x46\xee\xfe\x3f\xc6\x2d\x9d\xec\x7f\xfd\xff\x11\xf4\xff\x97\x1d\x5f\x2c\x0e\xb4\xff\xdf\xc5\xfb\xff\xf5\xff\x7d\xf4\xff\x3b\x3c\xbf\x9d\xfe\xff\x1e\xe7\x9f\xba\xe9\x41\x0f\xbd\xe6\x2a\xfd\x3f\x67\x1d\x66\xff\x9f\x3f\x16\xf4\xff\xfa\x7f\xfd\xff\x19\xfa\x7f\xfd\xbf\xfe\x9f\xad\xa6\xf6\xfe\xff\xdc\xfd\x7f\x8a\x5b\x3a\xd9\xff\x00\x00\x00\xd0\x83\xdc\xfd\x77\xc6\x2d\xf6\x3f\x00\x00\x00\x34\x23\x77\xff\x9f\xe3\x16\xfb\x1f\x00\x00\x00\x9a\x91\xbb\xff\x2f\x71\x4b\x27\xfb\x5f\xff\xdf\xe2\xfb\xff\xe7\xd9\xff\xe7\x9f\xeb\x23\xe8\xff\x4f\xcd\xaf\xff\xcf\xa6\xb8\xf7\xfe\xdf\xfb\xff\xf5\xff\xdb\x79\xff\xff\x38\xfd\xff\x12\xfa\x7f\xfd\xbf\xfe\x5f\xff\xcf\x4a\x4d\xad\xff\xcf\xdd\xff\xd7\xb8\xa5\x93\xfd\x0f\x00\x00\x00\x3d\xc8\xdd\xff\xb7\xb8\x25\xf7\xff\xda\x9e\xff\xd5\x3d\x00\x00\x00\x30\x31\xb9\xfb\xff\x1e\xb7\xf8\xf9\x7f\x00\x00\x00\x68\x46\xee\xfe\xbb\xe2\x96\x4e\xf6\xbf\xfe\x5f\xff\x3f\x95\xfe\x3f\x79\xff\xff\xd9\xef\xf3\xfe\xff\x33\xf4\xff\xfa\xff\xbd\xd0\xff\x8f\xd3\xff\x2f\xa1\xff\xd7\xff\xeb\xff\xf5\xff\xac\xd4\xd4\xfa\xff\xdc\xfd\xff\x88\x5b\x3a\xd9\xff\x00\x00\x00\xd0\x83\xdc\xfd\x77\xc7\x2d\xf6\x3f\x00\x00\x00\x34\x23\x77\xff\x3f\xe3\x16\xfb\x1f\x00\x00\x00\x9a\x91\xbb\xff\x5f\x71\x4b\x27\xfb\x5f\xff\xaf\xff\xd7\xff\xeb\xff\xf5\xff\xc3\xcf\xd7\xff\xcf\x93\xfe\x7f\x9c\xfe\x7f\x09\xfd\xbf\xfe\x5f\xff\xaf\xff\x67\xa5\xa6\xd6\xff\xe7\xee\xff\x4f\x00\x00\x00\xff\xff\x0b\x4f\x6c\x1c", 24928);
syz_mount_image(/*fs=*/0x200000000000, /*dir=*/0x200000000180, /*flags=MS_STRICTATIME|MS_NOSUID*/0x1000002, /*opts=*/0x2000000002c0, /*chdir=*/1, /*size=*/0x6161, /*img=*/0x20000000d680);
// openat arguments: [
// fd: fd_dir (resource)
// file: ptr[in, buffer] {
// buffer: {2e 2f 66 69 6c 65 31 00} (length 0x8)
// }
// flags: open_flags = 0x0 (4 bytes)
// mode: open_mode = 0x0 (2 bytes)
// ]
// returns fd
memcpy((void*)0x200000000100, "./file1\000", 8);
syscall(__NR_openat, /*fd=*/0xffffff9c, /*file=*/0x200000000100ul, /*flags=*/0, /*mode=*/0);
return 0;
}
]
|
| 3/1 |
2026/05/11 22:53 |
action |
kernel-checkouter |
0m
Results: map[KernelSrc:/app/workdir/cache/src/ecd8bb68855fdd08aa08215ac485989bac875215]
|
| 4/1 |
2026/05/11 22:53 |
action |
kernel-builder |
21m
Results: map[KernelObj:/app/workdir/cache/build/6779b8c8716bd733df605779bb4d612ba862ae74]
|
| 5/1 |
2026/05/11 23:15 |
action |
crash-reproducer |
2m
Results: map[ReproducedBugTitle:KASAN: slab-use-after-free Write in lmLogSync ReproducedCrashReport: ... Log Wrap ... Log Wrap ... Log Wrap ...
==================================================================
BUG: KASAN: slab-use-after-free in lmLogSync+0x9bb/0xa50 fs/jfs/jfs_logmgr.c:1003
Write of size 4 at addr ffff88804dbfaa18 by task jfsCommit/122
CPU: 1 UID: 0 PID: 122 Comm: jfsCommit Not tainted syzkaller #1 PREEMPT(full)
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
Call Trace:
<TASK>
dump_stack_lvl+0xe8/0x150 lib/dump_stack.c:120
print_address_description+0x55/0x1e0 mm/kasan/report.c:378
print_report+0x58/0x70 mm/kasan/report.c:482
kasan_report+0x117/0x150 mm/kasan/report.c:595
lmLogSync+0x9bb/0xa50 fs/jfs/jfs_logmgr.c:1003
jfs_syncpt+0x7b/0x90 fs/jfs/jfs_logmgr.c:1039
txEnd+0x2e5/0x530 fs/jfs/jfs_txnmgr.c:551
txLazyCommit fs/jfs/jfs_txnmgr.c:2686 [inline]
jfs_lazycommit+0x5b8/0xaa0 fs/jfs/jfs_txnmgr.c:2735
kthread+0x388/0x470 kernel/kthread.c:436
ret_from_fork+0x514/0xb70 arch/x86/kernel/process.c:158
ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245
</TASK>
Allocated by task 6683:
kasan_save_stack mm/kasan/common.c:57 [inline]
kasan_save_track+0x3e/0x80 mm/kasan/common.c:78
poison_kmalloc_redzone mm/kasan/common.c:398 [inline]
__kasan_kmalloc+0x93/0xb0 mm/kasan/common.c:415
kasan_kmalloc include/linux/kasan.h:263 [inline]
__kmalloc_cache_noprof+0x31c/0x660 mm/slub.c:5419
kmalloc_noprof include/linux/slab.h:950 [inline]
kzalloc_noprof include/linux/slab.h:1188 [inline]
open_inline_log fs/jfs/jfs_logmgr.c:1157 [inline]
lmLogOpen+0x2d1/0xfa0 fs/jfs/jfs_logmgr.c:1067
jfs_mount_rw+0xee/0x670 fs/jfs/jfs_mount.c:257
jfs_fill_super+0x754/0xd80 fs/jfs/super.c:532
get_tree_bdev_flags+0x431/0x4f0 fs/super.c:1694
vfs_get_tree+0x92/0x2a0 fs/super.c:1754
fc_mount fs/namespace.c:1193 [inline]
do_new_mount_fc fs/namespace.c:3758 [inline]
do_new_mount+0x341/0xd30 fs/namespace.c:3834
do_mount fs/namespace.c:4167 [inline]
__do_sys_mount fs/namespace.c:4383 [inline]
__se_sys_mount+0x31d/0x420 fs/namespace.c:4360
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0x15f/0xf80 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x77/0x7f
Freed by task 6065:
kasan_save_stack mm/kasan/common.c:57 [inline]
kasan_save_track+0x3e/0x80 mm/kasan/common.c:78
kasan_save_free_info+0x46/0x50 mm/kasan/generic.c:584
poison_slab_object mm/kasan/common.c:253 [inline]
__kasan_slab_free+0x5c/0x80 mm/kasan/common.c:285
kasan_slab_free include/linux/kasan.h:235 [inline]
slab_free_hook mm/slub.c:2689 [inline]
slab_free mm/slub.c:6250 [inline]
kfree+0x1c5/0x640 mm/slub.c:6565
lmLogClose+0x297/0x520 fs/jfs/jfs_logmgr.c:-1
jfs_umount+0x2fb/0x3d0 fs/jfs/jfs_umount.c:124
jfs_put_super+0x8c/0x190 fs/jfs/super.c:194
generic_shutdown_super+0x13d/0x2d0 fs/super.c:646
kill_block_super+0x44/0x90 fs/super.c:1725
deactivate_locked_super+0xbc/0x130 fs/super.c:476
cleanup_mnt+0x437/0x4d0 fs/namespace.c:1312
task_work_run+0x1d9/0x270 kernel/task_work.c:233
resume_user_mode_work include/linux/resume_user_mode.h:50 [inline]
__exit_to_user_mode_loop kernel/entry/common.c:67 [inline]
exit_to_user_mode_loop+0xf3/0x4d0 kernel/entry/common.c:98
__exit_to_user_mode_prepare include/linux/irq-entry-common.h:207 [inline]
syscall_exit_to_user_mode_prepare include/linux/irq-entry-common.h:238 [inline]
syscall_exit_to_user_mode include/linux/entry-common.h:318 [inline]
do_syscall_64+0x33e/0xf80 arch/x86/entry/syscall_64.c:100
entry_SYSCALL_64_after_hwframe+0x77/0x7f
The buggy address belongs to the object at ffff88804dbfa800
which belongs to the cache kmalloc-1k of size 1024
The buggy address is located 536 bytes inside of
freed 1024-byte region [ffff88804dbfa800, ffff88804dbfac00)
The buggy address belongs to the physical page:
page: refcount:0 mapcount:0 mapping:0000000000000000 index:0xffff88804dbf9800 pfn:0x4dbf8
head: order:3 mapcount:0 entire_mapcount:0 nr_pages_mapped:0 pincount:0
flags: 0x4fff00000000240(workingset|head|node=1|zone=1|lastcpupid=0x7ff)
page_type: f5(slab)
raw: 04fff00000000240 ffff88801a841dc0 ffffea0001a6e610 ffffea000123f010
raw: ffff88804dbf9800 000000080010000f 00000000f5000000 0000000000000000
head: 04fff00000000240 ffff88801a841dc0 ffffea0001a6e610 ffffea000123f010
head: ffff88804dbf9800 000000080010000f 00000000f5000000 0000000000000000
head: 04fff00000000003 fffffffffffffe01 00000000ffffffff 00000000ffffffff
head: ffffffffffffffff 0000000000000000 00000000ffffffff 0000000000000008
page dumped because: kasan: bad access detected
page_owner tracks the page as allocated
page last allocated via order 3, migratetype Unmovable, gfp_mask 0xd20c0(__GFP_IO|__GFP_FS|__GFP_NOWARN|__GFP_NORETRY|__GFP_COMP|__GFP_NOMEMALLOC), pid 6080, tgid 6080 (syz-executor), ts 85500584456, free_ts 84013765231
set_page_owner include/linux/page_owner.h:32 [inline]
post_alloc_hook+0x231/0x280 mm/page_alloc.c:1858
prep_new_page mm/page_alloc.c:1866 [inline]
get_page_from_freelist+0x24ba/0x2540 mm/page_alloc.c:3946
__alloc_frozen_pages_noprof+0x18d/0x380 mm/page_alloc.c:5226
alloc_slab_page mm/slub.c:3278 [inline]
allocate_slab+0x77/0x660 mm/slub.c:3467
new_slab mm/slub.c:3525 [inline]
refill_objects+0x339/0x3d0 mm/slub.c:7255
refill_sheaf mm/slub.c:2816 [inline]
__pcs_replace_empty_main+0x321/0x720 mm/slub.c:4651
alloc_from_pcs mm/slub.c:4749 [inline]
slab_alloc_node mm/slub.c:4883 [inline]
__do_kmalloc_node mm/slub.c:5294 [inline]
__kmalloc_noprof+0x474/0x760 mm/slub.c:5307
kmalloc_noprof include/linux/slab.h:954 [inline]
kzalloc_noprof include/linux/slab.h:1188 [inline]
__alloc_workqueue+0x100/0x1c00 kernel/workqueue.c:5815
alloc_workqueue_va kernel/workqueue.c:5917 [inline]
alloc_workqueue_noprof+0xe3/0x210 kernel/workqueue.c:5933
tipc_crypto_start+0xd8/0x640 net/tipc/crypto.c:1472
tipc_init_net+0x213/0x330 net/tipc/core.c:72
ops_init+0x35c/0x5c0 net/core/net_namespace.c:137
setup_net+0x118/0x340 net/core/net_namespace.c:446
copy_net_ns+0x3e2/0x570 net/core/net_namespace.c:579
create_new_namespaces+0x3e7/0x6a0 kernel/nsproxy.c:132
unshare_nsproxy_namespaces+0x149/0x190 kernel/nsproxy.c:234
page last free pid 5978 tgid 5978 stack trace:
reset_page_owner include/linux/page_owner.h:25 [inline]
__free_pages_prepare mm/page_alloc.c:1402 [inline]
__free_frozen_pages+0xb84/0xcd0 mm/page_alloc.c:2943
__slab_free+0x274/0x2c0 mm/slub.c:5612
qlink_free mm/kasan/quarantine.c:163 [inline]
qlist_free_all+0x99/0x100 mm/kasan/quarantine.c:179
kasan_quarantine_reduce+0x148/0x160 mm/kasan/quarantine.c:286
__kasan_slab_alloc+0x22/0x80 mm/kasan/common.c:350
kasan_slab_alloc include/linux/kasan.h:253 [inline]
slab_post_alloc_hook mm/slub.c:4569 [inline]
slab_alloc_node mm/slub.c:4898 [inline]
kmem_cache_alloc_node_noprof+0x384/0x690 mm/slub.c:4950
__alloc_skb+0x1d0/0x7d0 net/core/skbuff.c:702
alloc_skb include/linux/skbuff.h:1383 [inline]
nlmsg_new include/net/netlink.h:1055 [inline]
netlink_ack+0x146/0xa50 net/netlink/af_netlink.c:2487
netlink_rcv_skb+0x2b6/0x4b0 net/netlink/af_netlink.c:2556
netlink_unicast_kernel net/netlink/af_netlink.c:1318 [inline]
netlink_unicast+0x75c/0x8e0 net/netlink/af_netlink.c:1344
netlink_sendmsg+0x813/0xb40 net/netlink/af_netlink.c:1894
sock_sendmsg_nosec net/socket.c:787 [inline]
__sock_sendmsg+0x167/0x1b0 net/socket.c:802
__sys_sendto+0x3c0/0x550 net/socket.c:2265
__do_sys_sendto net/socket.c:2272 [inline]
__se_sys_sendto net/socket.c:2268 [inline]
__x64_sys_sendto+0xde/0x100 net/socket.c:2268
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0x15f/0xf80 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x77/0x7f
Memory state around the buggy address:
ffff88804dbfa900: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
ffff88804dbfa980: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
>ffff88804dbfaa00: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
^
ffff88804dbfaa80: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
ffff88804dbfab00: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
==================================================================
ReproducedFaultInjection:]
|
| 6/1 |
2026/05/11 23:17 |
action |
codesearch-prepare |
12m
Results: map[Index:codesearch-index]
|
| 7/1 |
2026/05/11 23:30 |
agent |
debugger |
18m
Model:
Instruction:
You are an experienced Linux kernel developer tasked with debugging a kernel crash root cause.
You need to provide a detailed explanation of the root cause for another developer to be
able to write a fix for the bug based on your explanation. Include all relevant details
into the response: function/struct/field/etc names, code snippets, line numbers,
macro/enum values, etc.
Prefer calling several tools at the same time to save round-trips.
Prompt:
The crash is:
... Log Wrap ... Log Wrap ... Log Wrap ...
==================================================================
BUG: KASAN: slab-use-after-free in lmLogSync+0x9bb/0xa50 fs/jfs/jfs_logmgr.c:1003
Write of size 4 at addr ffff88804dbfaa18 by task jfsCommit/122
CPU: 1 UID: 0 PID: 122 Comm: jfsCommit Not tainted syzkaller #1 PREEMPT(full)
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
Call Trace:
<TASK>
dump_stack_lvl+0xe8/0x150 lib/dump_stack.c:120
print_address_description+0x55/0x1e0 mm/kasan/report.c:378
print_report+0x58/0x70 mm/kasan/report.c:482
kasan_report+0x117/0x150 mm/kasan/report.c:595
lmLogSync+0x9bb/0xa50 fs/jfs/jfs_logmgr.c:1003
jfs_syncpt+0x7b/0x90 fs/jfs/jfs_logmgr.c:1039
txEnd+0x2e5/0x530 fs/jfs/jfs_txnmgr.c:551
txLazyCommit fs/jfs/jfs_txnmgr.c:2686 [inline]
jfs_lazycommit+0x5b8/0xaa0 fs/jfs/jfs_txnmgr.c:2735
kthread+0x388/0x470 kernel/kthread.c:436
ret_from_fork+0x514/0xb70 arch/x86/kernel/process.c:158
ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245
</TASK>
Allocated by task 6683:
kasan_save_stack mm/kasan/common.c:57 [inline]
kasan_save_track+0x3e/0x80 mm/kasan/common.c:78
poison_kmalloc_redzone mm/kasan/common.c:398 [inline]
__kasan_kmalloc+0x93/0xb0 mm/kasan/common.c:415
kasan_kmalloc include/linux/kasan.h:263 [inline]
__kmalloc_cache_noprof+0x31c/0x660 mm/slub.c:5419
kmalloc_noprof include/linux/slab.h:950 [inline]
kzalloc_noprof include/linux/slab.h:1188 [inline]
open_inline_log fs/jfs/jfs_logmgr.c:1157 [inline]
lmLogOpen+0x2d1/0xfa0 fs/jfs/jfs_logmgr.c:1067
jfs_mount_rw+0xee/0x670 fs/jfs/jfs_mount.c:257
jfs_fill_super+0x754/0xd80 fs/jfs/super.c:532
get_tree_bdev_flags+0x431/0x4f0 fs/super.c:1694
vfs_get_tree+0x92/0x2a0 fs/super.c:1754
fc_mount fs/namespace.c:1193 [inline]
do_new_mount_fc fs/namespace.c:3758 [inline]
do_new_mount+0x341/0xd30 fs/namespace.c:3834
do_mount fs/namespace.c:4167 [inline]
__do_sys_mount fs/namespace.c:4383 [inline]
__se_sys_mount+0x31d/0x420 fs/namespace.c:4360
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0x15f/0xf80 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x77/0x7f
Freed by task 6065:
kasan_save_stack mm/kasan/common.c:57 [inline]
kasan_save_track+0x3e/0x80 mm/kasan/common.c:78
kasan_save_free_info+0x46/0x50 mm/kasan/generic.c:584
poison_slab_object mm/kasan/common.c:253 [inline]
__kasan_slab_free+0x5c/0x80 mm/kasan/common.c:285
kasan_slab_free include/linux/kasan.h:235 [inline]
slab_free_hook mm/slub.c:2689 [inline]
slab_free mm/slub.c:6250 [inline]
kfree+0x1c5/0x640 mm/slub.c:6565
lmLogClose+0x297/0x520 fs/jfs/jfs_logmgr.c:-1
jfs_umount+0x2fb/0x3d0 fs/jfs/jfs_umount.c:124
jfs_put_super+0x8c/0x190 fs/jfs/super.c:194
generic_shutdown_super+0x13d/0x2d0 fs/super.c:646
kill_block_super+0x44/0x90 fs/super.c:1725
deactivate_locked_super+0xbc/0x130 fs/super.c:476
cleanup_mnt+0x437/0x4d0 fs/namespace.c:1312
task_work_run+0x1d9/0x270 kernel/task_work.c:233
resume_user_mode_work include/linux/resume_user_mode.h:50 [inline]
__exit_to_user_mode_loop kernel/entry/common.c:67 [inline]
exit_to_user_mode_loop+0xf3/0x4d0 kernel/entry/common.c:98
__exit_to_user_mode_prepare include/linux/irq-entry-common.h:207 [inline]
syscall_exit_to_user_mode_prepare include/linux/irq-entry-common.h:238 [inline]
syscall_exit_to_user_mode include/linux/entry-common.h:318 [inline]
do_syscall_64+0x33e/0xf80 arch/x86/entry/syscall_64.c:100
entry_SYSCALL_64_after_hwframe+0x77/0x7f
The buggy address belongs to the object at ffff88804dbfa800
which belongs to the cache kmalloc-1k of size 1024
The buggy address is located 536 bytes inside of
freed 1024-byte region [ffff88804dbfa800, ffff88804dbfac00)
The buggy address belongs to the physical page:
page: refcount:0 mapcount:0 mapping:0000000000000000 index:0xffff88804dbf9800 pfn:0x4dbf8
head: order:3 mapcount:0 entire_mapcount:0 nr_pages_mapped:0 pincount:0
flags: 0x4fff00000000240(workingset|head|node=1|zone=1|lastcpupid=0x7ff)
page_type: f5(slab)
raw: 04fff00000000240 ffff88801a841dc0 ffffea0001a6e610 ffffea000123f010
raw: ffff88804dbf9800 000000080010000f 00000000f5000000 0000000000000000
head: 04fff00000000240 ffff88801a841dc0 ffffea0001a6e610 ffffea000123f010
head: ffff88804dbf9800 000000080010000f 00000000f5000000 0000000000000000
head: 04fff00000000003 fffffffffffffe01 00000000ffffffff 00000000ffffffff
head: ffffffffffffffff 0000000000000000 00000000ffffffff 0000000000000008
page dumped because: kasan: bad access detected
page_owner tracks the page as allocated
page last allocated via order 3, migratetype Unmovable, gfp_mask 0xd20c0(__GFP_IO|__GFP_FS|__GFP_NOWARN|__GFP_NORETRY|__GFP_COMP|__GFP_NOMEMALLOC), pid 6080, tgid 6080 (syz-executor), ts 85500584456, free_ts 84013765231
set_page_owner include/linux/page_owner.h:32 [inline]
post_alloc_hook+0x231/0x280 mm/page_alloc.c:1858
prep_new_page mm/page_alloc.c:1866 [inline]
get_page_from_freelist+0x24ba/0x2540 mm/page_alloc.c:3946
__alloc_frozen_pages_noprof+0x18d/0x380 mm/page_alloc.c:5226
alloc_slab_page mm/slub.c:3278 [inline]
allocate_slab+0x77/0x660 mm/slub.c:3467
new_slab mm/slub.c:3525 [inline]
refill_objects+0x339/0x3d0 mm/slub.c:7255
refill_sheaf mm/slub.c:2816 [inline]
__pcs_replace_empty_main+0x321/0x720 mm/slub.c:4651
alloc_from_pcs mm/slub.c:4749 [inline]
slab_alloc_node mm/slub.c:4883 [inline]
__do_kmalloc_node mm/slub.c:5294 [inline]
__kmalloc_noprof+0x474/0x760 mm/slub.c:5307
kmalloc_noprof include/linux/slab.h:954 [inline]
kzalloc_noprof include/linux/slab.h:1188 [inline]
__alloc_workqueue+0x100/0x1c00 kernel/workqueue.c:5815
alloc_workqueue_va kernel/workqueue.c:5917 [inline]
alloc_workqueue_noprof+0xe3/0x210 kernel/workqueue.c:5933
tipc_crypto_start+0xd8/0x640 net/tipc/crypto.c:1472
tipc_init_net+0x213/0x330 net/tipc/core.c:72
ops_init+0x35c/0x5c0 net/core/net_namespace.c:137
setup_net+0x118/0x340 net/core/net_namespace.c:446
copy_net_ns+0x3e2/0x570 net/core/net_namespace.c:579
create_new_namespaces+0x3e7/0x6a0 kernel/nsproxy.c:132
unshare_nsproxy_namespaces+0x149/0x190 kernel/nsproxy.c:234
page last free pid 5978 tgid 5978 stack trace:
reset_page_owner include/linux/page_owner.h:25 [inline]
__free_pages_prepare mm/page_alloc.c:1402 [inline]
__free_frozen_pages+0xb84/0xcd0 mm/page_alloc.c:2943
__slab_free+0x274/0x2c0 mm/slub.c:5612
qlink_free mm/kasan/quarantine.c:163 [inline]
qlist_free_all+0x99/0x100 mm/kasan/quarantine.c:179
kasan_quarantine_reduce+0x148/0x160 mm/kasan/quarantine.c:286
__kasan_slab_alloc+0x22/0x80 mm/kasan/common.c:350
kasan_slab_alloc include/linux/kasan.h:253 [inline]
slab_post_alloc_hook mm/slub.c:4569 [inline]
slab_alloc_node mm/slub.c:4898 [inline]
kmem_cache_alloc_node_noprof+0x384/0x690 mm/slub.c:4950
__alloc_skb+0x1d0/0x7d0 net/core/skbuff.c:702
alloc_skb include/linux/skbuff.h:1383 [inline]
nlmsg_new include/net/netlink.h:1055 [inline]
netlink_ack+0x146/0xa50 net/netlink/af_netlink.c:2487
netlink_rcv_skb+0x2b6/0x4b0 net/netlink/af_netlink.c:2556
netlink_unicast_kernel net/netlink/af_netlink.c:1318 [inline]
netlink_unicast+0x75c/0x8e0 net/netlink/af_netlink.c:1344
netlink_sendmsg+0x813/0xb40 net/netlink/af_netlink.c:1894
sock_sendmsg_nosec net/socket.c:787 [inline]
__sock_sendmsg+0x167/0x1b0 net/socket.c:802
__sys_sendto+0x3c0/0x550 net/socket.c:2265
__do_sys_sendto net/socket.c:2272 [inline]
__se_sys_sendto net/socket.c:2268 [inline]
__x64_sys_sendto+0xde/0x100 net/socket.c:2268
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0x15f/0xf80 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x77/0x7f
Memory state around the buggy address:
ffff88804dbfa900: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
ffff88804dbfa980: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
>ffff88804dbfaa00: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
^
ffff88804dbfaa80: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
ffff88804dbfab00: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
==================================================================
The following C code is a draft of the vulnerable syscall sequence. Keep in mind that
it may lack the precise threading, sandboxing, and some arguments of a working reproducer:
// autogenerated by syzkaller (https://github.com/google/syzkaller)
#define _GNU_SOURCE
#include <endian.h>
#include <errno.h>
#include <fcntl.h>
#include <setjmp.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>
#include <linux/loop.h>
#ifndef __NR_memfd_create
#define __NR_memfd_create 319
#endif
static unsigned long long procid;
//% This code is derived from puff.{c,h}, found in the zlib development. The
//% original files come with the following copyright notice:
//% Copyright (C) 2002-2013 Mark Adler, all rights reserved
//% version 2.3, 21 Jan 2013
//% This software is provided 'as-is', without any express or implied
//% warranty. In no event will the author be held liable for any damages
//% arising from the use of this software.
//% Permission is granted to anyone to use this software for any purpose,
//% including commercial applications, and to alter it and redistribute it
//% freely, subject to the following restrictions:
//% 1. The origin of this software must not be misrepresented; you must not
//% claim that you wrote the original software. If you use this software
//% in a product, an acknowledgment in the product documentation would be
//% appreciated but is not required.
//% 2. Altered source versions must be plainly marked as such, and must not be
//% misrepresented as being the original software.
//% 3. This notice may not be removed or altered from any source distribution.
//% Mark Adler madler@alumni.caltech.edu
//% BEGIN CODE DERIVED FROM puff.{c,h}
#define MAXBITS 15
#define MAXLCODES 286
#define MAXDCODES 30
#define MAXCODES (MAXLCODES + MAXDCODES)
#define FIXLCODES 288
struct puff_state {
unsigned char* out;
unsigned long outlen;
unsigned long outcnt;
const unsigned char* in;
unsigned long inlen;
unsigned long incnt;
int bitbuf;
int bitcnt;
jmp_buf env;
};
static int puff_bits(struct puff_state* s, int need)
{
long val = s->bitbuf;
while (s->bitcnt < need) {
if (s->incnt == s->inlen)
longjmp(s->env, 1);
val |= (long)(s->in[s->incnt++]) << s->bitcnt;
s->bitcnt += 8;
}
s->bitbuf = (int)(val >> need);
s->bitcnt -= need;
return (int)(val & ((1L << need) - 1));
}
static int puff_stored(struct puff_state* s)
{
s->bitbuf = 0;
s->bitcnt = 0;
if (s->incnt + 4 > s->inlen)
return 2;
unsigned len = s->in[s->incnt++];
len |= s->in[s->incnt++] << 8;
if (s->in[s->incnt++] != (~len & 0xff) ||
s->in[s->incnt++] != ((~len >> 8) & 0xff))
return -2;
if (s->incnt + len > s->inlen)
return 2;
if (s->outcnt + len > s->outlen)
return 1;
for (; len--; s->outcnt++, s->incnt++) {
if (s->in[s->incnt])
s->out[s->outcnt] = s->in[s->incnt];
}
return 0;
}
struct puff_huffman {
short* count;
short* symbol;
};
static int puff_decode(struct puff_state* s, const struct puff_huffman* h)
{
int first = 0;
int index = 0;
int bitbuf = s->bitbuf;
int left = s->bitcnt;
int code = first = index = 0;
int len = 1;
short* next = h->count + 1;
while (1) {
while (left--) {
code |= bitbuf & 1;
bitbuf >>= 1;
int count = *next++;
if (code - count < first) {
s->bitbuf = bitbuf;
s->bitcnt = (s->bitcnt - len) & 7;
return h->symbol[index + (code - first)];
}
index += count;
first += count;
first <<= 1;
code <<= 1;
len++;
}
left = (MAXBITS + 1) - len;
if (left == 0)
break;
if (s->incnt == s->inlen)
longjmp(s->env, 1);
bitbuf = s->in[s->incnt++];
if (left > 8)
left = 8;
}
return -10;
}
static int puff_construct(struct puff_huffman* h, const short* length, int n)
{
int len;
for (len = 0; len <= MAXBITS; len++)
h->count[len] = 0;
int symbol;
for (symbol = 0; symbol < n; symbol++)
(h->count[length[symbol]])++;
if (h->count[0] == n)
return 0;
int left = 1;
for (len = 1; len <= MAXBITS; len++) {
left <<= 1;
left -= h->count[len];
if (left < 0)
return left;
}
short offs[MAXBITS + 1];
offs[1] = 0;
for (len = 1; len < MAXBITS; len++)
offs[len + 1] = offs[len] + h->count[len];
for (symbol = 0; symbol < n; symbol++)
if (length[symbol] != 0)
h->symbol[offs[length[symbol]]++] = symbol;
return left;
}
static int puff_codes(struct puff_state* s,
const struct puff_huffman* lencode,
const struct puff_huffman* distcode)
{
static const short lens[29] = {
3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258};
static const short lext[29] = {
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0};
static const short dists[30] = {
1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
8193, 12289, 16385, 24577};
static const short dext[30] = {
0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
12, 12, 13, 13};
int symbol;
do {
symbol = puff_decode(s, lencode);
if (symbol < 0)
return symbol;
if (symbol < 256) {
if (s->outcnt == s->outlen)
return 1;
if (symbol)
s->out[s->outcnt] = symbol;
s->outcnt++;
} else if (symbol > 256) {
symbol -= 257;
if (symbol >= 29)
return -10;
int len = lens[symbol] + puff_bits(s, lext[symbol]);
symbol = puff_decode(s, distcode);
if (symbol < 0)
return symbol;
unsigned dist = dists[symbol] + puff_bits(s, dext[symbol]);
if (dist > s->outcnt)
return -11;
if (s->outcnt + len > s->outlen)
return 1;
while (len--) {
if (dist <= s->outcnt && s->out[s->outcnt - dist])
s->out[s->outcnt] = s->out[s->outcnt - dist];
s->outcnt++;
}
}
} while (symbol != 256);
return 0;
}
static int puff_fixed(struct puff_state* s)
{
static int virgin = 1;
static short lencnt[MAXBITS + 1], lensym[FIXLCODES];
static short distcnt[MAXBITS + 1], distsym[MAXDCODES];
static struct puff_huffman lencode, distcode;
if (virgin) {
lencode.count = lencnt;
lencode.symbol = lensym;
distcode.count = distcnt;
distcode.symbol = distsym;
short lengths[FIXLCODES];
int symbol;
for (symbol = 0; symbol < 144; symbol++)
lengths[symbol] = 8;
for (; symbol < 256; symbol++)
lengths[symbol] = 9;
for (; symbol < 280; symbol++)
lengths[symbol] = 7;
for (; symbol < FIXLCODES; symbol++)
lengths[symbol] = 8;
puff_construct(&lencode, lengths, FIXLCODES);
for (symbol = 0; symbol < MAXDCODES; symbol++)
lengths[symbol] = 5;
puff_construct(&distcode, lengths, MAXDCODES);
virgin = 0;
}
return puff_codes(s, &lencode, &distcode);
}
static int puff_dynamic(struct puff_state* s)
{
static const short order[19] =
{16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
int nlen = puff_bits(s, 5) + 257;
int ndist = puff_bits(s, 5) + 1;
int ncode = puff_bits(s, 4) + 4;
if (nlen > MAXLCODES || ndist > MAXDCODES)
return -3;
short lengths[MAXCODES];
int index;
for (index = 0; index < ncode; index++)
lengths[order[index]] = puff_bits(s, 3);
for (; index < 19; index++)
lengths[order[index]] = 0;
short lencnt[MAXBITS + 1], lensym[MAXLCODES];
struct puff_huffman lencode = {lencnt, lensym};
int err = puff_construct(&lencode, lengths, 19);
if (err != 0)
return -4;
index = 0;
while (index < nlen + ndist) {
int symbol;
int len;
symbol = puff_decode(s, &lencode);
if (symbol < 0)
return symbol;
if (symbol < 16)
lengths[index++] = symbol;
else {
len = 0;
if (symbol == 16) {
if (index == 0)
return -5;
len = lengths[index - 1];
symbol = 3 + puff_bits(s, 2);
} else if (symbol == 17)
symbol = 3 + puff_bits(s, 3);
else
symbol = 11 + puff_bits(s, 7);
if (index + symbol > nlen + ndist)
return -6;
while (symbol--)
lengths[index++] = len;
}
}
if (lengths[256] == 0)
return -9;
err = puff_construct(&lencode, lengths, nlen);
if (err && (err < 0 || nlen != lencode.count[0] + lencode.count[1]))
return -7;
short distcnt[MAXBITS + 1], distsym[MAXDCODES];
struct puff_huffman distcode = {distcnt, distsym};
err = puff_construct(&distcode, lengths + nlen, ndist);
if (err && (err < 0 || ndist != distcode.count[0] + distcode.count[1]))
return -8;
return puff_codes(s, &lencode, &distcode);
}
static int puff(
unsigned char* dest,
unsigned long* destlen,
const unsigned char* source,
unsigned long sourcelen)
{
struct puff_state s = {
.out = dest,
.outlen = *destlen,
.outcnt = 0,
.in = source,
.inlen = sourcelen,
.incnt = 0,
.bitbuf = 0,
.bitcnt = 0,
};
int err;
if (setjmp(s.env) != 0)
err = 2;
else {
int last;
do {
last = puff_bits(&s, 1);
int type = puff_bits(&s, 2);
err = type == 0 ? puff_stored(&s) : (type == 1 ? puff_fixed(&s) : (type == 2 ? puff_dynamic(&s) : -1));
if (err != 0)
break;
} while (!last);
}
*destlen = s.outcnt;
return err;
}
//% END CODE DERIVED FROM puff.{c,h}
#define ZLIB_HEADER_WIDTH 2
static int puff_zlib_to_file(const unsigned char* source, unsigned long sourcelen, int dest_fd)
{
if (sourcelen < ZLIB_HEADER_WIDTH)
return 0;
source += ZLIB_HEADER_WIDTH;
sourcelen -= ZLIB_HEADER_WIDTH;
const unsigned long max_destlen = 132 << 20;
void* ret = mmap(0, max_destlen, PROT_WRITE | PROT_READ, MAP_PRIVATE | MAP_ANON, -1, 0);
if (ret == MAP_FAILED)
return -1;
unsigned char* dest = (unsigned char*)ret;
unsigned long destlen = max_destlen;
int err = puff(dest, &destlen, source, sourcelen);
if (err) {
munmap(dest, max_destlen);
errno = -err;
return -1;
}
if (write(dest_fd, dest, destlen) != (ssize_t)destlen) {
munmap(dest, max_destlen);
return -1;
}
return munmap(dest, max_destlen);
}
static int setup_loop_device(unsigned char* data, unsigned long size, const char* loopname, int* loopfd_p)
{
int err = 0, loopfd = -1;
int memfd = syscall(__NR_memfd_create, "syzkaller", 0);
if (memfd == -1) {
err = errno;
goto error;
}
if (puff_zlib_to_file(data, size, memfd)) {
err = errno;
goto error_close_memfd;
}
loopfd = open(loopname, O_RDWR);
if (loopfd == -1) {
err = errno;
goto error_close_memfd;
}
if (ioctl(loopfd, LOOP_SET_FD, memfd)) {
if (errno != EBUSY) {
err = errno;
goto error_close_loop;
}
ioctl(loopfd, LOOP_CLR_FD, 0);
usleep(1000);
if (ioctl(loopfd, LOOP_SET_FD, memfd)) {
err = errno;
goto error_close_loop;
}
}
close(memfd);
*loopfd_p = loopfd;
return 0;
error_close_loop:
close(loopfd);
error_close_memfd:
close(memfd);
error:
errno = err;
return -1;
}
static void reset_loop_device(const char* loopname)
{
int loopfd = open(loopname, O_RDWR);
if (loopfd == -1) {
return;
}
if (ioctl(loopfd, LOOP_CLR_FD, 0)) {
}
close(loopfd);
}
static long syz_mount_image(
volatile long fsarg,
volatile long dir,
volatile long flags,
volatile long optsarg,
volatile long change_dir,
volatile unsigned long size,
volatile long image)
{
unsigned char* data = (unsigned char*)image;
int res = -1, err = 0, need_loop_device = !!size;
char* mount_opts = (char*)optsarg;
char* target = (char*)dir;
char* fs = (char*)fsarg;
char* source = NULL;
char loopname[64];
if (need_loop_device) {
int loopfd;
memset(loopname, 0, sizeof(loopname));
snprintf(loopname, sizeof(loopname), "/dev/loop%llu", procid);
if (setup_loop_device(data, size, loopname, &loopfd) == -1)
return -1;
close(loopfd);
source = loopname;
}
mkdir(target, 0777);
char opts[256];
memset(opts, 0, sizeof(opts));
if (strlen(mount_opts) > (sizeof(opts) - 32)) {
}
strncpy(opts, mount_opts, sizeof(opts) - 32);
if (strcmp(fs, "iso9660") == 0) {
flags |= MS_RDONLY;
} else if (strncmp(fs, "ext", 3) == 0) {
bool has_remount_ro = false;
char* remount_ro_start = strstr(opts, "errors=remount-ro");
if (remount_ro_start != NULL) {
char after = *(remount_ro_start + strlen("errors=remount-ro"));
char before = remount_ro_start == opts ? '\0' : *(remount_ro_start - 1);
has_remount_ro = ((before == '\0' || before == ',') && (after == '\0' || after == ','));
}
if (strstr(opts, "errors=panic") || !has_remount_ro)
strcat(opts, ",errors=continue");
} else if (strcmp(fs, "xfs") == 0) {
strcat(opts, ",nouuid");
} else if (strncmp(fs, "gfs2", 4) == 0 && (strstr(opts, "errors=panic") || strstr(opts, "debug"))) {
strcat(opts, ",errors=withdraw");
}
res = mount(source, target, fs, flags, opts);
if (res == -1) {
err = errno;
goto error_clear_loop;
}
res = open(target, O_RDONLY | O_DIRECTORY);
if (res == -1) {
err = errno;
goto error_clear_loop;
}
if (change_dir) {
res = chdir(target);
if (res == -1) {
err = errno;
}
}
error_clear_loop:
if (need_loop_device)
reset_loop_device(loopname);
errno = err;
return res;
}
int main(void)
{
syscall(__NR_mmap, /*addr=*/0x1ffffffff000ul, /*len=*/0x1000ul, /*prot=*/0ul, /*flags=MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE*/0x32ul, /*fd=*/(intptr_t)-1, /*offset=*/0ul);
syscall(__NR_mmap, /*addr=*/0x200000000000ul, /*len=*/0x1000000ul, /*prot=PROT_WRITE|PROT_READ|PROT_EXEC*/7ul, /*flags=MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE*/0x32ul, /*fd=*/(intptr_t)-1, /*offset=*/0ul);
syscall(__NR_mmap, /*addr=*/0x200001000000ul, /*len=*/0x1000ul, /*prot=*/0ul, /*flags=MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE*/0x32ul, /*fd=*/(intptr_t)-1, /*offset=*/0ul);
const char* reason;
(void)reason;
if (write(1, "executing program\n", sizeof("executing program\n") - 1)) {}
// syz_mount_image$jfs arguments: [
// fs: ptr[in, buffer] {
// buffer: {6a 66 73 00} (length 0x4)
// }
// dir: ptr[in, buffer] {
// buffer: {2e 2f 66 69 6c 65 30 00} (length 0x8)
// }
// flags: mount_flags = 0x1000002 (8 bytes)
// opts: ptr[in, fs_options[jfs_options]] {
// fs_options[jfs_options] {
// elems: array[fs_opt_elem[jfs_options]] {
// }
// common: array[fs_opt_elem[fs_options_common]] {
// }
// null: const = 0x0 (1 bytes)
// }
// }
// chdir: int8 = 0x1 (1 bytes)
// size: len = 0x6161 (8 bytes)
// img: ptr[in, buffer] {
// buffer: (compressed buffer with length 0x6160)
// }
// ]
// returns fd_dir
memcpy((void*)0x200000000000, "jfs\000", 4);
memcpy((void*)0x200000000180, "./file0\000", 8);
*(uint8_t*)0x2000000002c0 = 0;
memcpy((void*)0x20000000d680, "\x78\x9c\xec\xdd\x4b\x8f\x1c\x57\xd9\x07\xf0\xa7\xfa\x36\x17\xbf\x71\xac\x2c\xa2\xbc\x16\x42\x93\xc4\x5c\x42\x88\xaf\xc1\x18\x02\x24\x59\xc0\x82\x0d\x0b\xe4\x2d\xb2\x35\x99\x44\x16\x0e\x20\xdb\x20\x27\xb2\xf0\x44\xb3\x61\xc1\x87\x00\x21\xb1\x44\x88\x25\x2b\x3e\x40\x16\x6c\xd9\xf1\x01\xb0\x64\x23\x81\xb2\x4a\xa1\x9a\x39\x67\x5c\xd3\xe9\x76\x8f\xed\x4c\x57\xcf\x9c\xdf\x4f\x1a\x57\x3d\x7d\xaa\xa6\x4f\xf9\xdf\xd5\x97\xa9\xaa\x3e\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc4\x0f\x7f\xf0\xe3\x73\x55\x44\x5c\xf9\x55\xba\xe1\x44\xc4\xff\x45\x3f\xa2\x17\xb1\xd2\xd4\x6b\x11\xb1\xb2\x76\x22\x2f\x3f\x88\x88\x17\x62\xbb\x39\x9e\x8f\x88\xe1\x52\x44\x95\x1b\x9f\x8d\x78\x3d\x22\x3e\x3e\x1e\x71\xff\xc1\x9d\xf5\xe6\xa6\xf3\xfb\xec\xc7\xf7\xff\xfc\x8f\x3f\xfc\xe4\xd8\x8f\xfe\xfe\xa7\xe1\x99\xff\xfe\xe5\x56\xff\x8d\x69\xcb\xdd\xbe\xfd\xdb\xff\xfc\xf5\xee\x93\x6f\x2f\x00\x00\x00\x94\xa8\xae\xeb\xba\x4a\x1f\xf3\x4f\xa6\xcf\xf7\xbd\xae\x3b\x05\x00\xcc\x45\x7e\xfd\xaf\x93\x7c\xbb\x7a\xe1\xea\xcd\x05\xeb\x8f\x5a\xad\x56\xab\x0f\x61\xdd\x56\x4f\x76\xb7\x5d\x44\xc4\x66\x7b\x9d\xe6\x3d\x83\xc3\xf1\x00\x70\xc8\x6c\xc6\x27\x5d\x77\x81\x0e\xc9\xbf\x68\x83\x88\x38\xd6\x75\x27\x80\x85\x56\x75\xdd\x01\x0e\xc4\xfd\x07\x77\xd6\xab\x94\x6f\xd5\x7e\x3d\x58\xdb\x69\xcf\xe7\x82\xec\xc9\x7f\xb3\xda\xbd\xbe\x63\xda\x74\x96\xf1\x73\x4c\xe6\xf5\xf8\xda\x8a\x7e\x3c\x37\xa5\x3f\x2b\x73\xea\xc3\x22\xc9\xf9\xf7\xc6\xf3\xbf\xb2\xd3\x3e\x4a\xcb\x1d\x74\xfe\xf3\x32\x2d\xff\xd1\xce\xa5\x4f\xc5\xc9\xf9\xf7\xc7\xf3\x1f\x73\x74\xf2\xef\x4d\xcc\xbf\x54\x39\xff\xc1\x63\xe5\xdf\x97\x3f\x00\x00\x00\x00\x00\x2c\xb0\xfc\xf7\xff\x13\x1d\x1f\xff\x5d\x7a\xfa\x4d\xd9\x97\x47\x1d\xff\x5d\x9b\x53\x1f\x00\x00\x00\x00\x00\x00\x00\xe0\xf3\xf6\xb4\xe3\xff\xed\xaa\x8c\xff\x07\x00\x00\x00\x8b\xaa\xf9\xac\xde\xf8\xdd\xf1\x87\xb7\x4d\xfb\x2e\xb6\xe6\xf6\xcb\x55\xc4\x33\x63\xcb\x03\x85\x49\x17\xcb\xac\x76\xdd\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x28\xc9\x60\xe7\x1c\xde\xcb\x55\xc4\x30\x22\x9e\x59\x5d\xad\xeb\xba\xf9\x69\x1b\xaf\x1f\xd7\xd3\xae\x7f\xd8\x95\xbe\xfd\x50\xb2\xae\x9f\xe4\x01\x00\x60\xc7\xc7\xc7\xc7\xae\xe5\xaf\x22\x96\x23\xe2\x72\xfa\xae\xbf\xe1\xea\xea\x6a\x5d\x2f\xaf\xac\xd6\xab\xf5\xca\x52\x7e\x3f\x3b\x5a\x5a\xae\x57\x5a\x9f\x6b\xf3\xb4\xb9\x6d\x69\xb4\x8f\x37\xc4\x83\x51\xdd\xfc\xb2\xe5\xd6\x7a\x6d\xb3\x3e\x2f\xcf\x6a\x1f\xff\x7d\xcd\x7d\x8d\xea\xfe\x3e\x3a\x36\x1f\x1d\x06\x0e\x00\x11\xb1\xf3\x6a\x74\xdf\x2b\xd2\x11\x53\xd7\xcf\x46\xd7\xef\x72\x38\x1c\xec\xff\x47\x8f\xfd\x9f\xfd\xe8\xfa\x71\x0a\x00\x00\x00\x1c\xbc\xba\xae\xeb\x2a\x7d\x9d\xf7\xc9\x74\xcc\xbf\xd7\x75\xa7\x00\x80\xb9\xc8\xaf\xff\xe3\xc7\x05\xd4\x6a\xb5\x5a\xad\x56\x1f\xbd\xba\xad\x9e\xec\x6e\xbb\x88\x88\xcd\xf6\x3a\xcd\x7b\x06\xc3\xf1\x03\xc0\x21\xb3\x19\x9f\x74\xdd\x05\x3a\x24\xff\xa2\x0d\x22\xe2\x85\xae\x3b\x01\x2c\xb4\xaa\xeb\x0e\x70\x20\xee\x3f\xb8\xb3\x5e\xa5\x7c\xab\xf6\xeb\x41\x1a\xdf\x3d\x9f\x0b\xb2\x27\xff\xcd\x6a\x7b\xbd\xbc\xfe\xa4\xe9\x2c\xe3\xe7\x98\xcc\xeb\xf1\xb5\x15\xfd\x78\x6e\x4a\x7f\x9e\x9f\x53\x1f\x16\x49\xce\xbf\x37\x9e\xff\x95\x9d\xf6\x51\x5a\xee\xa0\xf3\x9f\x97\x69\xf9\x37\xdb\x79\xa2\x83\xfe\x74\x2d\xe7\xdf\x1f\xcf\x7f\xcc\xd1\xc9\xbf\x37\x31\xff\x52\xe5\xfc\x07\x8f\x95\x7f\x5f\xfe\x00\x00\x00\x00\x00\xb0\xc0\xf2\xdf\xff\x4f\x2c\xd4\xf1\xdf\xd1\x93\x6e\xce\x4c\x8f\x3a\xfe\xbb\x76\x60\xf7\x0a\x00\x00\x00\x00\x00\x00\x00\x07\xeb\xfe\x83\x3b\xeb\xf9\xba\xd7\x7c\xfc\xff\x0b\x13\x96\x73\xfd\xe7\xd1\x94\xf3\xaf\xe4\x5f\xa4\x9c\x7f\x6f\x2c\xff\xaf\x8e\x2d\xd7\x6f\xcd\xdf\x7b\xfb\x61\xfe\xff\x7e\x70\x67\xfd\x8f\xb7\xfe\xf5\xff\x79\xba\xdf\xfc\x97\xf2\x4c\x95\x1e\x59\x55\x7a\x44\x54\xe9\x9e\xaa\x41\x9a\x3e\xcd\xd6\x7d\xd6\xd6\xb0\x3f\x6a\xee\x69\x58\xf5\xfa\x83\x74\xce\x4f\x3d\x7c\x37\xae\xc5\xf5\xd8\x88\xb3\x7b\x96\xed\xa5\xff\x8f\x87\xed\xe7\xf6\xb4\x37\x3d\x1d\x6e\xb7\xd7\xfd\x9d\xf6\xf3\x7b\xda\x07\xbb\xed\x79\xfd\x0b\x7b\xda\x87\xe9\x4c\xa7\x7a\x25\xb7\x9f\x8e\xf5\xf8\x79\x5c\x8f\x77\xb6\xdb\x9b\xb6\xa5\x19\xdb\xbf\x3c\xa3\xbd\x9e\xd1\x9e\xf3\xef\xdb\xff\x8b\x94\xf3\x1f\xb4\x7e\x9a\xfc\x57\x53\x7b\x35\x36\x6d\xdc\xfb\xa8\xf7\x99\xfd\xbe\x3d\x9d\x74\x3f\x6f\x5d\xfb\xe2\x6f\xce\x1e\xfc\xe6\xcc\xb4\x15\xfd\xdd\x6d\x6b\x6b\xb6\xef\xa5\x0e\xfa\xb3\xfd\x7f\x72\x6c\x14\xbf\xbc\xb9\x71\xe3\xf4\xed\xab\xb7\x6e\xdd\x38\x17\x69\xb2\xe7\xd6\xf3\x91\x26\x9f\xb3\x9c\xff\x30\xfd\xec\x3e\xff\xbf\xbc\xd3\x9e\x9f\xf7\xdb\xfb\xeb\xbd\x8f\x46\x8f\x9d\xff\xa2\xd8\x8a\xc1\xd4\xfc\x5f\x6e\xcd\x37\xdb\xfb\xca\x9c\xfb\xd6\x85\x9c\xff\x28\xfd\xe4\xfc\xdf\x49\xed\x93\xf7\xff\xc3\x9c\xff\xf4\xfd\xff\xd5\x0e\xfa\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8f\x52\xd7\xf5\xf6\x25\xa2\x6f\x45\xc4\xc5\x74\xfd\x4f\x57\xd7\x66\x02\x00\xf3\x95\x5f\xff\xeb\x24\xdf\x3e\xaf\xba\x3f\xe7\xfb\x53\xab\x0f\x79\x5d\x2d\x58\x7f\xe6\x5a\x7f\x5a\x2f\x56\x7f\xd4\xea\xc3\x58\xb7\xd5\x93\xbd\xd9\x2e\x22\xe2\x6f\xed\x75\x9a\xf7\x0c\xbf\x9e\xf4\xcb\x00\x80\x45\xf6\x69\x44\xfc\xb3\xeb\x4e\xd0\x19\xf9\x17\x2c\x7f\xdf\x5f\x33\x3d\xd5\x75\x67\x80\xb9\xba\xf9\xc1\x87\x3f\xbd\x7a\xfd\xfa\xc6\x8d\x9b\x5d\xf7\x04\x00\x00\x00\x00\x00\x00\x00\x78\x52\x79\xfc\xcf\xb5\xd6\xf8\xcf\xa7\xea\xba\xbe\x3b\xb6\xdc\x9e\xf1\x5f\xdf\x8e\xb5\xa7\x1d\xff\x73\x90\x67\x76\x07\x18\x9d\x32\x50\x75\xff\xf1\xb7\xe9\x51\xb6\x7a\xa3\x7e\xaf\x35\xdc\xf8\x8b\x31\x6d\xfc\xef\xe1\xee\xdc\xa3\xc6\xff\x1e\xcc\xb8\xbf\xe1\x8c\xf6\xd1\x8c\xf6\xa5\x19\xed\xcb\x33\xda\x27\x5e\xe8\xd1\x92\xf3\x7f\xb1\x35\xde\xf9\xa9\x88\x38\x39\x36\xfc\x7a\x09\xe3\xbf\x8e\x8f\x79\x5f\x82\x9c\xff\x4b\xad\xc7\x73\x93\xff\x57\xc6\x96\x6b\xe7\x5f\xff\xfe\x30\xe7\xdf\xdb\x93\xff\x99\x5b\xef\xff\xe2\xcc\xcd\x0f\x3e\x7c\xed\xda\xfb\x57\xdf\xdb\x78\x6f\xe3\x67\x17\xce\x9d\x3b\x7b\xe1\xe2\xc5\x4b\x97\x2e\x9d\x79\xf7\xda\xf5\x8d\xb3\x3b\xff\x76\xd8\xe3\x83\x95\xf3\xcf\x63\x5f\x3b\x0f\xb4\x2c\x39\xff\x9c\xb9\xfc\xcb\x92\xf3\xff\x52\xaa\xe5\x5f\x96\x9c\xff\x97\x53\x2d\xff\xb2\xe4\xfc\xf3\xfb\x3d\xf9\x97\x25\xe7\x9f\x3f\xfb\xc8\xbf\x2c\x39\xff\x57\x52\x2d\xff\xb2\xe4\xfc\xbf\x96\x6a\xf9\x97\x25\xe7\xff\x6a\xaa\xe5\x5f\x96\x9c\xff\xd7\x53\x2d\xff\xb2\xe4\xfc\x5f\x4b\xb5\xfc\xcb\x92\xf3\x3f\x9d\x6a\xf9\x97\x25\xe7\x7f\x26\xd5\xfb\xcc\x7f\xe5\xa0\xfb\xc5\x7c\xe4\xfc\xf3\x11\x2e\xfb\x7f\x59\x72\xfe\xf9\xcc\x06\xf9\x97\x25\xe7\x7f\x3e\xd5\xf2\x2f\x4b\xce\xff\x42\xaa\xe5\x5f\x96\x9c\xff\xeb\xa9\x96\x7f\x59\x72\xfe\xdf\x48\xb5\xfc\xcb\x92\xf3\xbf\x98\x6a\xf9\x97\x25\xe7\xff\xcd\x54\xcb\xbf\x2c\x39\xff\x4b\xa9\x96\x7f\x59\x72\xfe\xdf\x4a\xb5\xfc\xcb\x92\xf3\xff\x76\xaa\xe5\x5f\x96\x9c\xff\x1b\xa9\x96\x7f\x59\x72\xfe\xdf\x49\xb5\xfc\xcb\x92\xf3\xff\x6e\xaa\xe5\x5f\x96\x9c\xff\xf7\x52\x2d\xff\xb2\xe4\xfc\xdf\x4c\xb5\xfc\xcb\xf2\xf0\xfb\xff\xcd\x98\x31\x63\x26\xcf\x74\xfd\xcc\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8c\x9b\xc7\xe9\xc4\x5d\x6f\x23\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf0\x3f\x76\xe0\x40\x00\x00\x00\x00\x00\xc8\xff\xb5\x11\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xb0\x03\x07\x02\x00\x00\x00\x00\x40\xfe\xaf\x8d\x50\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x85\xbd\x7b\x8b\x91\xeb\xae\xef\x00\x7e\x66\x6f\x5e\x3b\x90\x18\x08\xa9\x93\x9a\xb0\x76\x8c\x31\xce\x26\xbb\xbe\xc4\x17\x5a\x17\x13\xae\x0d\xb7\x92\x10\x0a\xbd\x60\xbb\xde\xb5\x59\xf0\x0d\xaf\x5d\x02\x8d\x6a\x47\x81\x12\x09\xa3\xa2\x8a\xb6\xe1\xa1\x2d\x20\xd4\xe6\xa5\xc2\xaa\x78\xa0\x15\xa0\x3c\xa0\x56\x95\x2a\x41\xfb\x40\x5f\x10\x15\x2a\x0f\x51\x15\x50\x40\xaa\xd4\x56\xc0\x56\x33\xe7\xff\xff\xef\xcc\xec\xec\xcc\xae\x77\xb2\x39\x73\xce\xe7\x23\x25\xbf\xec\xcc\x99\x39\x67\xce\xfc\x67\x76\xbf\x76\xbe\x3b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x34\xdb\xf6\x86\xd9\x4f\xd5\xb2\x2c\xab\xd5\x6a\xf9\x05\x9b\xb3\xec\x45\xf5\xb9\x71\x62\x73\xe3\x92\xd7\xbe\xb0\xc7\x07\x00\x00\x00\xac\xdd\xcf\x1b\xff\x7e\xee\x96\x74\xc1\xd1\x15\xdc\xa8\x69\x9b\x7f\xba\xf3\xdb\x5f\x5d\x58\x58\x58\xc8\xde\x37\xfc\xa7\xa3\x9f\x5b\x58\x48\x57\x4c\x64\xd9\xe8\x86\x2c\x6b\x5c\x17\x5d\xff\xc1\xfb\x6b\xcd\xdb\x04\x8f\x67\xe3\xb5\xa1\xa6\xaf\x87\x7a\xec\x7e\xb8\xc7\xf5\x23\x3d\xae\x1f\xed\x71\xfd\x58\x8f\xeb\x37\xf4\xb8\x7e\xbc\xc7\xf5\x4b\x4e\xc0\x12\x1b\xb3\x5a\xba\xb3\x1d\x8d\xff\xdc\x9c\x9f\xd2\xec\xd6\x6c\xb4\x71\xdd\x8e\x0e\xb7\x7a\xbc\xb6\x61\xa8\x7e\xee\xd2\x6d\xb3\x5a\xe3\x36\x0b\xa3\xa7\xb2\xb9\xec\x4c\x36\x9b\x4d\xb7\x6c\x9f\x6f\x5b\x6b\x6c\xff\xf5\x6d\xf5\x7d\xbd\x35\x8b\xfb\x1a\x6a\xda\xd7\xd6\xfa\x0a\xf9\xc9\xa3\x27\xe3\x31\xd4\xc2\x39\xde\xd1\xb2\xaf\xc5\xfb\x8c\x7e\xf4\xfa\x6c\xe2\xa7\x3f\x79\xf4\xe4\x5f\x5f\x7a\xf6\xf6\x4e\xb3\xe7\x69\x68\xb9\xbf\xfc\x38\x77\x6d\xaf\x1f\xe7\x27\xc2\x25\xf9\xb1\xd6\xb2\x0d\xe9\x9c\xc4\xe3\x1c\x6a\x3a\xce\xad\x1d\x9e\x93\xe1\x96\xe3\xac\x35\x6e\x57\xff\xef\xf6\xe3\x7c\x6e\x85\xc7\x39\xbc\x78\x98\xeb\xaa\xfd\x39\x1f\xcf\x86\x1a\xff\xfd\x9d\xc6\x79\x1a\xa9\x65\x1d\xce\xd3\xd6\x70\xd9\xff\xdc\x95\x65\xd9\xd5\xc5\xc3\x6e\xdf\x66\xc9\xbe\xb2\xa1\x6c\x53\xcb\x25\x43\x8b\xcf\xcf\x78\xbe\x22\xeb\xf7\x51\x5f\x4a\x2f\xcd\x46\x56\xb5\x4e\xb7\xad\x60\x9d\xd6\xe7\xcc\x8e\xd6\x75\xda\xfe\x9a\x88\xcf\xff\xb6\x70\xbb\x91\x65\x8e\xa1\xf9\x69\xfa\xd1\x63\x63\x4d\xcf\xfb\xcf\x16\x6e\x64\x9d\x46\xf5\x47\xbd\xdc\x6b\xa5\x7d\x0d\xf6\xfb\xb5\x52\x94\x35\x18\xd7\xc5\x77\x1a\x0f\xfa\x89\x8e\x6b\x70\x47\x78\xfc\x8f\xee\x5c\x7e\x0d\x76\x5c\x3b\x1d\xd6\x60\x7a\xdc\x4d\x6b\x70\x7b\xaf\x35\x38\x34\x36\xdc\x38\xe6\xf4\x24\xd4\x1a\xb7\x59\x5c\x83\x7b\x5a\xb6\x1f\x6e\xec\xa9\xd6\x98\xcf\xec\xec\xbe\x06\xa7\x2e\x9d\xbd\x30\x35\xff\xb1\x8f\xdf\x33\x77\xf6\xc4\xe9\xd9\xd3\xb3\xe7\xf6\xed\xd9\x33\xbd\xef\xc0\x81\x43\x87\x0e\x4d\x9d\x9a\x3b\x33\x3b\x9d\xff\xfb\x06\xcf\x76\xf1\x6d\xca\x86\xd2\x6b\x60\x7b\x38\x77\xf1\x35\xf0\xea\xb6\x6d\x9b\x97\xea\xc2\x17\xc7\x96\xbc\xff\xde\xe8\xeb\x70\xbc\xcb\xeb\x70\x73\xdb\xb6\xfd\x7e\x1d\x8e\xb4\x3f\xb8\xda\xfa\xbc\x20\x97\xae\xe9\xfc\xb5\xf1\x9e\xfa\x49\x1f\xbf\x36\x94\x2d\xf3\x1a\x6b\x3c\x3f\xbb\xd7\xfe\x3a\x4c\x8f\xbb\xe9\x75\x38\xd2\xf4\x3a\xec\xf8\x3d\xa5\xc3\xeb\x70\x64\x05\xaf\xc3\xfa\x36\x17\x76\xaf\xec\x67\x96\x91\xa6\x7f\x3a\x1d\xc3\xf2\xdf\x0b\xd6\xb6\x06\x37\x37\xad\xc1\xf6\x9f\x47\xda\xd7\x60\xbf\x7f\x1e\x29\xca\x1a\x1c\x0f\xeb\xe2\x7b\xbb\x97\xff\x5e\xb0\x35\x1c\xef\x13\x93\xab\xfd\x79\x64\x78\xc9\x1a\x4c\x0f\x37\xbc\xf7\xd4\x2f\x49\x3f\xef\x8f\x1f\x6a\x8c\x4e\xeb\xf2\x8e\xfa\x15\x37\x8d\x65\x97\xe7\x67\x2f\xde\xfb\xc8\x89\x4b\x97\x2e\xee\xc9\xc2\x58\x17\x2f\x6b\x5a\x2b\xed\xeb\x75\x53\xd3\x63\xca\x96\xac\xd7\xa1\x55\xaf\xd7\xa3\x73\x77\x3e\x71\x47\x87\xcb\x37\x87\x73\x35\x7e\x4f\xfd\x5f\xe3\xcb\x3e\x57\xf5\x6d\xf6\xdf\xdb\xfd\xb9\x6a\x7c\x77\xeb\x7c\x3e\x5b\x2e\xdd\x9b\x85\xd1\x67\xeb\x7d\x3e\x3b\x7d\x37\xaf\x9f\xcf\xb1\x2c\xfb\xfc\xb7\x1e\x7b\xf0\x1b\x8f\x7e\xfe\x0d\xcb\x9e\xcf\x7a\xde\xfc\xc4\xd4\xda\x7f\x16\x4f\xb9\xb4\xe9\xfd\x77\x74\x99\xf7\xdf\x98\xfb\x7f\x91\xef\x2f\xdd\xd5\xe3\xc3\xa3\x23\xf9\xeb\x77\x38\x9d\x9d\xd1\x96\xf7\xe3\xd6\xa7\x6a\xa4\xf1\xde\x55\x6b\xec\xfb\xb9\xa9\x95\xbd\x1f\x8f\x86\x7f\xd6\xfb\xfd\xf8\xd6\x2e\xef\xc7\x5b\xda\xb6\xed\xf7\xfb\xf1\x68\xfb\x83\x8b\xef\xc7\xb5\x5e\x7f\xda\xb1\x36\xed\xcf\xe7\x78\x58\x27\x67\xa6\xbb\xbf\x1f\xd7\xb7\xd9\xb2\x77\xb5\x6b\x72\xa4\xeb\xfb\xf1\x5d\x61\xd6\xc2\xf9\x7f\x4d\x48\x0a\x29\x17\x35\xad\x9d\xe5\xd6\x6d\xda\xd7\xc8\xc8\x68\x78\x5c\x23\x71\x0f\xad\xeb\x74\x5f\xcb\xf6\xa3\x21\x9b\xd5\xf7\xf5\xd4\xde\x1b\x5b\xa7\xbb\xee\xca\xef\x6b\x38\x3d\xba\x45\xeb\xb5\x4e\x27\xda\xb6\xed\xf7\x3a\x4d\x7f\xf6\xb5\xdc\x3a\xad\xf5\xfa\xd3\xb7\x1b\xd3\xfe\x7c\x8e\x87\x75\x71\xeb\xbe\xee\xeb\xb4\xbe\xcd\xd3\xfb\xd7\xfe\xde\xb9\x31\xfe\x67\xd3\x7b\xe7\x58\xaf\x35\x38\x3a\x3c\x56\x3f\xe6\xd1\xb4\x08\x1b\xef\xf7\xd9\xc2\xc6\xb8\x06\xef\xcd\x4e\x66\xe7\xb3\x33\xd9\x4c\xe3\xda\xb1\xc6\x7a\xaa\x35\xf6\x35\x79\xdf\xca\xd6\xe0\x58\xf8\x67\xbd\xdf\x2b\xb7\x74\x59\x83\xbb\xda\xb6\xed\xf7\x1a\x4c\xdf\xc7\x96\x5b\x7b\xb5\x91\xa5\x0f\xbe\x0f\xda\x9f\xcf\xf1\xb0\x2e\x9e\xbc\xaf\xfb\x1a\xac\x6f\xf3\xc6\x83\xfd\xfd\xd9\x75\x57\xb8\x24\x6d\xd3\xf4\xb3\x6b\xfb\x9f\xaf\x2d\xf7\x67\x5e\x77\xb4\x9d\xa6\xe7\x6b\xad\x8c\x84\xe3\xfc\xd6\xc1\xee\x7f\x36\x5b\xdf\xe6\xcc\xa1\xd5\xe6\xcc\xee\xe7\xe9\xee\x70\xc9\x4d\x1d\xce\x53\xfb\xeb\x77\xb9\xd7\xd4\x4c\xb6\x3e\xe7\x69\x4b\x38\xce\x67\x0f\x2d\x7f\x9e\xea\xc7\x53\xdf\xe6\x73\x87\x57\xb8\x9e\x8e\x66\x59\x76\xe5\x23\xf7\x37\xfe\xbc\x37\xfc\xfd\xca\xdf\x5d\xfe\xee\x57\x5b\xfe\xde\xa5\xd3\xdf\xe9\x5c\xf9\xc8\xfd\x3f\x7e\xf1\xa9\x7f\x5c\xcd\xf1\x03\x30\xf8\x7e\x91\x8f\x4d\xf9\xf7\xba\xa6\xbf\x99\x5a\xc9\xdf\xff\x03\x00\x00\x00\x03\x21\xe6\xfe\xa1\x30\x13\xf9\x1f\x00\x00\x00\x4a\x23\xe6\xfe\xf8\x7f\x85\x27\xf2\x3f\x00\x00\x00\x94\x46\xcc\xfd\x23\x61\x26\x15\xc9\xff\x5b\xde\xf8\xec\xdc\x2f\xae\x64\xa9\x99\xbf\x10\xc4\xeb\xd3\x69\x78\x20\xdf\x2e\x76\x5c\xa7\xc3\xd7\x13\x0b\x8b\xea\x97\xdf\xff\xe5\xd9\xff\xfe\x87\x2b\x2b\xdb\xf7\x50\x96\x65\x3f\x7b\xe0\x0f\x3a\x6e\xbf\xe5\x81\x78\x5c\xb9\x89\x70\x9c\xd7\xdf\xd4\x7a\xf9\x12\x5f\xbd\x67\x45\xfb\x3e\xfe\xf0\x95\xb4\xdf\xe6\xfe\xfa\x17\xc2\xfd\xc7\xc7\xb3\xd2\x65\xd0\xa9\x82\x3b\x9d\x65\xd9\xd7\x6f\xf9\x4c\x63\x3f\x13\xef\xbf\xd6\x98\x4f\x3f\x70\xbc\x31\x1f\xbc\xfa\xc4\xe3\xf5\x6d\x9e\x3b\x9c\x7f\x1d\x6f\xff\xcc\xcb\xf2\xed\xff\x22\x94\x7f\x8f\x9e\x3a\xd1\x72\xfb\x67\xc2\x79\xf8\x61\x98\xd3\x6f\xeb\x7c\x3e\xe2\xed\xbe\x72\xed\x35\x5b\x0f\xbe\x77\x71\x7f\xf1\x76\xb5\xed\x37\x37\x1e\xf6\x93\x1f\xc8\xef\x37\xfe\x9e\x9c\xcf\x3e\x9e\x6f\x1f\xcf\xf3\x72\xc7\xff\x8d\x4f\x3f\xf5\x95\xfa\xf6\x8f\xbc\xaa\xf3\xf1\x5f\x19\xea\x7c\xfc\x4f\x85\xfb\xfd\x72\x98\xff\xfb\x8a\x7c\xfb\xe6\xe7\xa0\xfe\x75\xbc\xdd\x27\xc3\xf1\xc7\xfd\xc5\xdb\xdd\xfb\xa5\x6f\x76\x3c\xfe\xeb\x9f\xca\xb7\xbf\xf0\xe6\x7c\xbb\xe3\x61\xc6\xfd\xef\x0a\x5f\xef\x78\xf3\xb3\x73\xcd\xe7\xeb\x91\xda\x89\x96\xc7\x95\xbd\x25\xdf\x2e\xee\x7f\xfa\xbb\x7f\xdc\xb8\x3e\xde\x5f\xbc\xff\xf6\xe3\x1f\x3f\x76\xad\xe5\x7c\xb4\xaf\x8f\xa7\xff\x2d\xbf\x9f\xa9\xb6\xed\xe3\xe5\x71\x3f\xd1\xdf\xb7\xed\xbf\x7e\x3f\xcd\xeb\x33\xee\xff\xa9\x3f\x3a\xde\x72\x9e\x7b\xed\xff\xfa\x83\xcf\xbc\xa2\x7e\xbf\xed\xfb\xbf\xbb\x6d\xbb\x0b\x1f\xd9\xdd\xd8\xff\xe2\xfd\xb5\xfe\xc6\xa6\xbf\xfc\xe4\x67\x3a\xee\x2f\x1e\xcf\xd1\xbf\xbd\xd0\xf2\x78\x8e\xbe\x3b\xbc\x8e\xc3\xfe\x9f\xfc\x40\x58\x8f\xe1\xfa\xff\xbb\x9e\xdf\x5f\xfb\x6f\x57\x38\xfe\xee\xd6\xf7\x9f\xb8\xfd\x17\x36\x5f\x69\x79\x3c\xd1\x5b\x7f\x9a\xef\xff\xfa\xeb\x4e\x37\xe6\x86\xf1\x8d\x9b\x6e\x7a\xd1\x8b\x6f\xbe\xfa\xca\xfa\xb9\xcb\xb2\xef\x6c\xc8\xef\xaf\xd7\xfe\x4f\xff\xd5\xf9\x96\xe3\xff\xe2\x6d\xf9\xf9\x88\xd7\xc7\x8e\x7e\xfb\xfe\x97\x13\xf7\x7f\xf1\xa3\x93\xe7\xce\xcf\x5f\x9e\x9b\x49\x67\xf5\xd1\x5b\x1a\xbf\x3b\xe7\xed\xf9\xf1\xc4\xe3\xbd\x25\xbc\xb7\xb6\x7f\x7d\xec\xfc\xa5\x0f\xce\x5e\x9c\x98\x9e\x98\xce\xb2\x89\xf2\xfe\x0a\xbd\x1b\xf6\xa5\x30\x7f\x9c\x8f\xab\xdd\xb7\x5e\x58\xf2\x0e\xba\xfb\xe1\xf0\x7c\xde\xf1\xe7\x5f\xdf\xb4\xf3\x5f\x3f\x1d\x2f\xff\xf7\xf7\xe4\x97\x5f\x7b\x5b\xfe\x7d\xeb\xd5\x61\xbb\xcf\x86\xcb\x37\x87\xe7\x6f\x75\xfb\x5f\xea\xc9\x6d\xb7\x35\x5e\xdf\xb5\xa7\xc3\x11\x2e\x2c\xfd\x7d\xc1\x6b\xb1\x75\xc7\x7f\x1d\x5a\xd1\x86\xe1\xf1\xb7\xff\x5c\x10\xd7\xfb\x85\x97\x7f\xb0\x71\x1e\xea\xd7\x35\xbe\x6f\xc4\xd7\xf5\x1a\x8f\xff\xfb\x33\xf9\xfd\x7c\x2d\x9c\xd7\x85\xf0\x9b\x99\xb7\xdf\xb6\xb8\xbf\xe6\xed\xe3\xef\x46\xb8\xf6\x50\xfe\x7a\x5f\xf3\xf9\x0b\x6f\x73\xf1\x79\xfd\x9b\xf0\x7c\xbf\xe3\x87\xf9\xfd\xc7\xe3\x8a\x8f\xf7\xfb\xe1\xe7\x98\x6f\x6e\x69\x7d\xbf\x8b\xeb\xe3\x6b\x57\x86\xda\xef\xbf\xf1\x5b\x3c\xae\x86\xf7\x93\xec\x6a\x7e\x7d\xdc\x2a\x9e\xef\x6b\xcf\xdd\xd6\xf1\xf0\xe2\xef\x21\xc9\xae\xde\xde\xf8\xfa\x4f\xd2\xfd\xdc\xbe\xaa\x87\xb9\x9c\xf9\x8f\xcd\x4f\x9d\x99\x3b\x77\xf9\x91\xa9\x4b\xb3\xf3\x97\xa6\xe6\x3f\xf6\xf1\x63\x67\xcf\x5f\x3e\x77\xe9\x58\xe3\x77\x79\x1e\xfb\x50\xaf\xdb\x2f\xbe\x3f\x6d\x6a\xbc\x3f\xcd\xcc\x1e\xd8\x9f\x35\xde\xad\xce\xe7\xe3\x79\xf6\x42\x1f\xff\x85\x87\x4f\xce\x1c\x9c\xde\x39\x33\x7b\xea\xc4\xe5\x53\x97\x1e\xbe\x30\x7b\xf1\xf4\xc9\xf9\xf9\x93\xb3\x33\xf3\x3b\x4f\x9c\x3a\x35\xfb\xd1\x5e\xb7\x9f\x9b\x39\xb2\x67\xef\xe1\x7d\x07\xf7\x4e\x9e\x9e\x9b\x39\x72\xe8\xf0\xe1\x7d\x87\x27\xe7\xce\x9d\xaf\x1f\x46\x7e\x50\x3d\x1c\x98\xfe\xf0\xe4\xb9\x8b\xc7\x1a\x37\x99\x3f\xb2\xff\xf0\x9e\xfb\xee\xdb\x3f\x3d\x79\xf6\xfc\xcc\xec\x91\x83\xd3\xd3\x93\x97\x7b\xdd\xbe\xf1\xbd\x69\xb2\x7e\xeb\xdf\x9f\xbc\x38\x7b\xe6\xc4\xa5\xb9\xb3\xb3\x93\xf3\x73\x1f\x9f\x3d\xb2\xe7\xf0\x81\x03\x7b\x7b\xfe\x36\xc0\xb3\x17\x4e\xcd\x4f\x4c\x5d\xbc\x7c\x6e\xea\xf2\xfc\xec\xc5\xa9\xfc\xb1\x4c\x5c\x6a\x5c\x5c\xff\xde\xd7\xeb\xf6\x94\xd3\xfc\x7f\xe4\x3f\xcf\xb6\xab\xe5\xbf\x88\x2f\x7b\xd7\xdd\x07\xd2\xef\x67\xad\xfb\xf2\x63\xcb\xde\x55\xbe\x49\xdb\x2f\x10\x7d\x36\xfc\x2e\x9a\x7f\x7e\xc9\x85\x43\x2b\xf9\x3a\xe6\xfe\xd1\x30\x93\x8a\xe4\x7f\x00\x00\x00\xa8\x82\x98\xfb\xc7\xc2\x4c\xe4\x7f\x00\x00\x00\x28\x8d\x98\xfb\x37\x84\x99\xc8\xff\x00\x00\x00\x50\x1a\x31\xf7\x8f\x87\x99\x54\x24\xff\x97\xae\xff\xbf\xe5\xca\x8a\xf6\xaf\xff\xaf\xff\xdf\x7c\xbe\xf4\xff\x2b\xd6\xff\x7f\xa8\x68\xfd\xff\xfc\xfd\x42\xff\xbf\x3f\xd6\xda\xbf\xd7\xff\x0f\xf4\xff\xf5\xff\xf5\xff\xf5\xff\xf5\xff\xe9\x83\xa2\xf5\xff\x63\xee\xdf\x98\x65\x95\xcc\xff\x00\x00\x00\x50\x05\x31\xf7\x6f\x0a\x33\x91\xff\x01\x00\x00\xa0\x34\x62\xee\xbf\x29\xcc\x44\xfe\x07\x00\x00\x80\xd2\x88\xb9\xff\x45\x61\x26\x15\xc9\xff\xfa\xff\xfa\xff\xfa\xff\xfa\xff\xfa\xff\x9d\xf7\xaf\xff\x3f\x98\xf4\xff\xbb\xd3\xff\xef\x41\xff\x7f\x2a\xab\x56\xff\xff\x6a\x3f\x8f\x5f\xff\x5f\xff\x9f\xa5\x8a\xd6\xff\x8f\xb9\xff\xc5\x61\x26\x15\xc9\xff\x00\x00\x00\x50\x05\x31\xf7\xdf\x1c\x66\x22\xff\x03\x00\x00\x40\x69\xc4\xdc\x7f\x4b\x98\x89\xfc\x0f\x00\x00\x00\xa5\x11\x73\xff\xe6\x30\x93\x8a\xe4\x7f\xfd\x7f\xfd\x7f\xfd\x7f\xfd\x7f\xfd\xff\xce\xfb\xd7\xff\x1f\x4c\xfa\xff\xdd\xe9\xff\xf7\xa0\xff\xef\xf3\xff\xf5\xff\xf5\xff\xe9\xab\xa2\xf5\xff\x63\xee\x7f\x49\x98\x49\x45\xf2\x3f\x00\x00\x00\x54\x41\xcc\xfd\x2f\x0d\x33\x91\xff\x01\x00\x00\xa0\x78\x46\x6e\xec\x66\x31\xf7\xbf\x2c\xcc\x64\x49\xfe\xbf\xc1\x1d\x00\x00\x00\x00\x2f\xb8\x98\xfb\x6f\xcd\xda\x8a\xe0\x15\xf9\xfb\x7f\xfd\x7f\xfd\xff\xe2\xf7\xff\x37\xa4\xeb\xf4\xff\xf5\xff\xb3\x42\xf6\xff\x87\x33\xfd\xff\xe2\xd0\xff\xef\x4e\xff\xbf\x07\xfd\x7f\xfd\x7f\xfd\x7f\xfd\x7f\xfa\xaa\x68\xfd\xff\x46\xee\xcf\xc6\xb3\x97\x87\x99\x54\x24\xff\x03\x00\x00\x40\x15\xc4\xdc\x7f\x5b\x98\x89\xfc\x0f\x00\x00\x00\xa5\x11\x73\xff\x2f\x85\x99\xc8\xff\x00\x00\x00\x50\x1a\x31\xf7\x6f\x09\x33\xa9\x48\xfe\xd7\xff\xd7\xff\x2f\x7e\xff\xdf\xe7\xff\xeb\xff\x17\xbd\xff\xef\xf3\xff\x8b\x44\xff\xbf\x3b\xfd\xff\x1e\xf4\xff\xf5\xff\xf5\xff\xf5\xff\xe9\xab\xa2\xf5\xff\x63\xee\xbf\x3d\xcc\xa4\x22\xf9\x1f\x00\x00\x00\xaa\x20\xe6\xfe\x3b\xc2\x4c\xe4\x7f\x00\x00\x00\x28\x8d\x98\xfb\x7f\x39\xcc\x44\xfe\x07\x00\x00\x80\xd2\x88\xb9\x7f\x6b\x98\x49\x45\xf2\xbf\xfe\x7f\xc1\xfb\xff\xb1\x39\xaa\xff\xaf\xff\xaf\xff\xaf\xff\xaf\xff\xbf\x22\xfa\xff\xdd\xe9\xff\xf7\xa0\xff\xaf\xff\xaf\xff\xaf\xff\x4f\x5f\x15\xad\xff\x1f\x73\xff\x2b\xc2\x4c\x2a\x92\xff\x01\x00\x00\xa0\x0a\x62\xee\xbf\x33\xcc\x44\xfe\x07\x00\x00\x80\xd2\x88\xb9\xff\x95\x61\x26\xf2\x3f\x00\x00\x00\x94\x46\xcc\xfd\x13\x61\x26\x15\xc9\xff\xfa\xff\x05\xef\xff\xe7\x3d\xf8\x31\x9f\xff\xaf\xff\xaf\xff\xaf\xff\xaf\xff\xbf\x32\xfa\xff\xdd\xe9\xff\xf7\xa0\xff\xaf\xff\xaf\xff\xaf\xff\x4f\x5f\x15\xad\xff\x1f\x73\xff\xb6\x30\x93\x8a\xe4\x7f\x00\x00\x00\xa8\x82\x98\xfb\xb7\x87\x99\xc8\xff\x00\x00\x00\x50\x1a\x31\xf7\xdf\x15\x66\x22\xff\x03\x00\x00\x40\x69\xc4\xdc\xbf\x23\xcc\xa4\x22\xf9\x5f\xff\x7f\x20\xfa\xff\x99\xfe\xbf\xfe\xbf\xfe\xbf\xfe\xbf\xfe\xff\xca\xe8\xff\x77\xa7\xff\xdf\x83\xfe\xbf\xfe\xbf\xfe\xbf\xfe\x3f\x7d\x55\xb4\xfe\x7f\xcc\xfd\xaf\x0a\x33\xa9\x48\xfe\x07\x00\x00\x80\x2a\x88\xb9\x7f\x67\x98\x89\xfc\x0f\x00\x00\x00\xa5\x11\x73\xff\xab\xc3\x4c\xe4\x7f\x00\x00\x00\x28\x8d\x98\xfb\x77\x85\x99\x54\x24\xff\xeb\xff\xeb\xff\xeb\xff\xeb\xff\xeb\xff\x77\xde\xbf\xfe\xff\x60\xd2\xff\xef\x4e\xff\xbf\x07\xfd\x7f\xfd\x7f\xfd\x7f\xfd\x7f\xfa\xaa\x68\xfd\xff\x98\xfb\x5f\x13\x66\x52\x91\xfc\x0f\x00\x00\x00\x55\x10\x73\xff\xee\x30\x13\xf9\x1f\x00\x00\x00\x4a\x23\xe6\xfe\xbb\xc3\x4c\xe4\x7f\x00\x00\x00\x28\x8d\x98\xfb\x27\xc3\x4c\x2a\x92\xff\xf5\xff\xf5\xff\xf5\xff\xf5\xff\xf5\xff\x3b\xef\x5f\xff\x7f\x30\xe9\xff\x77\xa7\xff\xdf\x83\xfe\xbf\xfe\xbf\xfe\xbf\xfe\x3f\x7d\x55\xb4\xfe\x7f\xcc\xfd\xf7\x84\x99\x54\x24\xff\x03\x00\x00\x40\x15\xc4\xdc\x7f\x6f\x98\x89\xfc\x0f\x00\x00\x00\xa5\x11\x73\xff\x54\x98\x89\xfc\x0f\x00\x00\x00\xa5\x11\x73\xff\x74\x98\x49\x45\xf2\xbf\xfe\xbf\xfe\xbf\xfe\xbf\xfe\xff\xaa\xfa\xff\xaf\x5c\xbc\x5f\xfd\xff\x9c\xfe\x7f\xb1\xe8\xff\x77\xa7\xff\xdf\x83\xfe\xbf\xfe\xff\x0b\xde\xff\x1f\xd5\xff\xa7\x54\x8a\xd6\xff\x8f\xb9\x7f\x4f\x98\x49\x45\xf2\x3f\x00\x00\x00\x54\x41\xcc\xfd\x7b\xc3\x4c\xe4\x7f\x00\x00\x00\x28\x8d\x98\xfb\xf7\x85\x99\xc8\xff\x00\x00\x00\x50\x1a\x31\xf7\xef\x0f\x33\xa9\x48\xfe\xd7\xff\xd7\xff\xd7\xff\xd7\xff\xf7\xf9\xff\x9d\xf7\xaf\xff\x3f\x98\xf4\xff\xbb\xeb\x7f\xff\x3f\x3e\x44\xfd\x7f\xfd\x7f\xfd\x7f\x9f\xff\xaf\xff\xcf\x52\x45\xeb\xff\xc7\xdc\x7f\x5f\x98\x49\x45\xf2\x3f\x00\x00\x00\x54\x41\xcc\xfd\x07\xc2\x4c\xe4\x7f\x00\x00\x00\x28\x8d\x98\xfb\x0f\x86\x99\xc8\xff\x00\x00\x00\x50\x1a\x31\xf7\x1f\x0a\x33\xa9\x48\xfe\xd7\xff\xd7\xff\xd7\xff\xd7\xff\xd7\xff\xef\xbc\x7f\xfd\xff\xc1\xa4\xff\xdf\x9d\xcf\xff\xef\x41\xff\x5f\xff\x5f\xff\x5f\xff\x9f\x35\x7a\xe8\x0f\x9b\xbf\x2a\x5a\xff\x3f\xe6\xfe\xc3\x61\x26\x15\xc9\xff\x00\x00\x00\x50\x05\x31\xf7\xbf\x36\xcc\x44\xfe\x07\x00\x00\x80\xd2\x88\xb9\xff\x57\xc2\x4c\xe4\x7f\x00\x00\x00\x28\x8d\x98\xfb\x7f\x35\xcc\xa4\x22\xf9\x5f\xff\x5f\xff\x5f\xff\x5f\xff\x5f\xff\xbf\xf3\xfe\xf5\xff\x07\x93\xfe\x7f\x77\xfa\xff\x3d\xe8\xff\xeb\xff\xeb\xff\xeb\xff\xd3\x57\x45\xeb\xff\xc7\xdc\x7f\x24\xcc\xa4\x22\xf9\x1f\x00\x00\x00\xaa\x20\xe6\xfe\x5f\x0b\x33\x91\xff\x01\x00\x00\xa0\x34\x62\xee\x7f\x5d\x98\x89\xfc\x0f\x00\x00\x00\xa5\x11\x73\xff\xd1\x30\x93\x8a\xe4\x7f\xfd\x7f\xfd\x7f\xfd\x7f\xfd\x7f\xfd\xff\xce\xfb\x5f\xef\xfe\xff\x58\xbc\x5f\xfd\xff\x35\xd1\xff\xef\x4e\xff\xbf\x07\xfd\x7f\xfd\x7f\xfd\x7f\xfd\x7f\xfa\xaa\x68\xfd\xff\x98\xfb\x5f\x1f\x66\x52\x91\xfc\x0f\x00\x00\x00\x55\x10\x73\xff\xfd\x61\x26\xf2\x3f\x00\x00\x00\x94\x46\xcc\xfd\x6f\x08\x33\x91\xff\x01\x00\x00\xa0\x34\x62\xee\x7f\x63\x98\x49\x45\xf2\xbf\xfe\xbf\xfe\xbf\xfe\xbf\xfe\xbf\xfe\x7f\xe7\xfd\xfb\xfc\xff\xc1\xa4\xff\xdf\x9d\xfe\x7f\x0f\xfa\xff\xfa\xff\xfa\xff\xfa\xff\xf4\x55\xd1\xfa\xff\x31\xf7\xbf\x29\xcc\xa4\x22\xf9\x1f\x00\x00\x00\xaa\x20\xe6\xfe\x37\x87\x99\xc8\xff\x00\x00\x00\x50\x1a\x31\xf7\xbf\x25\xcc\x44\xfe\x07\x00\x00\x80\xd2\x88\xb9\xff\xad\x61\x26\x15\xc9\xff\xfa\xff\xfa\xff\xfa\xff\xfa\xff\xfa\xff\x9d\xf7\xaf\xff\x3f\x98\xf4\xff\xbb\xd3\xff\xef\x41\xff\x5f\xff\x5f\xff\x5f\xff\x9f\xbe\x2a\x5a\xff\x3f\xe6\xfe\x5f\x0f\x33\xa9\x48\xfe\x07\x00\x00\x80\x2a\x88\xb9\xff\x81\x30\x13\xf9\x1f\x00\x00\x00\x4a\x23\xe6\xfe\xb7\x85\x99\xc8\xff\x00\x00\x00\x50\x1a\x31\xf7\xbf\x3d\xcc\xa4\x22\xf9\x5f\xff\x5f\xff\x5f\xff\x5f\xff\x5f\xff\xbf\xf3\xfe\xf5\xff\x07\x93\xfe\x7f\x77\x03\xd6\xff\xff\xf9\xcd\xe1\x72\xfd\xff\x9c\xfe\x7f\xb1\x8f\x7f\xb5\xfd\xff\x91\xb6\xaf\x9f\x97\xfe\xff\x0f\x96\xeb\xff\x2f\x6c\x68\xbf\xbd\xfe\x3f\xcf\x87\xa2\xf5\xff\x63\xee\x7f\x47\x98\x49\x45\xf2\x3f\x00\x00\x00\x54\x41\xcc\xfd\xef\x0c\x33\x91\xff\x01\x00\x00\xa0\x34\x62\xee\x7f\x57\x98\x89\xfc\x0f\x00\x00\x00\xa5\x11\x73\xff\x6f\x84\x99\x54\x24\xff\xeb\xff\xd7\x8f\x63\xb1\xbd\xac\xff\xaf\xff\xdf\xb8\x40\xff\x5f\xff\x5f\xff\x7f\x60\xe9\xff\x77\x37\x60\xfd\x7f\x9f\xff\xdf\x46\xff\xbf\xd8\xc7\xef\xf3\xff\xf5\xff\x59\xaa\x68\xfd\xff\x98\xfb\xdf\x1d\x66\x52\x91\xfc\x0f\x00\x00\x00\x55\x10\x73\xff\x83\x61\x26\xf2\x3f\x00\x00\x00\x94\x46\xcc\xfd\x0f\x85\x99\xc8\xff\x00\x00\x00\x50\x1a\x31\xf7\xbf\x27\xcc\xa4\x22\xf9\x5f\xff\xdf\xe7\xff\xeb\xff\xeb\xff\xeb\xff\x77\xde\xbf\xfe\xff\x60\xd2\xff\xef\x4e\xff\xbf\x07\xfd\x7f\xfd\xff\xa2\xf5\xff\xff\x53\xff\x9f\xc1\x56\xb4\xfe\x7f\xcc\xfd\x0f\x87\x99\x54\x24\xff\x03\x00\x00\x40\x15\xc4\xdc\xff\xde\x30\x13\xf9\x1f\x00\x00\x00\x4a\x23\xe6\xfe\xdf\x0c\x33\x91\xff\x01\x00\x00\xa0\x34\x62\xee\x7f\x5f\x98\x49\x45\xf2\xbf\xfe\xff\xa0\xf4\xff\x27\x06\xb4\xff\xff\x98\xfe\xff\xf3\xd8\xff\xbf\xf3\xe6\x7c\x3b\xfd\x7f\xfd\x7f\x16\xe9\xff\x77\xa7\xff\xdf\x83\xfe\xbf\xfe\x7f\xd1\xfa\xff\x3e\xff\x9f\x01\x57\xb4\xfe\x7f\xcc\xfd\xef\x0f\x33\x59\x79\xfe\x1f\x5f\xf1\x96\x00\x00\x00\xc0\x0b\x22\xe6\xfe\xdf\x0a\x33\xa9\xc8\xdf\xff\x03\x00\x00\x40\x15\xc4\xdc\xff\xdb\x61\x26\xf2\x3f\x00\x00\x00\x94\x46\xcc\xfd\xbf\x13\x66\x52\x91\xfc\xaf\xff\x3f\x28\xfd\x7f\x9f\xff\x9f\xe9\xff\xfb\xfc\xff\xb6\xc7\xa3\xff\xaf\xff\xdf\xc9\xfa\xf5\xff\xe3\x3b\x8f\xfe\xbf\xfe\xbf\xfe\x7f\xa4\xff\xaf\xff\xaf\xff\x4f\xbb\xa2\xf5\xff\x63\xee\xff\xdd\x30\x93\x8a\xe4\x7f\x00\x00\x00\xa8\x82\x98\xfb\x3f\x10\x66\x22\xff\x03\x00\x00\xc0\x40\xe8\xf4\xff\x64\xb7\x8b\xb9\xff\x58\x98\x89\xfc\x0f\x00\x00\x00\xa5\x11\x73\xff\xf1\x30\x93\x8a\xe4\x7f\xfd\x7f\xfd\x7f\xfd\xff\x82\xf6\xff\xff\x6c\xfb\xbf\x7c\xef\xdb\xef\x3c\xbe\x47\xff\x5f\xff\x5f\xff\x7f\x55\xd6\xf5\xf3\xff\xeb\x2f\x7e\x9f\xff\xaf\xff\xaf\xff\x9f\xe8\xff\xeb\xff\xeb\xff\xd3\xae\x68\xfd\xff\x98\xfb\x4f\x84\x99\x54\x24\xff\x03\x00\x00\x40\x15\xc4\xdc\xff\x7b\x61\x26\xf2\x3f\x00\x00\x00\x94\x46\xcc\xfd\x27\xc3\x4c\xe4\x7f\x00\x00\x00\x28\x8d\x98\xfb\x67\xc2\x4c\x2a\x92\xff\xf5\xff\xf5\xff\xf5\xff\x0b\xda\xff\x1f\xe0\xcf\xff\x8f\xe7\x43\xff\xbf\x55\xdf\xfa\xff\xf1\x4d\x57\xff\xbf\xa3\x75\xed\xff\xbf\x77\xb1\x27\xae\xff\xbf\xda\xfe\xff\x58\xc7\x4b\xf5\xff\xf5\xff\x07\xf9\xf8\xf5\xff\xf5\xff\x59\xaa\x68\xfd\xff\x98\xfb\x67\xc3\x4c\x2a\x92\xff\x01\x00\x00\xa0\x0a\x42\xee\x1f\x3a\x95\xcf\xc5\x2b\xe4\x7f\x00\x00\x00\x28\x8d\x98\xfb\x4f\x87\x99\xc8\xff\x00\x00\x00\x50\x1a\x31\xf7\x7f\x30\xcc\xa4\x22\xf9\x5f\xff\x5f\xff\x5f\xff\x5f\xff\xdf\xe7\xff\x77\xde\x7f\xb7\xfe\x7f\x6d\xc4\xe7\xff\x17\x95\xfe\x7f\x77\xc5\xe9\xff\x77\xa6\xff\xaf\xff\x3f\xc8\xc7\xaf\xff\xaf\xff\xcf\x52\x45\xeb\xff\xc7\xdc\x3f\x17\x66\x52\x91\xfc\x0f\x00\x00\x00\x55\x10\x73\xff\x87\xc2\x4c\xe4\x7f\x00\x00\x00\x28\x8d\x98\xfb\x3f\x1c\x66\x22\xff\x03\x00\x00\x40\x69\xc4\xdc\x7f\x26\xcc\xa4\x22\xf9\x5f\xff\x5f\xff\x5f\xff\x5f\xff\x5f\xff\xbf\xf3\xfe\x0b\xfb\xf9\xff\xfa\xff\x5d\xe9\xff\x77\xa7\xff\xdf\x83\xfe\xbf\xfe\xbf\xfe\xbf\xfe\x3f\x7d\x55\xb4\xfe\x7f\xcc\xfd\x67\xc3\x4c\x2a\x92\xff\x01\x00\x00\xa0\x0a\x62\xee\x3f\x17\x66\x22\xff\x03\x00\x00\x40\x69\xc4\xdc\x7f\x3e\xcc\x44\xfe\x07\x00\xfe\x9f\xbd\x3b\x69\xb2\xac\xac\xf6\x38\x7c\xf2\xde\x22\xaa\x2a\xb8\x83\x3b\x73\xe0\xc4\x08\x87\x7e\x04\x06\x3a\xd6\x0f\xe0\xc0\x89\x03\x8d\x30\x1c\xd8\xa1\x62\x4f\x61\xdf\xa2\xa8\xd8\x2b\x8a\x7d\x83\x0d\x08\x22\x2a\xf6\x1d\xd8\xa1\xd8\x83\x8a\x7d\xdf\x60\x87\xa8\x51\x86\x59\x6b\xad\xca\x66\xe7\x3e\x99\x59\x27\x33\xf7\x7e\xdf\xe7\x19\xb0\xee\x4d\x49\xf6\x91\xa8\x00\xfe\x54\xfd\xdc\x00\x40\x33\x72\xf7\x3f\x2a\x6e\xe9\x64\xff\xeb\xff\xf5\xff\xcd\xf6\xff\xf7\xd5\xff\xef\xf4\x7c\xfd\xbf\xfe\xbf\x65\xfa\xff\x71\xfa\xff\x25\xf4\xff\xfa\x7f\xfd\xbf\xfe\x9f\x95\x9a\x5a\xff\x9f\xbb\xff\xd1\x71\x4b\x27\xfb\x1f\x00\x00\x00\x7a\x90\xbb\xff\x31\x71\x8b\xfd\x0f\x00\x00\x00\xcd\xc8\xdd\x7f\x61\xdc\x62\xff\x03\x00\x00\x40\x33\x72\xf7\x3f\x36\x6e\xe9\x64\xff\x6f\xe9\xff\xd7\x16\x7d\xf6\xff\x99\xf1\xea\xff\x5b\xea\xff\xbd\xff\x7f\xc7\xe7\xeb\xff\xf5\xff\x2d\x3b\xdc\xfe\xff\x92\xff\xfe\x95\x4f\xff\xaf\xff\xd7\xff\x07\xfd\xff\xae\xfa\xff\xe3\x3b\x7d\xbf\xfe\x9f\x16\x4d\xad\xff\xcf\xdd\xff\xb8\xb8\xa5\x93\xfd\x0f\x00\x00\x00\x3d\xc8\xdd\xff\xf8\xb8\xc5\xfe\x07\x00\x00\x80\x66\xe4\xee\xbf\x28\x6e\xb1\xff\x01\x00\x00\xa0\x19\xb9\xfb\x9f\x10\xb7\x74\xb2\xff\x57\xf7\xfe\xff\x93\xeb\x5f\x9f\x69\xff\x5f\xf4\xff\xfa\xff\xf5\x2f\xe8\xff\xf5\xff\xfa\xff\xd9\xf2\xfe\xff\x71\x3d\xf5\xff\x17\xde\x7a\xfe\x23\xee\xbc\xee\x9e\xd7\xef\xe5\xf9\xfa\x7f\xfd\xbf\xf7\xff\xeb\xff\x59\xad\xa9\xf5\xff\xb9\xfb\x9f\x18\xb7\x74\xb2\xff\x01\x00\x00\xa0\x07\xb9\xfb\x9f\x14\xb7\xd8\xff\x00\x00\x00\xd0\x8c\xdc\xfd\x4f\x8e\x5b\xec\x7f\x00\x00\x00\x68\x46\xee\xfe\xa7\xc4\x2d\x9d\xec\xff\xd5\xf5\xff\xb3\x7e\xff\x7f\xd1\xff\xeb\xff\xd7\xbf\xa0\xff\xd7\xff\xeb\xff\x67\x4b\xff\x3f\xae\xa7\xfe\x7f\x3f\xcf\xd7\xff\xeb\xff\xf5\xff\xfa\x7f\x56\x6b\x6a\xfd\x7f\xee\xfe\xa7\xc6\x2d\x9d\xec\x7f\x00\x00\x00\xe8\x41\xee\xfe\xa7\xc5\x2d\xf6\x3f\x00\x00\x00\x34\x23\x77\xff\xc5\x71\x8b\xfd\x0f\x00\x00\x00\xcd\xc8\xdd\x7f\x2a\x6e\xe9\x64\xff\xeb\xff\x0f\xbe\xff\xff\xb7\xfe\x5f\xff\x1f\x57\xff\xaf\xff\xd7\xff\x1f\x3c\xfd\xff\x38\xfd\xff\x12\xfa\x7f\xfd\xbf\xfe\x5f\xff\xcf\x4a\x4d\xad\xff\xcf\xdd\x7f\x49\xdc\xd2\xc9\xfe\x07\x00\x00\x80\x1e\xe4\xee\x7f\x7a\xdc\x62\xff\x03\x00\x00\x40\x33\x72\xf7\x3f\x23\x6e\xb1\xff\x01\x00\x00\xa0\x19\xb9\xfb\x9f\x19\xb7\x74\xb2\xff\xf5\xff\xde\xff\xaf\xff\xd7\xff\xeb\xff\x87\x9f\xaf\xff\x9f\x27\xfd\xff\x38\xfd\xff\x12\xfa\xff\x73\xed\xe7\xcf\xd3\xff\xeb\xff\xf5\xff\x6c\xb4\xc7\xfe\xff\xee\x91\xbf\x6c\xaf\xa4\xff\xcf\xdd\xff\xac\xb8\xa5\x93\xfd\x0f\x00\x00\x00\x3d\xc8\xdd\xff\xec\xb8\xc5\xfe\x07\x00\x00\x80\x66\xe4\xee\x7f\x4e\xdc\x62\xff\x03\x00\x00\x40\x33\x72\xf7\x3f\x37\x6e\xe9\x64\xff\xeb\xff\xf5\xff\xfa\x7f\xfd\xff\xbe\xfb\xff\xed\x3f\xf4\xd6\xe9\xff\x87\xe9\xff\x0f\x87\xfe\x7f\xdc\x64\xfa\xff\xb5\x63\x83\x5f\xd6\xff\xcf\xbe\xff\xf7\xfe\x7f\xfd\xbf\xfe\x9f\x4d\xa6\xf6\xfe\xff\xdc\xfd\xcf\x8b\x5b\x3a\xd9\xff\x00\x00\x00\xd0\x83\xdc\xfd\xcf\x8f\x5b\x46\xf6\xff\x9e\xff\x65\x3e\x00\x00\x00\x70\xa4\x72\xf7\xbf\x20\x6e\xf1\xf3\xff\x00\x00\x00\x30\x7b\x59\x9d\xe5\xee\x7f\x61\xdc\xd2\xc9\xfe\xd7\xff\xeb\xff\xf5\xff\xfa\x7f\xef\xff\x1f\x7e\xfe\x58\xff\x7f\xfd\x86\xcf\xa7\xff\x9f\x16\xfd\xff\xb8\xc9\xf4\xff\x3b\xd0\xff\xeb\xff\xe7\xfc\xf9\xf5\xff\xfa\x7f\xb6\x9b\x5a\xff\x9f\xbb\xff\x45\x71\x4b\x27\xfb\x1f\x00\x00\x00\x7a\x90\xbb\xff\xd2\xb8\xc5\xfe\x07\x00\x00\x80\x66\xe4\xee\x7f\x71\xdc\x62\xff\x03\x00\x00\x40\x33\x72\xf7\xbf\x24\x6e\xe9\x64\xff\x0f\xf7\xff\x67\xff\x73\xfd\xff\xee\xe8\xff\x37\x7f\x7e\xfd\xff\xf0\x8f\x8f\x55\xf5\xff\xf9\x47\xd4\xff\x8f\xf6\xff\xf7\xf3\xfe\xff\x3e\xe9\xff\xc7\x1d\x7e\xff\x7f\x5c\xff\xbf\xf9\x8f\xaf\xff\x3f\x40\x47\xfd\xf9\x1b\xef\xff\x4f\x2e\xfb\x7e\xfd\x3f\x43\xa6\xd6\xff\xe7\xee\xbf\x2c\x6e\xe9\x64\xff\x03\x00\x00\x40\x0f\x72\xf7\xbf\x34\x6e\xb1\xff\x01\x00\x00\xa0\x19\xb9\xfb\x5f\x16\xb7\xd8\xff\x00\x00\x00\xd0\x8c\xdc\xfd\x2f\x8f\x5b\x3a\xd9\xff\xde\xff\xaf\xff\xd7\xff\xcf\xaf\xff\xf7\xfe\xff\x33\x8e\xf2\xfd\xff\x8b\x43\xef\xff\x8f\xe9\xff\x77\x49\xff\x3f\xce\xfb\xff\x97\xd0\xff\xeb\xff\xf5\xff\xde\xff\xcf\x4a\x4d\xad\xff\xcf\xdd\x7f\x79\xdc\xd2\xc9\xfe\x07\x00\x00\x80\x1e\x5c\x7e\xd7\x62\x7d\xf7\xbf\x62\xb1\xb0\xff\x01\x00\x00\x60\x8e\x36\xfe\xda\x81\xad\xbf\xa0\x34\xe4\xee\x7f\x65\xdc\x62\xff\x03\x00\x00\x40\x33\x72\xf7\xbf\x2a\x6e\xe9\x64\xff\xeb\xff\xf5\xff\xfa\x7f\xfd\xbf\xfe\x7f\xf8\xf9\xd3\xea\xff\xbd\xff\x7f\xb7\xf4\xff\xe3\xf4\xff\x4b\xe8\xff\x0f\xa2\x9f\x3f\xd6\x58\xff\x7f\xc5\x4e\xdf\x3f\x85\xfe\xff\x62\xfd\x3f\x13\xb3\xa9\xff\xbf\xf1\xec\xd7\x8f\xaa\xff\xcf\xdd\xff\xea\xb8\xa5\x93\xfd\x0f\x00\x00\x00\x3d\xc8\xdd\xff\x9a\xb8\xc5\xfe\x07\x00\x00\x80\x66\xe4\xee\x7f\x6d\xdc\x62\xff\x03\x00\x00\x40\x33\x72\xf7\xbf\x2e\x6e\xe9\x64\xff\x1f\x78\xff\x7f\x72\xe7\x67\xeb\xff\xf5\xff\xfa\x7f\xfd\xbf\xfe\x5f\xff\xbf\x6a\xfa\xff\x71\xfa\xff\x25\xf4\xff\xde\xff\xef\xfd\xff\xfa\x7f\x56\x6a\x53\xff\xbf\xc1\x51\xf5\xff\xb9\xfb\x5f\x1f\xb7\x74\xb2\xff\x01\x00\x00\xa0\x07\xb9\xfb\xdf\x10\xb7\xd8\xff\x00\x00\x00\xd0\x8c\xdc\xfd\x57\xc4\x2d\xf6\x3f\x00\x00\x00\x34\x23\x77\xff\x1b\xe3\x96\x4e\xf6\xbf\xf7\xff\xeb\xff\xf5\xff\xfa\x7f\xfd\xff\xf0\xf3\xf5\xff\xf3\xa4\xff\x1f\xa7\xff\x5f\x42\xff\xaf\xff\xd7\xff\xeb\xff\x59\xa9\xa9\xf5\xff\xb9\xfb\xdf\x14\xb7\x74\xb2\xff\x01\x00\x00\xa0\x07\xb9\xfb\xaf\x8c\x5b\xec\x7f\x00\x00\x00\x68\x46\xee\xfe\x37\xc7\x2d\xf6\x3f\x00\x00\x00\x34\x23\x77\xff\x5b\xe2\x96\x4e\xf6\xbf\xfe\xff\x60\xfb\xff\xfc\xba\xfe\x5f\xff\xbf\xd0\xff\xeb\xff\xf5\xff\x87\xa2\xdb\xfe\x7f\x6d\xe8\xef\x44\xdb\xed\xd0\xff\xdf\xfc\xb0\x53\x0f\xd8\xfc\x15\xfd\xbf\xfe\x5f\xff\xaf\xff\xd7\xff\xb3\x02\x93\xe8\xff\x4f\x9f\xfd\xa7\xcb\xdc\xfd\x6f\x8d\x5b\x3a\xd9\xff\x00\x00\x00\xd0\x83\xdc\xfd\x6f\x8b\x5b\xec\x7f\x00\x00\x00\x68\x46\xee\xfe\xb7\xc7\x2d\xf6\x3f\x00\x00\x00\x34\x23\x77\xff\x3b\xe2\x96\x3d\xee\xff\xff\x5f\xe9\xa7\x3a\x3c\xfa\x7f\xef\xff\xd7\xff\xeb\xff\xf5\xff\xc3\xcf\xd7\xff\xcf\x53\xb7\xfd\xff\x2e\x79\xff\xff\x12\xfa\x7f\xfd\xbf\xfe\x5f\xff\xcf\x4a\x4d\xa2\xff\xdf\xf0\xff\xe7\xee\x7f\x67\xdc\xe2\xe7\xff\x01\x00\x00\xa0\x19\xb9\xfb\xdf\x15\xb7\xd8\xff\x00\x00\x00\xd0\x8c\xdc\xfd\xef\x8e\x5b\xec\x7f\x00\x00\x00\x68\x46\xee\xfe\xf7\xc4\x2d\x9d\xec\x7f\xfd\xbf\xfe\x5f\xff\xaf\xff\xd7\xff\x0f\x3f\x7f\xbf\xfd\xff\x89\xc5\x30\xfd\xff\xe1\xd0\xff\x8f\xd3\xff\x2f\xa1\xff\xd7\xff\xeb\xff\xf5\xff\xac\xd4\xd4\xfa\xff\xdc\xfd\x57\xc5\x2d\x9d\xec\x7f\x00\x00\x00\xe8\x41\xee\xfe\xf7\xc6\x2d\xf6\x3f\x00\x00\x00\x34\x23\x77\xff\xfb\xe2\x16\xfb\x1f\x00\x00\x00\x9a\x91\xbb\xff\xfd\x71\x4b\x27\xfb\x5f\xff\xaf\xff\xd7\xff\xeb\xff\xf5\xff\xc3\xcf\xf7\xfe\xff\x79\xd2\xff\x8f\xd3\xff\x2f\x16\x8b\xab\x47\x3e\xc0\x50\xff\x7f\xfa\xb8\xfe\x5f\xff\xaf\xff\xd7\xff\xb3\x4f\x53\xeb\xff\x73\xf7\x7f\x20\x6e\xe9\x64\xff\x03\x00\x00\x40\x0f\x72\xf7\x5f\x1d\xb7\xd8\xff\x00\x00\x00\xd0\x8c\xdc\xfd\xd7\xc4\x2d\xf6\x3f\x00\x00\x00\x34\x23\x77\xff\x07\xe3\x96\x4e\xf6\xbf\xfe\x5f\xff\xaf\xff\xd7\xff\xeb\xff\x87\x9f\xaf\xff\x9f\x27\xfd\xff\x38\xfd\xff\x12\xde\xff\xaf\xff\xd7\xff\xeb\xff\x59\xa9\xa9\xf5\xff\xb9\xfb\xaf\x8d\x5b\x3a\xd9\xff\x00\x00\x00\xd0\x83\xdc\xfd\xd7\xc5\x2d\xf6\x3f\x00\x00\x00\x34\x23\x77\xff\x87\xe2\x16\xfb\x1f\x00\x00\x00\x9a\x91\xbb\xff\xfa\xb8\xa5\x93\xfd\xaf\xff\xd7\xff\xeb\xff\xf5\xff\xfa\xff\xe1\xe7\xeb\xff\xe7\xe9\xe0\xfa\xff\x85\xfe\x5f\xff\xaf\xff\x5f\x42\xff\xaf\xff\xd7\xff\xb3\xd5\xd4\xfa\xff\xdc\xfd\x1f\x8e\x5b\x3a\xd9\xff\x00\x00\x00\xd0\x83\xdc\xfd\x37\xc4\x2d\xf6\x3f\x00\x00\x00\x34\x23\x77\xff\x47\xe2\x16\xfb\x1f\x00\x00\x00\x9a\x91\xbb\xff\xa3\x71\x4b\x27\xfb\x5f\xff\xaf\xff\xd7\xff\xeb\xff\xf5\xff\xc3\xcf\xd7\xff\xcf\x93\xf7\xff\x8f\xd3\xff\x2f\xa1\xff\xd7\xff\xeb\xff\xf5\xff\xac\xd4\xd4\xfa\xff\xdc\xfd\x1f\x8b\x5b\x3a\xd9\xff\x00\x00\x00\xd0\x83\xdc\xfd\x37\xc6\x2d\xf6\x3f\x00\x00\x00\x34\x23\x77\xff\xc7\xe3\x16\xfb\x1f\x00\x00\x00\x9a\x91\xbb\xff\x13\x71\x4b\x27\xfb\x5f\xff\xaf\xff\xdf\xdc\xff\x2f\x16\xfa\x7f\xfd\xbf\xfe\xff\x8c\x43\xe8\xff\x4f\x2c\xf4\xff\x2b\xa7\xff\x1f\xa7\xff\x5f\x42\xff\xdf\x66\xff\xff\x3f\x8b\x86\xfa\xff\x93\x3b\x7e\xbf\xfe\x9f\x29\x9a\x5a\xff\x9f\xbb\xff\x93\x71\x4b\x27\xfb\x1f\x00\x00\x00\x7a\x90\xbb\xff\x53\x71\x8b\xfd\x0f\x00\x00\x00\xcd\xc8\xdd\xff\xe9\xb8\xc5\xfe\x07\x00\x00\x80\x66\xe4\xee\xff\x4c\xdc\xd2\xc9\xfe\x9f\x7f\xff\x7f\x7c\xcb\x37\xea\xff\x17\x8b\xc5\x6d\x17\x79\xff\xbf\xfe\x7f\xe4\xf9\xfa\xff\xc9\xf4\xff\xf5\x67\x55\xff\xbf\x3a\xfa\xff\x71\xfa\xff\x25\xf4\xff\x6d\xf6\xff\xde\xff\xaf\xff\xe7\xc8\x4c\xad\xff\xcf\xdd\xff\xd9\xb8\xa5\x93\xfd\x0f\x00\x00\x00\x3d\xc8\xdd\xff\xb9\xb8\xc5\xfe\x07\x00\x00\x80\x66\xe4\xee\xff\x7c\xdc\x62\xff\x03\x00\x00\x40\x33\x72\xf7\x7f\x21\x6e\xe9\x64\xff\xcf\xbf\xff\xdf\xfa\x8d\xfa\xff\xc5\x39\xbd\xff\x5f\xff\xbf\xfe\x05\xfd\xbf\xfe\x5f\xff\x3f\x5b\xfa\xff\x71\xfa\xff\x25\xf4\xff\x4b\xfb\xf9\xb5\x1d\xfe\xb9\x67\xa1\xff\xd7\xff\xeb\xff\x19\x30\xb5\xfe\x3f\x77\xff\x17\xe3\x96\x4e\xf6\x3f\x00\x00\x00\xf4\x20\x77\xff\x4d\x71\x8b\xfd\x0f\x00\x00\x00\xcd\xc8\xdd\x7f\x73\xdc\x62\xff\x03\x00\x00\x40\x33\x72\xf7\x7f\x29\x6e\xe9\x64\xff\xeb\xff\xf5\xff\xfa\xff\x79\xf6\xff\x27\xf4\xff\xfa\x7f\xfd\xff\xa0\xa9\xf4\xff\x17\x5c\x70\xff\x5b\xf4\xff\xfa\xff\x16\xfb\xff\x31\xfa\x7f\xfd\xbf\xfe\x9f\xad\xa6\xd6\xff\xe7\xee\xff\x72\xdc\xd2\xc9\xfe\x07\x00\x00\x80\x1e\xe4\xee\xff\x4a\xdc\x62\xff\x03\x00\x00\x40\x33\x72\xf7\x7f\x35\x6e\xb1\xff\x01\x00\x00\xa0\x19\xb9\xfb\xbf\x16\xb7\x74\xb2\xff\xb7\xf7\xff\xe7\x2d\xce\x14\xaa\x67\x0c\xf5\xff\xd1\xa8\xe9\xff\x37\xd0\xff\x6f\xfe\xfc\xfa\xff\xe1\x1f\x1f\xde\xff\xaf\xff\xd7\xff\x1f\xbc\xa9\xf4\xff\xde\xff\xbf\xbf\xcf\xaf\xff\xd7\xff\xcf\xf9\xf3\xef\xa9\xff\xbf\xd7\xf6\xef\xd7\xff\xd3\xa2\xa9\xf5\xff\xb9\xfb\x6f\x89\x5b\x3a\xd9\xff\x00\x00\x00\xd0\x83\xdc\xfd\x5f\x8f\x5b\xec\x7f\x00\x00\x00\x68\x46\xee\xfe\x6f\xc4\x2d\xf6\x3f\x00\x00\x00\x34\x23\x77\xff\xad\x71\x4b\x27\xfb\xdf\xfb\xff\xf5\xff\xfa\x7f\xfd\xbf\xfe\x7f\xf8\xf9\xfa\xff\x79\xd2\xff\x8f\xd3\xff\x2f\xa1\xff\xd7\xff\x7b\xff\xff\x23\x1f\xf2\xbf\xfa\x7f\x56\x67\x6a\xfd\x7f\xee\xfe\x6f\xc6\x2d\xeb\xc3\xef\xde\xff\xb7\xcf\xff\x9a\x00\x00\x00\xc0\x84\xe4\xee\xff\x56\xdc\xd2\xc9\xcf\xff\x03\x00\x00\x40\x0f\x72\xf7\x7f\x3b\x6e\xb1\xff\x01\x00\x00\xa0\x19\xb9\xfb\xbf\x13\xb7\x74\xb2\xff\xf5\xff\xfa\x7f\xfd\xbf\xfe\x5f\xff\x3f\xfc\x7c\xfd\xff\x3c\xe9\xff\xc7\xe9\xff\x97\xe8\xa7\xff\x3f\x31\xf4\xc5\xa3\xee\xe7\xcf\xd5\x51\x7f\xfe\x66\xfa\x7f\xef\xff\x67\x85\xa6\xd6\xff\xe7\xee\xff\x6e\xdc\xd2\xc9\xfe\x07\x00\x00\x80\x1e\xe4\xee\xff\x5e\xdc\x62\xff\x03\x00\x00\x40\x33\x72\xf7\x7f\x3f\x6e\xb1\xff\x01\x00\x00\xa0\x19\xb9\xfb\x6f\x8b\x5b\x3a\xd9\xff\xfa\x7f\xfd\x7f\xfb\xfd\xff\x83\xf5\xff\x5b\x9e\xaf\xff\xd7\xff\xb7\x4c\xff\x9f\x7f\x47\x1f\xa6\xff\x5f\xa2\x9f\xfe\x7f\xd0\x51\xf7\xf3\x73\xff\xfc\xfa\x7f\xfd\x3f\xdb\x4d\xad\xff\xcf\xdd\x7f\x7b\xdc\xd2\xc9\xfe\x07\x00\x00\x80\x1e\xe4\xee\xff\x41\xdc\x62\xff\x03\x00\x00\x40\x33\x72\xf7\xff\x30\x6e\xb1\xff\x01\x00\x00\xa0\x19\xb9\xfb\x7f\x14\xb7\x74\xb2\xff\xf5\xff\x7d\xf5\xff\x6b\x8b\x1e\xfb\x7f\xef\xff\xd7\xff\xeb\xff\x7b\x32\x9f\xfe\xff\xca\x63\x43\x5f\xf5\xfe\x7f\xfd\xbf\xfe\x7f\xbe\x9f\x5f\xff\xaf\xff\x67\xbb\xa9\xf5\xff\xb9\xfb\xef\x58\x3b\xd6\xe5\xfe\x07\x00\x00\x80\xb9\x7a\xe0\x7d\x1e\x7e\xfb\x6e\x7f\xdf\x3b\xd6\x7f\x7b\x62\xf1\xe3\xb8\xc5\xfe\x07\x00\x00\x80\x66\xe4\xee\xff\x49\xdc\x62\xff\x03\x00\x00\x40\x33\x72\xf7\xff\x34\x6e\xe9\x64\xff\xeb\xff\xfb\xea\xff\xfb\x7c\xff\xbf\xfe\x5f\xff\xaf\xff\xef\xc9\x7c\xfa\xff\x61\xfa\x7f\xfd\xbf\xfe\x7f\xbe\x9f\x5f\xff\xaf\xff\x67\xbb\xa9\xf5\xff\xb9\xfb\x7f\x16\xb7\x6c\x18\x7e\x83\xff\x03\x3d\x00\x00\x00\xc0\x6c\xe4\xee\xff\x79\xdc\xd2\xc9\xcf\xff\x03\x00\x00\x40\x0f\x72\xf7\xff\x22\x6e\xd9\xb6\xff\x4f\xef\xf2\x57\xb5\x03\x00\x00\x00\x53\x93\xbb\xff\x97\x71\x4b\x27\x3f\xff\xaf\xff\x9f\x78\xff\xbf\x38\xa0\xfe\x3f\x7e\x3f\xfd\xff\x19\xfa\x7f\xfd\xff\xd0\xf3\xf5\xff\xf3\xa4\xff\x1f\x77\x8e\xfd\xff\xe9\x35\xfd\xbf\xfe\x7f\x84\xfe\x5f\xff\xaf\xff\x67\xab\xa9\xf5\xff\xb9\xfb\x6f\xb8\x76\xd1\xe5\xfe\x07\x00\x00\x80\x46\x6d\xfa\x37\x0a\xbf\x5a\xff\xed\x89\xc5\xaf\xe3\x16\xfb\x1f\x00\x00\x00\x9a\x91\xbb\xff\x37\x71\x8b\xfd\x0f\x00\x00\x00\xcd\xc8\xdd\xff\xdb\xb8\xa5\x93\xfd\xaf\xff\x9f\x78\xff\xbf\xaf\xf7\xff\x9f\xac\xff\xcb\xfb\xff\x3b\xef\xff\x2f\x3d\x31\xf8\x7c\xfd\xbf\xfe\xbf\x65\xfa\xff\x71\xde\xff\xbf\x84\xfe\x5f\xff\xaf\xff\xd7\xff\xb3\x52\x7b\xe8\xff\xd7\x07\xe9\x41\xf7\xff\xb9\xfb\x7f\x17\xb7\x74\xb2\xff\x01\x00\x00\xa0\x07\xb9\xfb\x7f\x1f\xb7\xd8\xff\x00\x00\x00\xd0\x8c\xdc\xfd\x7f\x88\x5b\xec\x7f\x00\x00\x00\x68\x46\xee\xfe\x3f\xc6\x2d\x9d\xec\x7f\xfd\xff\x11\xf4\xff\x97\x1d\x5f\x2c\x0e\xb4\xff\xdf\xc5\xfb\xff\xf5\xff\x7d\xf4\xff\x3b\x3c\xbf\x9d\xfe\xff\x1e\xe7\x9f\xba\xe9\x41\x0f\xbd\xe6\x2a\xfd\x3f\x67\x1d\x66\xff\x9f\x3f\x16\xf4\xff\xfa\x7f\xfd\xff\x19\xfa\x7f\xfd\xbf\xfe\x9f\xad\xa6\xf6\xfe\xff\xdc\xfd\x7f\x8a\x5b\x3a\xd9\xff\x00\x00\x00\xd0\x83\xdc\xfd\x77\xc6\x2d\xf6\x3f\x00\x00\x00\x34\x23\x77\xff\x9f\xe3\x16\xfb\x1f\x00\x00\x00\x9a\x91\xbb\xff\x2f\x71\x4b\x27\xfb\x5f\xff\xdf\xe2\xfb\xff\xe7\xd9\xff\xe7\x9f\xeb\x23\xe8\xff\x4f\xcd\xaf\xff\xcf\xa6\xb8\xf7\xfe\xdf\xfb\xff\xf5\xff\xdb\x79\xff\xff\x38\xfd\xff\x12\xfa\x7f\xfd\xbf\xfe\x5f\xff\xcf\x4a\x4d\xad\xff\xcf\xdd\xff\xd7\xb8\xa5\x93\xfd\x0f\x00\x00\x00\x3d\xc8\xdd\xff\xb7\xb8\x25\xf7\xff\xda\x9e\xff\xd5\x3d\x00\x00\x00\x30\x31\xb9\xfb\xff\x1e\xb7\xf8\xf9\x7f\x00\x00\x00\x68\x46\xee\xfe\xbb\xe2\x96\x4e\xf6\xbf\xfe\x5f\xff\x3f\x95\xfe\x3f\x79\xff\xff\xd9\xef\xf3\xfe\xff\x33\xf4\xff\xfa\xff\xbd\xd0\xff\x8f\xd3\xff\x2f\xa1\xff\xd7\xff\xeb\xff\xf5\xff\xac\xd4\xd4\xfa\xff\xdc\xfd\xff\x88\x5b\x3a\xd9\xff\x00\x00\x00\xd0\x83\xdc\xfd\x77\xc7\x2d\xf6\x3f\x00\x00\x00\x34\x23\x77\xff\x3f\xe3\x16\xfb\x1f\x00\x00\x00\x9a\x91\xbb\xff\x5f\x71\x4b\x27\xfb\x5f\xff\xaf\xff\xd7\xff\xeb\xff\xf5\xff\xc3\xcf\xd7\xff\xcf\x93\xfe\x7f\x9c\xfe\x7f\x09\xfd\xbf\xfe\x5f\xff\xaf\xff\x67\xa5\xa6\xd6\xff\xe7\xee\xff\x4f\x00\x00\x00\xff\xff\x0b\x4f\x6c\x1c", 24928);
syz_mount_image(/*fs=*/0x200000000000, /*dir=*/0x200000000180, /*flags=MS_STRICTATIME|MS_NOSUID*/0x1000002, /*opts=*/0x2000000002c0, /*chdir=*/1, /*size=*/0x6161, /*img=*/0x20000000d680);
// openat arguments: [
// fd: fd_dir (resource)
// file: ptr[in, buffer] {
// buffer: {2e 2f 66 69 6c 65 31 00} (length 0x8)
// }
// flags: open_flags = 0x0 (4 bytes)
// mode: open_mode = 0x0 (2 bytes)
// ]
// returns fd
memcpy((void*)0x200000000100, "./file1\000", 8);
syscall(__NR_openat, /*fd=*/0xffffff9c, /*file=*/0x200000000100ul, /*flags=*/0, /*mode=*/0);
return 0;
}
Reply: An analysis of the crash reveals a race condition during the unmounting of a JFS filesystem, leading to a use-after-free in the `jfs_lazycommit` background thread.
### Root Cause
When a JFS filesystem is unmounted, `jfs_umount()` (and `jfs_umount_rw()`) calls `jfs_flush_journal(log, 2)` to flush all outstanding transactions to the disk.
`jfs_flush_journal()` waits until the commit queue (`log->cqueue`) and the sync list (`log->synclist`) are empty. However, it **does not wait** for the unlock queue (`TxAnchor.unlock_queue`) to be processed by the `jfs_lazycommit` thread.
The lifecycle of a lazy transaction is as follows:
1. Added to `log->cqueue` during `txCommit()`.
2. Moved from `log->cqueue` to `TxAnchor.unlock_queue` by `lmPostGC()` once the commit record hits the disk.
3. Removed from `TxAnchor.unlock_queue` and processed by the `jfs_lazycommit` thread via `txLazyCommit()`.
Because `jfs_flush_journal()` only waits for `log->cqueue` to drain, it can return while transactions are still sitting in `TxAnchor.unlock_queue` or are actively being processed by `jfs_lazycommit`.
After `jfs_flush_journal()` returns, `jfs_umount()` proceeds to tear down the filesystem: it frees the allocation maps (`sbi->ipimap`, `sbi->ipbmap`) and eventually calls `lmLogClose()`, which frees the `jfs_log` structure.
Meanwhile, the `jfs_lazycommit` thread wakes up, pops the transaction from `TxAnchor.unlock_queue`, and calls `txLazyCommit()`. This function accesses the now-freed allocation maps and the freed `log` structure (`log = JFS_SBI(tblk->sb)->log`), eventually calling `txEnd()` -> `jfs_syncpt()` -> `lmLogSync()`, which writes to `log->syncpt`, resulting in the KASAN slab-use-after-free crash.
### How to Fix
To fix this, we need to ensure that `jfs_lazycommit` has completely finished processing all transactions for the unmounting superblock before `jfs_umount()` proceeds to free the filesystem structures.
1. **Introduce a wait function in `fs/jfs/jfs_txnmgr.c`:**
Create a function `txLazyCommitWait(sb)` that waits until `TxAnchor.unlock_queue` contains no transactions for the given `sb`, and the `jfs_lazycommit` thread is not actively processing one (`sbi->commit_state & IN_LAZYCOMMIT` is cleared).
```c
/*
* Wait for lazycommit thread to finish processing all transactions
* for the given superblock.
*/
void txLazyCommitWait(struct super_block *sb)
{
struct jfs_sb_info *sbi = JFS_SBI(sb);
struct jfs_log *log = sbi->log;
unsigned long flags;
struct tblock *tblk;
int found;
if (!log)
return;
/*
* Synchronize with lmPostGC to ensure that all transactions
* removed from cqueue have been added to unlock_queue.
*/
spin_lock_irqsave(&log->gclock, flags);
spin_unlock_irqrestore(&log->gclock, flags);
do {
found = 0;
LAZY_LOCK(flags);
if (sbi->commit_state & IN_LAZYCOMMIT)
found = 1;
else {
list_for_each_entry(tblk, &TxAnchor.unlock_queue, cqueue) {
if (tblk->sb == sb) {
found = 1;
break;
}
}
}
LAZY_UNLOCK(flags);
if (found)
msleep(10);
} while (found);
}
```
*(Note: Briefly taking `log->gclock` is crucial here to close a tiny race window where `jfs_flush_journal` sees an empty `cqueue`, but `lmPostGC` is still holding `log->gclock` and hasn't yet added the transaction to `unlock_queue`)*.
2. **Export the function in `fs/jfs/jfs_txnmgr.h`:**
```c
extern void txLazyCommitWait(struct super_block *sb);
```
3. **Call the wait function during unmount in `fs/jfs/jfs_umount.c`:**
Invoke `txLazyCommitWait(sb)` immediately after `jfs_flush_journal(log, 2)` in both `jfs_umount()` and `jfs_umount_rw()`.
In `jfs_umount()`:
```c
- if ((log = sbi->log))
+ if ((log = sbi->log)) {
/*
* Wait for outstanding transactions to be written to log:
*/
jfs_flush_journal(log, 2);
+ txLazyCommitWait(sb);
+ }
```
In `jfs_umount_rw()`:
```c
/*
* Note that we have to do this even if dummy_log is used.
* This is because dummy_log is shared among all mounts.
*/
jfs_flush_journal(log, 2);
+ txLazyCommitWait(sb);
/*
* close log:
```
|
| 8/2 |
2026/05/11 23:30 |
llm |
debugger |
0m
Model:
Tokens:
input: 103665
output: 46
thoughts: 590
Thoughts: **Analyzing a KASAN Slab-Use-After-Free in JFS Logging**
Okay, so I'm looking at a KASAN use-after-free in the `lmLogSync` function within the JFS filesystem code. The crash is happening at `fs/jfs/jfs_logmgr.c:1003`, right in the middle of `lmLogSync`. The task that triggered this is `jfsCommit/122`. Let's get right into the stack trace to understand the context.
The stack shows `lmLogSync` being called, which then triggers `jfs_syncpt`, followed by calls within the transaction management - `txEnd`, `txLazyCommit`, and finally `jfs_lazycommit`. Now, I'm thinking, where was the problematic memory allocated and freed?
Tracing back, it looks like the log itself was opened and allocated during the filesystem mount process, specifically through a chain of calls: `jfs_fill_super`, eventually leading to `lmLogOpen` which involves `open_inline_log`. This is expected for JFS. However, the critical part is understanding when the memory is being deallocated.
The log memory is freed by `lmLogClose`, which is called during the unmount process, through `jfs_umount` and then `jfs_put_super` and down the line. It's clear that the umount triggers the closure of the log. This is the crux of the issue; it seems the `jfsCommit` thread, a kernel thread, is still running and trying to access the memory after it's been freed. This `jfsCommit` thread is responsible for committing transactions. I need to figure out the synchronization here.
The obvious question: Does `jfs_umount` properly synchronize with the `jfsCommit` thread? It calls `lmLogClose`, which frees the memory, but if `jfsCommit` isn't properly stopped or synchronized, we have a clear race condition. I need to dive into `jfs_umount` and `jfs_put_super` to see exactly how they handle the `jfsCommit` thread. That's where the answer lies. This is a classic example of unmounting and pending commit operations leading to trouble.
|
| 9/2 |
2026/05/11 23:30 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:fs/jfs/jfs_umount.c IncludeLines:true Name:jfs_umount]
Results: map[SourceCode: 27: /*
28: * NAME: jfs_umount(vfsp, flags, crp)
29: *
30: * FUNCTION: vfs_umount()
31: *
32: * PARAMETERS: vfsp - virtual file system pointer
33: * flags - unmount for shutdown
34: * crp - credential
35: *
36: * RETURN : EBUSY - device has open files
37: */
38: int jfs_umount(struct super_block *sb)
39: {
40: struct jfs_sb_info *sbi = JFS_SBI(sb);
41: struct inode *ipbmap = sbi->ipbmap;
42: struct inode *ipimap = sbi->ipimap;
43: struct inode *ipaimap = sbi->ipaimap;
44: struct inode *ipaimap2 = sbi->ipaimap2;
45: struct jfs_log *log;
46: int rc = 0;
47:
48: jfs_info("UnMount JFS: sb:0x%p", sb);
49:
50: /*
51: * update superblock and close log
52: *
53: * if mounted read-write and log based recovery was enabled
54: */
55: if ((log = sbi->log))
56: /*
57: * Wait for outstanding transactions to be written to log:
58: */
59: jfs_flush_journal(log, 2);
60:
61: /*
62: * Hold log lock so write_special_inodes (lmLogSync) cannot see
63: * this sbi with a NULL inode pointer while iterating log->sb_list.
64: */
65: if (log)
66: LOG_LOCK(log);
67: /*
68: * close fileset inode allocation map (aka fileset inode)
69: */
70: diUnmount(ipimap, 0);
71:
72: diFreeSpecial(ipimap);
73: sbi->ipimap = NULL;
74:
75: /*
76: * close secondary aggregate inode allocation map
77: */
78: if (ipaimap2) {
79: diUnmount(ipaimap2, 0);
80: diFreeSpecial(ipaimap2);
81: sbi->ipaimap2 = NULL;
82: }
83:
84: /*
85: * close aggregate inode allocation map
86: */
87: diUnmount(ipaimap, 0);
88: diFreeSpecial(ipaimap);
89: sbi->ipaimap = NULL;
90:
91: /*
92: * close aggregate block allocation map
93: */
94: dbUnmount(ipbmap, 0);
95:
96: diFreeSpecial(ipbmap);
97: sbi->ipbmap = NULL;
98:
99: /*
100: * Make sure all metadata makes it to disk before we mark
101: * the superblock as clean
102: */
103: filemap_write_and_wait(sbi->direct_inode->i_mapping);
104:
105: if (log)
106: LOG_UNLOCK(log);
107:
108: /*
109: * ensure all file system file pages are propagated to their
110: * home blocks on disk (and their in-memory buffer pages are
111: * invalidated) BEFORE updating file system superblock state
112: * (to signify file system is unmounted cleanly, and thus in
113: * consistent state) and log superblock active file system
114: * list (to signify skip logredo()).
115: */
116: if (log) { /* log = NULL if read-only mount */
117: updateSuper(sb, FM_CLEAN);
118:
119: /*
120: * close log:
121: *
122: * remove file system from log active file system list.
123: */
124: rc = lmLogClose(sb);
125: }
126: jfs_info("UnMount JFS Complete: rc = %d", rc);
127: return rc;
128: }
SourceFile:fs/jfs/jfs_umount.c]
|
| 10/2 |
2026/05/11 23:30 |
llm |
debugger |
0m
Model:
Tokens:
input: 106119
output: 44
thoughts: 26
Thoughts: Here's my summary, as the thought process unfolds:
**Diving into the JFS Unmount Sequence**
Okay, so `jfs_umount` is the starting point here. My initial thought is to trace the log closure process, which means focusing on how the system handles log files during an unmount. The code seems to call `lmLogClose(sb)`. Time to dig into `lmLogClose`. Let's see what's happening within that function.
|
| 11/2 |
2026/05/11 23:30 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:fs/jfs/jfs_logmgr.c IncludeLines:true Name:lmLogClose]
Results: map[SourceCode:1420: /*
1421: * NAME: lmLogClose()
1422: *
1423: * FUNCTION: remove file system <ipmnt> from active list of log <iplog>
1424: * and close it on last close.
1425: *
1426: * PARAMETER: sb - superblock
1427: *
1428: * RETURN: errors from subroutines
1429: *
1430: * serialization:
1431: */
1432: int lmLogClose(struct super_block *sb)
1433: {
1434: struct jfs_sb_info *sbi = JFS_SBI(sb);
1435: struct jfs_log *log = sbi->log;
1436: struct file *bdev_file;
1437: int rc = 0;
1438:
1439: jfs_info("lmLogClose: log:0x%p", log);
1440:
1441: mutex_lock(&jfs_log_mutex);
1442: LOG_LOCK(log);
1443: list_del(&sbi->log_list);
1444: LOG_UNLOCK(log);
1445: sbi->log = NULL;
1446:
1447: /*
1448: * We need to make sure all of the "written" metapages
1449: * actually make it to disk
1450: */
1451: sync_blockdev(sb->s_bdev);
1452:
1453: if (test_bit(log_INLINELOG, &log->flag)) {
1454: /*
1455: * in-line log in host file system
1456: */
1457: rc = lmLogShutdown(log);
1458: kfree(log);
1459: goto out;
1460: }
1461:
1462: if (!log->no_integrity)
1463: lmLogFileSystem(log, sbi, 0);
1464:
1465: if (!list_empty(&log->sb_list))
1466: goto out;
1467:
1468: /*
1469: * TODO: ensure that the dummy_log is in a state to allow
1470: * lbmLogShutdown to deallocate all the buffers and call
1471: * kfree against dummy_log. For now, leave dummy_log & its
1472: * buffers in memory, and resuse if another no-integrity mount
1473: * is requested.
1474: */
1475: if (log->no_integrity)
1476: goto out;
1477:
1478: /*
1479: * external log as separate logical volume
1480: */
1481: list_del(&log->journal_list);
1482: bdev_file = log->bdev_file;
1483: rc = lmLogShutdown(log);
1484:
1485: bdev_fput(bdev_file);
1486:
1487: kfree(log);
1488:
1489: out:
1490: mutex_unlock(&jfs_log_mutex);
1491: jfs_info("lmLogClose: exit(%d)", rc);
1492: return rc;
1493: }
SourceFile:fs/jfs/jfs_logmgr.c]
|
| 12/2 |
2026/05/11 23:30 |
llm |
debugger |
0m
Model:
Tokens:
input: 107308
output: 44
thoughts: 50
Thoughts: Here's my take on those thoughts:
**Analyzing the `lmLogClose` Function**
Okay, so `lmLogClose` calls `lmLogShutdown(log)` first, and then it frees the memory allocated to the log with `kfree(log)`. Seems pretty straightforward, the usual cleanup routine. But wait a minute... I need to be sure. Does `lmLogShutdown` handle the termination of that `jfsCommit` thread, or is that handled elsewhere? I need to dig into the `lmLogShutdown` function itself to be absolutely certain. Safety first β I don't want any resource leaks or, worse, race conditions. Let's see what's going on in there.
|
| 13/2 |
2026/05/11 23:31 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:fs/jfs/jfs_logmgr.c IncludeLines:true Name:lmLogShutdown]
Results: map[SourceCode:1614: /*
1615: * NAME: lmLogShutdown()
1616: *
1617: * FUNCTION: log shutdown at last LogClose().
1618: *
1619: * write log syncpt record.
1620: * update super block to set redone flag to 0.
1621: *
1622: * PARAMETER: log - log inode
1623: *
1624: * RETURN: 0 - success
1625: *
1626: * serialization: single last close thread
1627: */
1628: int lmLogShutdown(struct jfs_log * log)
1629: {
1630: int rc;
1631: struct lrd lrd;
1632: int lsn;
1633: struct logsuper *logsuper;
1634: struct lbuf *bpsuper;
1635: struct lbuf *bp;
1636: struct logpage *lp;
1637:
1638: jfs_info("lmLogShutdown: log:0x%p", log);
1639:
1640: jfs_flush_journal(log, 2);
1641:
1642: /*
1643: * write the last SYNCPT record with syncpoint = 0
1644: * (i.e., log redo up to HERE !)
1645: */
1646: lrd.logtid = 0;
1647: lrd.backchain = 0;
1648: lrd.type = cpu_to_le16(LOG_SYNCPT);
1649: lrd.length = 0;
1650: lrd.log.syncpt.sync = 0;
1651:
1652: lsn = lmWriteRecord(log, NULL, &lrd, NULL);
1653: bp = log->bp;
1654: lp = (struct logpage *) bp->l_ldata;
1655: lp->h.eor = lp->t.eor = cpu_to_le16(bp->l_eor);
1656: lbmWrite(log, log->bp, lbmWRITE | lbmRELEASE | lbmSYNC, 0);
1657: lbmIOWait(log->bp, lbmFREE);
1658: log->bp = NULL;
1659:
1660: /*
1661: * synchronous update log superblock
1662: * mark log state as shutdown cleanly
1663: * (i.e., Log does not need to be replayed).
1664: */
1665: if ((rc = lbmRead(log, 1, &bpsuper)))
1666: goto out;
1667:
1668: logsuper = (struct logsuper *) bpsuper->l_ldata;
1669: logsuper->state = cpu_to_le32(LOGREDONE);
1670: logsuper->end = cpu_to_le32(lsn);
1671: lbmDirectWrite(log, bpsuper, lbmWRITE | lbmRELEASE | lbmSYNC);
1672: rc = lbmIOWait(bpsuper, lbmFREE);
1673:
1674: jfs_info("lmLogShutdown: lsn:0x%x page:%d eor:%d",
1675: lsn, log->page, log->eor);
1676:
1677: out:
1678: /*
1679: * shutdown per log i/o
1680: */
1681: lbmLogShutdown(log);
1682:
1683: if (rc) {
1684: jfs_warn("lmLogShutdown: exit(%d)", rc);
1685: }
1686: return rc;
1687: }
SourceFile:fs/jfs/jfs_logmgr.c]
|
| 14/2 |
2026/05/11 23:31 |
llm |
debugger |
0m
Model:
Tokens:
input: 108671
output: 53
thoughts: 50
Thoughts: Okay, let's see what's going on here.
**Analyzing a File System Journal Flush**
Right, so I'm looking at this function call: `jfs_flush_journal(log, 2)`. That immediately triggers a question, given my experience with journaled file systems. I need to understand the context. Why is this flush happening? Is it a regular checkpoint, or a forced flush due to some write activity? And the more pressing thought that jumps to mind is, hang on... didn't I see something about a `jfsCommit` function in relation to the mount? Wasn't that created in `jfs_mount_rw`? Yes, that's right. I'll need to go back and check the code in `jfs_mount_rw` and figure out *exactly* how and where `jfsCommit` gets initialized. I need to trace the creation of `jfsCommit` because understanding its purpose will help understand this `jfs_flush_journal` call. I need to confirm its relation and role within this journal flushing operation.
|
| 15/2 |
2026/05/11 23:31 |
tool |
codesearch-find-references |
0m
Error: requested entity does not exist
Args: map[ContextFile:fs/jfs/jfs_txnmgr.c IncludeSnippetLines:0 Name:jfsCommit SourceTreePrefix:]
Results: map[References:<nil> TruncatedOutput:false]
|
| 16/2 |
2026/05/11 23:31 |
llm |
debugger |
0m
Model:
Tokens:
input: 109026
output: 17
thoughts: 28
Thoughts: Okay, here's my attempt at summarizing the thought process, as if it were my own, assuming the user is an expert.
**Initial Investigation into `jfsCommit`**
Right, the thread name is `jfsCommit`. My first instinct is to zero in on the relevant kernel functions. Let's start with a focused search. Given the context, `kthread_run` is a very likely candidate, especially if the `jfsCommit` process is set up as a kernel thread. Alternatively, I'll go directly for `jfsCommit`, hoping to find the exact function where the commit logic is triggered and the thread started. This direct search might immediately reveal the core of the commit process. Either way, these two keywords should get me the essential starting points.
|
| 17/2 |
2026/05/11 23:31 |
tool |
grepper |
0m
Args: map[Expression:jfsCommit]
Results: map[Output:fs/jfs/super.c=50=MODULE_PARM_DESC(commit_threads, "Number of commit threads");
fs/jfs/super.c-51-
fs/jfs/super.c:52:static struct task_struct *jfsCommitThread[MAX_COMMIT_THREADS];
fs/jfs/super.c-53-struct task_struct *jfsIOthread;
--
fs/jfs/super.c=951=static int __init init_jfs_fs(void)
--
fs/jfs/super.c-998- for (i = 0; i < commit_threads; i++) {
fs/jfs/super.c:999: jfsCommitThread[i] = kthread_run(jfs_lazycommit, NULL,
fs/jfs/super.c:1000: "jfsCommit");
fs/jfs/super.c:1001: if (IS_ERR(jfsCommitThread[i])) {
fs/jfs/super.c:1002: rc = PTR_ERR(jfsCommitThread[i]);
fs/jfs/super.c-1003- jfs_err("init_jfs_fs: fork failed w/rc = %d", rc);
--
fs/jfs/super.c-1029- for (i = 0; i < commit_threads; i++)
fs/jfs/super.c:1030: kthread_stop(jfsCommitThread[i]);
fs/jfs/super.c-1031- kthread_stop(jfsIOthread);
--
fs/jfs/super.c=1041=static void __exit exit_jfs_fs(void)
--
fs/jfs/super.c-1051- for (i = 0; i < commit_threads; i++)
fs/jfs/super.c:1052: kthread_stop(jfsCommitThread[i]);
fs/jfs/super.c-1053- kthread_stop(jfsSyncThread);
]
|
| 18/2 |
2026/05/11 23:31 |
llm |
debugger |
0m
Model:
Tokens:
input: 109763
output: 47
thoughts: 57
Thoughts: Okay, here's my take on those thoughts, framed as my own:
**Global Scope and Transaction Processing in JFS**
Right, so digging into this, it's immediately clear that the `jfsCommit` threads have a global scope. They're not tied to individual filesystems, which is an important design choice. They're birthed during the `init_jfs_fs` phase β that's when they're actually created and brought to life β and they're put to sleep again during `exit_jfs_fs`.
The key thing is, these threads are responsible for processing transactions across *all* JFS filesystems within the system. That architecture immediately brings a mental checklist to me. That's a potential bottleneck and needs to be handled elegantly and efficiently. It demands careful consideration around locking, queueing, and I/O scheduling to prevent contention when managing multiple file systems simultaneously.
Now, my next logical step is to dive into how this global transaction processing happens, and I think `jfs_lazycommit` is the next place I need to focus. That's likely the mechanism that orchestrates the actual commit operations.
|
| 19/2 |
2026/05/11 23:31 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:fs/jfs/jfs_txnmgr.c IncludeLines:true Name:jfs_lazycommit]
Results: map[SourceCode:2693: /*
2694: * jfs_lazycommit(void)
2695: *
2696: * To be run as a kernel daemon. If lbmIODone is called in an interrupt
2697: * context, or where blocking is not wanted, this routine will process
2698: * committed transactions from the unlock queue.
2699: */
2700: int jfs_lazycommit(void *arg)
2701: {
2702: int WorkDone;
2703: struct tblock *tblk;
2704: unsigned long flags;
2705: struct jfs_sb_info *sbi;
2706:
2707: set_freezable();
2708: do {
2709: LAZY_LOCK(flags);
2710: jfs_commit_thread_waking = 0; /* OK to wake another thread */
2711: while (!list_empty(&TxAnchor.unlock_queue)) {
2712: WorkDone = 0;
2713: list_for_each_entry(tblk, &TxAnchor.unlock_queue,
2714: cqueue) {
2715:
2716: sbi = JFS_SBI(tblk->sb);
2717: /*
2718: * For each volume, the transactions must be
2719: * handled in order. If another commit thread
2720: * is handling a tblk for this superblock,
2721: * skip it
2722: */
2723: if (sbi->commit_state & IN_LAZYCOMMIT)
2724: continue;
2725:
2726: sbi->commit_state |= IN_LAZYCOMMIT;
2727: WorkDone = 1;
2728:
2729: /*
2730: * Remove transaction from queue
2731: */
2732: list_del(&tblk->cqueue);
2733:
2734: LAZY_UNLOCK(flags);
2735: txLazyCommit(tblk);
2736: LAZY_LOCK(flags);
2737:
2738: sbi->commit_state &= ~IN_LAZYCOMMIT;
2739: /*
2740: * Don't continue in the for loop. (We can't
2741: * anyway, it's unsafe!) We want to go back to
2742: * the beginning of the list.
2743: */
2744: break;
2745: }
2746:
2747: /* If there was nothing to do, don't continue */
2748: if (!WorkDone)
2749: break;
2750: }
2751: /* In case a wakeup came while all threads were active */
2752: jfs_commit_thread_waking = 0;
2753:
2754: if (freezing(current)) {
2755: LAZY_UNLOCK(flags);
2756: try_to_freeze();
2757: } else {
2758: DECLARE_WAITQUEUE(wq, current);
2759:
2760: add_wait_queue(&jfs_commit_thread_wait, &wq);
2761: set_current_state(TASK_INTERRUPTIBLE);
2762: LAZY_UNLOCK(flags);
2763: schedule();
2764: remove_wait_queue(&jfs_commit_thread_wait, &wq);
2765: }
2766: } while (!kthread_should_stop());
2767:
2768: if (!list_empty(&TxAnchor.unlock_queue))
2769: jfs_err("jfs_lazycommit being killed w/pending transactions!");
2770: else
2771: jfs_info("jfs_lazycommit being killed");
2772: return 0;
2773: }
SourceFile:fs/jfs/jfs_txnmgr.c]
|
| 20/2 |
2026/05/11 23:31 |
llm |
debugger |
0m
Model:
Tokens:
input: 111266
output: 45
thoughts: 49
Thoughts: Okay, let's break this down.
**Diving into the `jfs_lazycommit` Process**
Alright, so I'm looking at how `jfs_lazycommit` functions. From what I can see, it's directly interacting with the `TxAnchor.unlock_queue`. This queue is where things are held, waiting to be processed. The core of this seems to revolve around grabbing a `tblk` β a transaction block, I assume β from that queue. Once it has a `tblk` in hand, it then hands it off to `txLazyCommit`. Let's now shift our focus to understand what `txLazyCommit` actually does. I want to understand what happens to this `tblk` next.
|
| 21/2 |
2026/05/11 23:31 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:fs/jfs/jfs_txnmgr.c IncludeLines:true Name:txLazyCommit]
Results: map[SourceCode:2644: /*
2645: * txLazyCommit(void)
2646: *
2647: * All transactions except those changing ipimap (COMMIT_FORCE) are
2648: * processed by this routine. This insures that the inode and block
2649: * allocation maps are updated in order. For synchronous transactions,
2650: * let the user thread finish processing after txUpdateMap() is called.
2651: */
2652: static void txLazyCommit(struct tblock * tblk)
2653: {
2654: struct jfs_log *log;
2655:
2656: while (((tblk->flag & tblkGC_READY) == 0) &&
2657: ((tblk->flag & tblkGC_UNLOCKED) == 0)) {
2658: /* We must have gotten ahead of the user thread
2659: */
2660: jfs_info("jfs_lazycommit: tblk 0x%p not unlocked", tblk);
2661: yield();
2662: }
2663:
2664: jfs_info("txLazyCommit: processing tblk 0x%p", tblk);
2665:
2666: txUpdateMap(tblk);
2667:
2668: log = (struct jfs_log *) JFS_SBI(tblk->sb)->log;
2669:
2670: spin_lock_irq(&log->gclock); // LOGGC_LOCK
2671:
2672: tblk->flag |= tblkGC_COMMITTED;
2673:
2674: if (tblk->flag & tblkGC_READY)
2675: log->gcrtc--;
2676:
2677: wake_up_all(&tblk->gcwait); // LOGGC_WAKEUP
2678:
2679: /*
2680: * Can't release log->gclock until we've tested tblk->flag
2681: */
2682: if (tblk->flag & tblkGC_LAZY) {
2683: spin_unlock_irq(&log->gclock); // LOGGC_UNLOCK
2684: txUnlock(tblk);
2685: tblk->flag &= ~tblkGC_LAZY;
2686: txEnd(tblk - TxBlock); /* Convert back to tid */
2687: } else
2688: spin_unlock_irq(&log->gclock); // LOGGC_UNLOCK
2689:
2690: jfs_info("txLazyCommit: done: tblk = 0x%p", tblk);
2691: }
SourceFile:fs/jfs/jfs_txnmgr.c]
|
| 22/2 |
2026/05/11 23:31 |
llm |
debugger |
0m
Model:
Tokens:
input: 112309
output: 44
thoughts: 62
Thoughts: **Analyzing Potential Locking Conflicts in the JFS File System**
Okay, here's what's running through my head. I'm looking at some JFS code, specifically around transaction management. I see that `txLazyCommit` is accessing the log structure, specifically pulling the `log` pointer from the superblock information (`JFS_SBI(tblk->sb)->log`) and then accessing `log->gclock`. Hmm, that's interesting. The global clock, `gclock`, is often a point of contention in concurrent systems.
Then it hits me - hang on a second, isn't `txEnd` also involved with the `log` structure? I need to quickly verify if `txEnd` is also going after `log`. If `txEnd` and `txLazyCommit` are both hitting the same log fields, especially `gclock`, that's a red flag. I should double-check how `txEnd` accesses the `log` structure to verify how these two routines might interact. Let's dig into `txEnd` and see what it's doing.
|
| 23/2 |
2026/05/11 23:31 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:fs/jfs/jfs_txnmgr.c IncludeLines:true Name:txEnd]
Results: map[SourceCode: 485: /*
486: * txEnd()
487: *
488: * function: free specified transaction block.
489: *
490: * logsync barrier processing:
491: *
492: * serialization:
493: */
494: void txEnd(tid_t tid)
495: {
496: struct tblock *tblk = tid_to_tblock(tid);
497: struct jfs_log *log;
498:
499: jfs_info("txEnd: tid = %d", tid);
500: TXN_LOCK();
501:
502: /*
503: * wakeup transactions waiting on the page locked
504: * by the current transaction
505: */
506: TXN_WAKEUP(&tblk->waitor);
507:
508: log = JFS_SBI(tblk->sb)->log;
509:
510: /*
511: * Lazy commit thread can't free this guy until we mark it UNLOCKED,
512: * otherwise, we would be left with a transaction that may have been
513: * reused.
514: *
515: * Lazy commit thread will turn off tblkGC_LAZY before calling this
516: * routine.
517: */
518: if (tblk->flag & tblkGC_LAZY) {
519: jfs_info("txEnd called w/lazy tid: %d, tblk = 0x%p", tid, tblk);
520: TXN_UNLOCK();
521:
522: spin_lock_irq(&log->gclock); // LOGGC_LOCK
523: tblk->flag |= tblkGC_UNLOCKED;
524: spin_unlock_irq(&log->gclock); // LOGGC_UNLOCK
525: return;
526: }
527:
528: jfs_info("txEnd: tid: %d, tblk = 0x%p", tid, tblk);
529:
530: assert(tblk->next == 0);
531:
532: /*
533: * insert tblock back on freelist
534: */
535: tblk->next = TxAnchor.freetid;
536: TxAnchor.freetid = tid;
537:
538: /*
539: * mark the tblock not active
540: */
541: if (--log->active == 0) {
542: clear_bit(log_FLUSH, &log->flag);
543:
544: /*
545: * synchronize with logsync barrier
546: */
547: if (test_bit(log_SYNCBARRIER, &log->flag)) {
548: TXN_UNLOCK();
549:
550: /* write dirty metadata & forward log syncpt */
551: jfs_syncpt(log, 1);
552:
553: jfs_info("log barrier off: 0x%x", log->lsn);
554:
555: /* enable new transactions start */
556: clear_bit(log_SYNCBARRIER, &log->flag);
557:
558: /* wakeup all waitors for logsync barrier */
559: TXN_WAKEUP(&log->syncwait);
560:
561: goto wakeup;
562: }
563: }
564:
565: TXN_UNLOCK();
566: wakeup:
567: /*
568: * wakeup all waitors for a free tblock
569: */
570: TXN_WAKEUP(&TxAnchor.freewait);
571: }
SourceFile:fs/jfs/jfs_txnmgr.c]
|
| 24/2 |
2026/05/11 23:31 |
llm |
debugger |
0m
Model:
Tokens:
input: 113829
output: 48
thoughts: 245
Thoughts: **My Analysis of a Potential JFS Crash**
Okay, so I'm looking at this crash that seems to be happening within the JFS filesystem, specifically during the transaction end process, specifically in `txEnd`. I see the code is grabbing the `log` structure using `log = JFS_SBI(tblk->sb)->log;`. Nothing immediately alarming there.
Then, there's a decrement of `log->active`, which seems to track active log usage. If it hits zero, it looks like `log_FLUSH` is cleared. Makes sense. Then there is a synchronization with a logsync barrier. And after that, `jfs_syncpt` is called, which in turn calls `lmLogSync`. Aha! The crash is happening within `lmLogSync`.
My initial thought is that Iβm assuming the problem is likely that the `log` structure is being freed *before* `lmLogSync` is called and completes. And sure enough, digging deeper I see that `lmLogClose` seems to be the culprit as it could be freeing `log`.
Why is `log` being freed while there's still work to do in a transaction on `tblk`? I'm betting that's the key. How can that happen? Looks like `jfs_umount` calls `jfs_flush_journal(log, 2)` and subsequently `lmLogClose(sb)`. So, `umount` is a possible trigger here.
The crucial question is, does `jfs_flush_journal` properly wait for all transactions to finish before proceeding? If it doesn't, or if it waits incorrectly, it could lead to this race condition where `lmLogClose` is called prematurely. Thatβs my primary hypothesis. I need to examine `jfs_flush_journal` closely to see if it waits for all transactions to complete before calling `lmLogClose`.
|
| 25/2 |
2026/05/11 23:31 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:fs/jfs/jfs_txnmgr.c IncludeLines:true Name:jfs_flush_journal]
Results: map[SourceCode:1496: /*
1497: * NAME: jfs_flush_journal()
1498: *
1499: * FUNCTION: initiate write of any outstanding transactions to the journal
1500: * and optionally wait until they are all written to disk
1501: *
1502: * wait == 0 flush until latest txn is committed, don't wait
1503: * wait == 1 flush until latest txn is committed, wait
1504: * wait > 1 flush until all txn's are complete, wait
1505: */
1506: void jfs_flush_journal(struct jfs_log *log, int wait)
1507: {
1508: int i;
1509: struct tblock *target = NULL;
1510:
1511: /* jfs_write_inode may call us during read-only mount */
1512: if (!log)
1513: return;
1514:
1515: jfs_info("jfs_flush_journal: log:0x%p wait=%d", log, wait);
1516:
1517: LOGGC_LOCK(log);
1518:
1519: if (!list_empty(&log->cqueue)) {
1520: /*
1521: * This ensures that we will keep writing to the journal as long
1522: * as there are unwritten commit records
1523: */
1524: target = list_entry(log->cqueue.prev, struct tblock, cqueue);
1525:
1526: if (test_bit(log_FLUSH, &log->flag)) {
1527: /*
1528: * We're already flushing.
1529: * if flush_tblk is NULL, we are flushing everything,
1530: * so leave it that way. Otherwise, update it to the
1531: * latest transaction
1532: */
1533: if (log->flush_tblk)
1534: log->flush_tblk = target;
1535: } else {
1536: /* Only flush until latest transaction is committed */
1537: log->flush_tblk = target;
1538: set_bit(log_FLUSH, &log->flag);
1539:
1540: /*
1541: * Initiate I/O on outstanding transactions
1542: */
1543: if (!(log->cflag & logGC_PAGEOUT)) {
1544: log->cflag |= logGC_PAGEOUT;
1545: lmGCwrite(log, 0);
1546: }
1547: }
1548: }
1549: if ((wait > 1) || test_bit(log_SYNCBARRIER, &log->flag)) {
1550: /* Flush until all activity complete */
1551: set_bit(log_FLUSH, &log->flag);
1552: log->flush_tblk = NULL;
1553: }
1554:
1555: if (wait && target && !(target->flag & tblkGC_COMMITTED)) {
1556: DECLARE_WAITQUEUE(__wait, current);
1557:
1558: add_wait_queue(&target->gcwait, &__wait);
1559: set_current_state(TASK_UNINTERRUPTIBLE);
1560: LOGGC_UNLOCK(log);
1561: schedule();
1562: LOGGC_LOCK(log);
1563: remove_wait_queue(&target->gcwait, &__wait);
1564: }
1565: LOGGC_UNLOCK(log);
1566:
1567: if (wait < 2)
1568: return;
1569:
1570: write_special_inodes(log, filemap_fdatawrite);
1571:
1572: /*
1573: * If there was recent activity, we may need to wait
1574: * for the lazycommit thread to catch up
1575: */
1576: if ((!list_empty(&log->cqueue)) || !list_empty(&log->synclist)) {
1577: for (i = 0; i < 200; i++) { /* Too much? */
1578: msleep(250);
1579: write_special_inodes(log, filemap_fdatawrite);
1580: if (list_empty(&log->cqueue) &&
1581: list_empty(&log->synclist))
1582: break;
1583: }
1584: }
1585: assert(list_empty(&log->cqueue));
1586:
1587: #ifdef CONFIG_JFS_DEBUG
1588: if (!list_empty(&log->synclist)) {
1589: struct logsyncblk *lp;
1590:
1591: printk(KERN_ERR "jfs_flush_journal: synclist not empty\n");
1592: list_for_each_entry(lp, &log->synclist, synclist) {
1593: if (lp->xflag & COMMIT_PAGE) {
1594: struct metapage *mp = (struct metapage *)lp;
1595: print_hex_dump(KERN_ERR, "metapage: ",
1596: DUMP_PREFIX_ADDRESS, 16, 4,
1597: mp, sizeof(struct metapage), 0);
1598: print_hex_dump(KERN_ERR, "page: ",
1599: DUMP_PREFIX_ADDRESS, 16,
1600: sizeof(long), mp->folio,
1601: sizeof(struct page), 0);
1602: } else
1603: print_hex_dump(KERN_ERR, "tblock:",
1604: DUMP_PREFIX_ADDRESS, 16, 4,
1605: lp, sizeof(struct tblock), 0);
1606: }
1607: }
1608: #else
1609: WARN_ON(!list_empty(&log->synclist));
1610: #endif
1611: clear_bit(log_FLUSH, &log->flag);
1612: }
SourceFile:fs/jfs/jfs_logmgr.c]
|
| 26/2 |
2026/05/11 23:31 |
llm |
debugger |
0m
Model:
Tokens:
input: 116335
output: 53
thoughts: 84
Thoughts: Okay, let me break this down.
**Diving into JFS Journal Flushing**
Right, `jfs_flush_journal` is supposed to ensure everything is written out. I see it waiting for the `log->cqueue` and `log->synclist` to be clear. That makes sense; those are the committed and synchronized data queues, respectively. But... it doesn't seem to care about `TxAnchor.unlock_queue`. That's a potential problem, something's not right. Hang on... isn't `tblk`, the transaction block, added to `TxAnchor.unlock_queue` in `txUpdateMap`? I need to double-check that. Let me trace that logic and make sure I haven't missed something. Where exactly *is* that added? I need a complete picture here before I can understand what's missing.
|
| 27/2 |
2026/05/11 23:31 |
tool |
codesearch-find-references |
0m
Error: requested entity does not exist
Args: map[ContextFile:fs/jfs/jfs_txnmgr.c IncludeSnippetLines:0 Name:unlock_queue SourceTreePrefix:]
Results: map[References:<nil> TruncatedOutput:false]
|
| 28/2 |
2026/05/11 23:31 |
llm |
debugger |
0m
Model:
Tokens:
input: 116679
output: 17
thoughts: 20
Thoughts: Here's my attempt at summarizing the thought process, tailored for an expert audience:
**Diving into the `TxAnchor.unlock_queue` Method**
Okay, so I'm thinking about `TxAnchor.unlock_queue`. That method name immediately triggers a mental search. I need to understand its role within the system, its interaction with other components, and potential implications for concurrency or state management. The next thing I'll do is probably pull up the codebase and run a `grep` for "unlock_queue". That should give me the context I need. I'm hoping this will show me all the places this method is called, how the queue is populated, and how its contents are processed. Understanding the call sites is key to grasping the overall logic and identifying any potential bottlenecks or areas of concern. It could be something straightforward or something quite intricate, depending on how this "unlock_queue" is used.
|
| 29/2 |
2026/05/11 23:32 |
tool |
grepper |
0m
Args: map[Expression:unlock_queue]
Results: map[Output:drivers/iio/buffer/industrialio-buffer-dma.c=771=EXPORT_SYMBOL_NS_GPL(iio_dma_buffer_lock_queue, "IIO_DMA_BUFFER");
drivers/iio/buffer/industrialio-buffer-dma.c-772-
drivers/iio/buffer/industrialio-buffer-dma.c:773:void iio_dma_buffer_unlock_queue(struct iio_buffer *buffer)
drivers/iio/buffer/industrialio-buffer-dma.c-774-{
--
drivers/iio/buffer/industrialio-buffer-dma.c-778-}
drivers/iio/buffer/industrialio-buffer-dma.c:779:EXPORT_SYMBOL_NS_GPL(iio_dma_buffer_unlock_queue, "IIO_DMA_BUFFER");
drivers/iio/buffer/industrialio-buffer-dma.c-780-
--
drivers/iio/buffer/industrialio-buffer-dmaengine.c=158=static const struct iio_buffer_access_funcs iio_dmaengine_buffer_ops = {
--
drivers/iio/buffer/industrialio-buffer-dmaengine.c-174- .lock_queue = iio_dma_buffer_lock_queue,
drivers/iio/buffer/industrialio-buffer-dmaengine.c:175: .unlock_queue = iio_dma_buffer_unlock_queue,
drivers/iio/buffer/industrialio-buffer-dmaengine.c-176-
--
drivers/iio/industrialio-buffer.c=1822=static int iio_buffer_enqueue_dmabuf(struct iio_dev_buffer_pair *ib,
--
drivers/iio/industrialio-buffer.c-1926-
drivers/iio/industrialio-buffer.c:1927: if (buffer->access->unlock_queue)
drivers/iio/industrialio-buffer.c:1928: buffer->access->unlock_queue(buffer);
drivers/iio/industrialio-buffer.c-1929-
--
drivers/iio/industrialio-buffer.c-1935-err_queue_unlock:
drivers/iio/industrialio-buffer.c:1936: if (buffer->access->unlock_queue)
drivers/iio/industrialio-buffer.c:1937: buffer->access->unlock_queue(buffer);
drivers/iio/industrialio-buffer.c-1938-err_resv_unlock:
--
fs/jfs/jfs_txnmgr.c=53=static struct {
--
fs/jfs/jfs_txnmgr.c-59- int tlocksInUse; /* Number of tlocks in use */
fs/jfs/jfs_txnmgr.c:60: spinlock_t LazyLock; /* synchronize sync_queue & unlock_queue */
fs/jfs/jfs_txnmgr.c-61-/* struct tblock *sync_queue; * Transactions waiting for data sync */
fs/jfs/jfs_txnmgr.c:62: struct list_head unlock_queue; /* Txns waiting to be released */
fs/jfs/jfs_txnmgr.c-63- struct list_head anon_list; /* inodes having anonymous txns */
--
fs/jfs/jfs_txnmgr.c=225=int txInit(void)
--
fs/jfs/jfs_txnmgr.c-316- LAZY_LOCK_INIT();
fs/jfs/jfs_txnmgr.c:317: INIT_LIST_HEAD(&TxAnchor.unlock_queue);
fs/jfs/jfs_txnmgr.c-318-
--
fs/jfs/jfs_txnmgr.c=2700=int jfs_lazycommit(void *arg)
--
fs/jfs/jfs_txnmgr.c-2710- jfs_commit_thread_waking = 0; /* OK to wake another thread */
fs/jfs/jfs_txnmgr.c:2711: while (!list_empty(&TxAnchor.unlock_queue)) {
fs/jfs/jfs_txnmgr.c-2712- WorkDone = 0;
fs/jfs/jfs_txnmgr.c:2713: list_for_each_entry(tblk, &TxAnchor.unlock_queue,
fs/jfs/jfs_txnmgr.c-2714- cqueue) {
--
fs/jfs/jfs_txnmgr.c-2767-
fs/jfs/jfs_txnmgr.c:2768: if (!list_empty(&TxAnchor.unlock_queue))
fs/jfs/jfs_txnmgr.c-2769- jfs_err("jfs_lazycommit being killed w/pending transactions!");
--
fs/jfs/jfs_txnmgr.c=2775=void txLazyUnlock(struct tblock * tblk)
--
fs/jfs/jfs_txnmgr.c-2780-
fs/jfs/jfs_txnmgr.c:2781: list_add_tail(&tblk->cqueue, &TxAnchor.unlock_queue);
fs/jfs/jfs_txnmgr.c-2782- /*
--
fs/jfs/jfs_txnmgr.c=2959=int jfs_txanchor_proc_show(struct seq_file *m, void *v)
--
fs/jfs/jfs_txnmgr.c-2981- "jfs_tlocks_low = %d\n"
fs/jfs/jfs_txnmgr.c:2982: "unlock_queue is %sempty\n",
fs/jfs/jfs_txnmgr.c-2983- TxAnchor.freetid,
--
fs/jfs/jfs_txnmgr.c-2989- jfs_tlocks_low,
fs/jfs/jfs_txnmgr.c:2990: list_empty(&TxAnchor.unlock_queue) ? "" : "not ");
fs/jfs/jfs_txnmgr.c-2991- return 0;
--
include/linux/iio/buffer-dma.h=179=void iio_dma_buffer_lock_queue(struct iio_buffer *buffer);
include/linux/iio/buffer-dma.h:180:void iio_dma_buffer_unlock_queue(struct iio_buffer *buffer);
include/linux/iio/buffer-dma.h-181-struct device *iio_dma_buffer_get_dma_dev(struct iio_buffer *buffer);
--
include/linux/iio/buffer_impl.h=17=struct sg_table;
--
include/linux/iio/buffer_impl.h-56- * it is used when enqueueing DMABUF objects.
include/linux/iio/buffer_impl.h:57: * @unlock_queue: used to unlock a previously locked buffer queue
include/linux/iio/buffer_impl.h-58- * @modes: Supported operating modes by this buffer type
--
include/linux/iio/buffer_impl.h=69=struct iio_buffer_access_funcs {
--
include/linux/iio/buffer_impl.h-96- void (*lock_queue)(struct iio_buffer *buffer);
include/linux/iio/buffer_impl.h:97: void (*unlock_queue)(struct iio_buffer *buffer);
include/linux/iio/buffer_impl.h-98-
]
|
| 30/2 |
2026/05/11 23:32 |
llm |
debugger |
0m
Model:
Tokens:
input: 118882
output: 53
thoughts: 33
Thoughts: Okay, here's my take on those thoughts, tailored for an expert audience, presented in the first person:
**Delving into `txLazyUnlock` and its Dependencies**
Alright, so the initial observation is straightforward: `txLazyUnlock` adds a `tblk` (presumably a transaction block or related data structure) to `TxAnchor.unlock_queue`. This hints at a lazy unlocking mechanism, likely involving deferred processing or potentially asynchronous operations. My immediate follow-up thought is: *who* is calling this function? Understanding the callers of `txLazyUnlock` is key to grasping the overall flow and the situations that trigger this deferred unlock process. I need to trace the call graph to determine where `txLazyUnlock` fits into the broader transactional context, specifically to understand how `tblk` is being populated. Are there specific dependencies within the system, such as a check for specific conditions that are needed for the function to run? This will help me to determine potential locking and unlocking patterns within the system. Is it triggered in direct response to a specific event, or part of a more generalized management scheme? This will give me a greater level of insight.
|
| 31/2 |
2026/05/11 23:32 |
tool |
codesearch-find-references |
0m
Args: map[ContextFile:fs/jfs/jfs_txnmgr.c IncludeSnippetLines:0 Name:txLazyUnlock SourceTreePrefix:]
Results: map[References:[map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:lmPostGC SourceFile:fs/jfs/jfs_logmgr.c SourceLine:843]] TruncatedOutput:false]
|
| 32/2 |
2026/05/11 23:32 |
llm |
debugger |
0m
Model:
Tokens:
input: 119280
output: 44
thoughts: 21
Thoughts: Okay, here's my interpretation of that thought process, from an expert's perspective:
**Diving into `lmPostGC` After a Transactional Unlock**
Alright, so the system is telling me that `lmPostGC` is being called after a `txLazyUnlock`. That's interesting. My immediate thought is, "Okay, let's trace this and see what `lmPostGC` is *actually* doing." I need to understand the connection here. A lazy unlock suggests we're dealing with some form of deferred or optimized resource release, likely tied to transactional operations. The fact that `lmPostGC` follows implies it's potentially responsible for cleaning up *after* garbage collection (GC) or taking some action related to the GC cycle in response to the unlock. I'm especially keen to see if this is tied to specific data structures or resources that are tracked transactionally. It could be about handling stale pointers, removing entries from some transaction log, or perhaps ensuring that resources are correctly finalized post-GC and in sync with the transactional state. Time to get my hands dirty and investigate `lmPostGC` itself. This feels like a critical area for performance and correctness.
|
| 33/2 |
2026/05/11 23:32 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:fs/jfs/jfs_logmgr.c IncludeLines:true Name:lmPostGC]
Results: map[SourceCode: 788: /*
789: * NAME: lmPostGC()
790: *
791: * FUNCTION: group commit post-processing
792: * Processes transactions after their commit records have been written
793: * to disk, redriving log I/O if necessary.
794: *
795: * RETURN: None
796: *
797: * NOTE:
798: * This routine is called a interrupt time by lbmIODone
799: */
800: static void lmPostGC(struct lbuf * bp)
801: {
802: unsigned long flags;
803: struct jfs_log *log = bp->l_log;
804: struct logpage *lp;
805: struct tblock *tblk, *temp;
806:
807: //LOGGC_LOCK(log);
808: spin_lock_irqsave(&log->gclock, flags);
809: /*
810: * current pageout of group commit completed.
811: *
812: * remove/wakeup transactions from commit queue who were
813: * group committed with the current log page
814: */
815: list_for_each_entry_safe(tblk, temp, &log->cqueue, cqueue) {
816: if (!(tblk->flag & tblkGC_COMMIT))
817: break;
818: /* if transaction was marked GC_COMMIT then
819: * it has been shipped in the current pageout
820: * and made it to disk - it is committed.
821: */
822:
823: if (bp->l_flag & lbmERROR)
824: tblk->flag |= tblkGC_ERROR;
825:
826: /* remove it from the commit queue */
827: list_del(&tblk->cqueue);
828: tblk->flag &= ~tblkGC_QUEUE;
829:
830: if (tblk == log->flush_tblk) {
831: /* we can stop flushing the log now */
832: clear_bit(log_FLUSH, &log->flag);
833: log->flush_tblk = NULL;
834: }
835:
836: jfs_info("lmPostGC: tblk = 0x%p, flag = 0x%x", tblk,
837: tblk->flag);
838:
839: if (!(tblk->xflag & COMMIT_FORCE))
840: /*
841: * Hand tblk over to lazy commit thread
842: */
843: txLazyUnlock(tblk);
844: else {
845: /* state transition: COMMIT -> COMMITTED */
846: tblk->flag |= tblkGC_COMMITTED;
847:
848: if (tblk->flag & tblkGC_READY)
849: log->gcrtc--;
850:
851: LOGGC_WAKEUP(tblk);
852: }
853:
854: /* was page full before pageout ?
855: * (and this is the last tblk bound with the page)
856: */
857: if (tblk->flag & tblkGC_FREE)
858: lbmFree(bp);
859: /* did page become full after pageout ?
860: * (and this is the last tblk bound with the page)
861: */
862: else if (tblk->flag & tblkGC_EOP) {
863: /* finalize the page */
864: lp = (struct logpage *) bp->l_ldata;
865: bp->l_ceor = bp->l_eor;
866: lp->h.eor = lp->t.eor = cpu_to_le16(bp->l_eor);
867: jfs_info("lmPostGC: calling lbmWrite");
868: lbmWrite(log, bp, lbmWRITE | lbmRELEASE | lbmFREE,
869: 1);
870: }
871:
872: }
873:
874: /* are there any transactions who have entered lnGroupCommit()
875: * (whose COMMITs are after that of the last log page written.
876: * They are waiting for new group commit (above at (SLEEP 1))
877: * or lazy transactions are on a full (queued) log page,
878: * select the latest ready transaction as new group leader and
879: * wake her up to lead her group.
880: */
881: if ((!list_empty(&log->cqueue)) &&
882: ((log->gcrtc > 0) || (tblk->bp->l_wqnext != NULL) ||
883: test_bit(log_FLUSH, &log->flag) || jfs_tlocks_low))
884: /*
885: * Call lmGCwrite with new group leader
886: */
887: lmGCwrite(log, 1);
888:
889: /* no transaction are ready yet (transactions are only just
890: * queued (GC_QUEUE) and not entered for group commit yet).
891: * the first transaction entering group commit
892: * will elect herself as new group leader.
893: */
894: else
895: log->cflag &= ~logGC_PAGEOUT;
896:
897: //LOGGC_UNLOCK(log);
898: spin_unlock_irqrestore(&log->gclock, flags);
899: return;
900: }
SourceFile:fs/jfs/jfs_logmgr.c]
|
| 34/2 |
2026/05/11 23:32 |
llm |
debugger |
1m
Model:
Tokens:
input: 121302
output: 17
thoughts: 2778
Thoughts: **Analysis of a JFS Use-After-Free Vulnerability**
My thought process is focused on a potential race condition and use-after-free vulnerability within the JFS file system during unmount. The core issue revolves around the interaction between the journal flush process (`jfs_flush_journal`), the lazy commit thread (`jfs_lazycommit`), and the closure of the log (`lmLogClose`) during the unmount operation (`jfs_umount`).
First, I observe that `lmPostGC` removes a transaction block (`tblk`) from the journal's commit queue (`log->cqueue`) and initiates its unlock via `txLazyUnlock`. This function adds the block to `TxAnchor.unlock_queue` and signals a wait condition for the lazy commit thread. Simultaneously, `jfs_flush_journal`, which is called during the unmount process, waits for the commit queue to be emptied but *doesn't* account for items on `TxAnchor.unlock_queue`. This critical omission becomes the crux of the problem.
`jfs_flush_journal` eventually returns, and `jfs_umount` continues, invoking `lmLogClose`, which frees the journal (`log`). This frees the memory that the `log` pointer points to and sets the `log` pointer to NULL. Meanwhile, the `jfs_lazycommit` thread wakes up, processes the `tblk` from `TxAnchor.unlock_queue`, and calls `txLazyCommit`. Within `txLazyCommit`, operations such as `txUpdateMap` take place, and, crucially, the code attempts to access the journal log via `log = JFS_SBI(tblk->sb)->log;`. However, the log has already been freed, leading to a potential use-after-free vulnerability.
I initially anticipated a NULL pointer dereference, but the crash manifests as a KASAN slab-use-after-free, indicating that the `log` pointer is *not* NULL, but is a dangling pointer referencing freed memory. This suggests that a time-of-check-time-of-use (TOCTOU) race exists. My analysis zeroes in on `txLazyCommit` to understand the conditions that contribute to this vulnerability.
I note that `txUpdateMap` might be time-consuming. Because of this, it can allow `lmLogClose` to free `log` *after* a value has been read and *before* it is accessed in `txLazyCommit`. Further, `txLazyCommit` calls `txEnd` for a transaction block. `txEnd` then reads the `log` pointer again, before calling `jfs_syncpt`, and then `lmLogSync`. This suggests the actual problematic access occurs inside `lmLogSync`.
The crucial race lies in the concurrent execution of `jfs_umount` (which frees the log) and `jfs_lazycommit` (which is still using the log). Specifically, the timing is such that `txLazyCommit` might read the valid `log` pointer *before* `lmLogClose` clears the `sbi->log` field, but *after* `lmLogClose` has actually freed the memory associated with that pointer. Then, during the later stages of transaction processing, where `txEnd` may call `jfs_syncpt` to pass the `log` pointer to `lmLogSync`, the use-after-free occurs. I trace this sequence through several functions.
I realize that `lmLogClose` frees the `log` only if `log->sb_list` is empty, confirming that the last superblock using the log is being unmounted. The solution involves guaranteeing that `jfs_lazycommit` completes all operations on a superblock before `jfs_umount` proceeds with `lmLogClose`. The current implementation of `jfs_flush_journal` waits only for `cqueue` and `synclist` to be empty, failing to synchronize with transactions held on `TxAnchor.unlock_queue`. Therefore, `jfs_umount` should be modified to wait for the lazy commit thread to finish processing blocks associated with *this* superblock. This wait must be inserted prior to the call to `lmLogClose`. This could be implemented by waiting for `log->active` to reach zero.
|
| 35/2 |
2026/05/11 23:33 |
tool |
grepper |
0m
Args: map[Expression:log->active]
Results: map[Output:fs/jfs/jfs_logmgr.c=919=static int lmLogSync(struct jfs_log * log, int hard_sync)
--
fs/jfs/jfs_logmgr.c-1014- if (!test_bit(log_SYNCBARRIER, &log->flag) &&
fs/jfs/jfs_logmgr.c:1015: (written > LOGSYNC_BARRIER(logsize)) && log->active) {
fs/jfs/jfs_logmgr.c-1016- set_bit(log_SYNCBARRIER, &log->flag);
--
fs/jfs/jfs_txnmgr.c=350=tid_t txBegin(struct super_block *sb, int flag)
--
fs/jfs/jfs_txnmgr.c-430-
fs/jfs/jfs_txnmgr.c:431: ++log->active;
fs/jfs/jfs_txnmgr.c-432-
--
fs/jfs/jfs_txnmgr.c=494=void txEnd(tid_t tid)
--
fs/jfs/jfs_txnmgr.c-540- */
fs/jfs/jfs_txnmgr.c:541: if (--log->active == 0) {
fs/jfs/jfs_txnmgr.c-542- clear_bit(log_FLUSH, &log->flag);
]
|
| 36/2 |
2026/05/11 23:33 |
llm |
debugger |
0m
Model:
Tokens:
input: 125387
output: 43
thoughts: 942
Thoughts: **Analyzing a Potential Use-After-Free in JFS Unmount**
Okay, so I'm digging into this JFS unmount sequence, and I've spotted a potential race condition. Let's break this down. `log->active` is incremented when a transaction starts (`txBegin`) and decremented when it ends (`txEnd`). My initial thought was that `jfs_umount` should simply wait for `log->active` to hit zero, indicating all transactions are complete, before proceeding. But, that's not what happens. Instead, `jfs_umount` calls `jfs_flush_journal(log, 2)`.
So, I had to investigate if `jfs_flush_journal` handles the necessary waiting. Nope, `jfs_flush_journal` waits for `cqueue` and `synclist` to be empty, not `log->active`. And, I realized that just because the `cqueue` and `synclist` are empty doesn't mean `log->active` is zero. `tblk`s can still be in the `TxAnchor.unlock_queue`.
This is where it gets interesting. A transaction's data is moved from `cqueue` to `unlock_queue` when it's committed (`lmPostGC` calls `txLazyUnlock`). Then, `jfs_lazycommit` processes the `unlock_queue`, calling `txLazyCommit`, which in turn calls `txEnd` β finally decrementing `log->active`. That means `log->active` can be > 0 even when `cqueue` and `synclist` are empty because transactions could be in `unlock_queue` or being processed by `jfs_lazycommit`.
Here's the problem: if `jfs_umount` continues, calls `lmLogClose`, and frees the `log`, we have a potential use-after-free situation. `jfs_lazycommit` is still working on `tblk`s associated with this `log`, which will access `log` through `txLazyCommit` and `txEnd` after it has been freed.
The fix? I have a couple of options: Wait for `TxAnchor.unlock_queue` to be empty of `tblk`s belonging to this specific `sbi`, or wait for `log->active` to become zero.
But wait, is `log->active` specific to the `log` or the `sbi`? A `log` can be shared between multiple `sbi`s if they use the same external journal. However, often a `log` is 1:1 with an `sbi` (inline log). If a `log` is shared, `log->active` is the total number of active transactions for *all* `sbi`s using that `log`. So, waiting for `log->active == 0` could hang if other `sbi`s are still active.
However, remembering that `jfs_umount` calls `lmLogClose(sb)`, and within that `lmLogClose` there is:
```c
list_del(&sbi->log_list);
sbi->log = NULL;
if (!list_empty(&log->sb_list))
goto out;
```
If the `log` is shared, then `log->sb_list` will *not* be empty, and `log` will *not* be freed. So, the use-after-free is only a problem when this is the last `sbi` using the `log`. In this case, `log->sb_list` becomes empty, and the `log` gets freed. BUT, if `log->sb_list` is empty, there are no other `sbi`s using the log. So, logically, `log->active` *must* eventually reach zero, once all pending transactions for *this* `log` have been processed by `jfs_lazycommit`.
So, perhaps we can wait for `log->active == 0` within `lmLogClose`, before freeing the `log`? But, we must be careful. We can't hold `jfs_log_mutex` while waiting because that would create a deadlock scenario.
Finally, I need to consider what `jfs_umount` does *before* calling `lmLogClose`. It calls `diUnmount`, `dbUnmount`, etc. Do *those* functions start new transactions? No, since the filesystem is being unmounted, new *user* transactions are not possible. But, they might still write to disk. I need to investigate `diUnmount`...
|
| 37/2 |
2026/05/11 23:34 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:fs/jfs/jfs_imap.c IncludeLines:true Name:diUnmount]
Results: map[SourceCode: 162: /*
163: * NAME: diUnmount()
164: *
165: * FUNCTION: write to disk the incore inode map control structures for
166: * a fileset or aggregate at unmount time.
167: *
168: * PARAMETERS:
169: * ipimap - pointer to inode map inode for the aggregate or fileset.
170: *
171: * RETURN VALUES:
172: * 0 - success
173: * -ENOMEM - insufficient free virtual memory.
174: * -EIO - i/o error.
175: */
176: int diUnmount(struct inode *ipimap, int mounterror)
177: {
178: struct inomap *imap = JFS_IP(ipimap)->i_imap;
179:
180: /*
181: * update the on-disk inode map control structure
182: */
183:
184: if (!(mounterror || isReadOnly(ipimap)))
185: diSync(ipimap);
186:
187: /*
188: * Invalidate the page cache buffers
189: */
190: truncate_inode_pages(ipimap->i_mapping, 0);
191:
192: /*
193: * free in-memory control structure
194: */
195: kfree(imap);
196: JFS_IP(ipimap)->i_imap = NULL;
197:
198: return (0);
199: }
SourceFile:fs/jfs/jfs_imap.c]
|
| 38/2 |
2026/05/11 23:34 |
llm |
debugger |
0m
Model:
Tokens:
input: 127899
output: 42
thoughts: 14
Thoughts: Okay, here's my take on those thoughts, tailored for an expert audience, presented in the first person:
**Transactionality of `diSync` Write Operations**
Hmm, `diSync` is writing to disk, and the immediate question that pops into my head is: *Does it initiate a transaction?* That's the crux of it, isn't it? Without a transaction, we're talking about potential data corruption if a write fails midway β a classic nightmare scenario. I need to understand the guarantees it's offering. Is it leveraging the underlying filesystem's transactional capabilities (if any)? Or, is it implementing its own, potentially application-level, transaction mechanism? What are the implications if there's a power failure or crash during a `diSync` operation? Is it using a write-ahead log? Atomicity, consistency, isolation, and durability - the ACID properties β I'm immediately running through them. The level of transactionality (or lack thereof) will drastically impact how I would approach its integration within a larger, more critical system that I am designing.
|
| 39/2 |
2026/05/11 23:34 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:fs/jfs/jfs_imap.c IncludeLines:true Name:diSync]
Results: map[SourceCode: 202: /*
203: * diSync()
204: */
205: int diSync(struct inode *ipimap)
206: {
207: struct dinomap_disk *dinom_le;
208: struct inomap *imp = JFS_IP(ipimap)->i_imap;
209: struct metapage *mp;
210: int index;
211:
212: /*
213: * write imap global conrol page
214: */
215: /* read the on-disk inode map control structure */
216: mp = get_metapage(ipimap,
217: IMAPBLKNO << JFS_SBI(ipimap->i_sb)->l2nbperpage,
218: PSIZE, 0);
219: if (mp == NULL) {
220: jfs_err("diSync: get_metapage failed!");
221: return -EIO;
222: }
223:
224: /* copy the in-memory version to the on-disk version */
225: dinom_le = (struct dinomap_disk *) mp->data;
226: dinom_le->in_freeiag = cpu_to_le32(imp->im_freeiag);
227: dinom_le->in_nextiag = cpu_to_le32(imp->im_nextiag);
228: dinom_le->in_numinos = cpu_to_le32(atomic_read(&imp->im_numinos));
229: dinom_le->in_numfree = cpu_to_le32(atomic_read(&imp->im_numfree));
230: dinom_le->in_nbperiext = cpu_to_le32(imp->im_nbperiext);
231: dinom_le->in_l2nbperiext = cpu_to_le32(imp->im_l2nbperiext);
232: for (index = 0; index < MAXAG; index++) {
233: dinom_le->in_agctl[index].inofree =
234: cpu_to_le32(imp->im_agctl[index].inofree);
235: dinom_le->in_agctl[index].extfree =
236: cpu_to_le32(imp->im_agctl[index].extfree);
237: dinom_le->in_agctl[index].numinos =
238: cpu_to_le32(imp->im_agctl[index].numinos);
239: dinom_le->in_agctl[index].numfree =
240: cpu_to_le32(imp->im_agctl[index].numfree);
241: }
242:
243: /* write out the control structure */
244: write_metapage(mp);
245:
246: /*
247: * write out dirty pages of imap
248: */
249: filemap_write_and_wait(ipimap->i_mapping);
250:
251: diWriteSpecial(ipimap, 0);
252:
253: return (0);
254: }
SourceFile:fs/jfs/jfs_imap.c]
|
| 40/2 |
2026/05/11 23:34 |
llm |
debugger |
1m
Model:
Tokens:
input: 129158
output: 55
thoughts: 1217
Thoughts: **Analyzing JFS Journal Flushing and Transaction Completion**
Okay, so I'm looking at how JFS handles journal flushing, particularly in the context of unmounting the file system. It seems that `diSync` writes metapages directly, bypassing transactions altogether. This means `jfs_umount` doesn't initiate new transactions. The question then becomes: where are the transactions that *are* happening, and when are they ending, relative to `jfs_umount`?
The transactions in `TxAnchor.unlock_queue` were either started before `jfs_umount`, or possibly during `jfs_flush_journal` if there was a mechanism to do so. However, `jfs_flush_journal` simply *flushes* existing transactions to the journal, it doesn't create new ones. So all transactions must already be in the `TxAnchor.unlock_queue`, or actively being processed by `jfs_lazycommit`.
My initial thought was, "Why doesn't `jfs_flush_journal` wait for `TxAnchor.unlock_queue` to be empty?" Let's revisit the code in `jfs_flush_journal`:
```c
/*
* If there was recent activity, we may need to wait
* for the lazycommit thread to catch up
*/
if ((!list_empty(&log->cqueue)) || !list_empty(&log->synclist)) {
for (i = 0; i < 200; i++) { /* Too much? */
msleep(250);
write_special_inodes(log, filemap_fdatawrite);
if (list_empty(&log->cqueue) &&
list_empty(&log->synclist))
break;
}
}
```
The loop breaks when `cqueue` and `synclist` are empty. But this doesn't guarantee that `TxAnchor.unlock_queue` is empty and that there aren't still `tblk`s being processed. What if we add a check for `log->active == 0`? Wait, `log->active` represents the number of active transactions! That's exactly what we need. It's incremented by `txBegin` and decremented by `txEnd`. If we wait for `log->active == 0` in `jfs_flush_journal`, we can ensure all transactions have finished their `txEnd` process. This seems like the correct strategy.
Since `jfs_flush_journal` is called with `wait > 1` (it's called with `wait = 2` from `jfs_umount`), it signals to "flush until all transactions are complete, and wait." So, it *should* be waiting for `log->active == 0`.
The key is in `jfs_umount`'s call:
```c
if ((log = sbi->log))
/*
* Wait for outstanding transactions to be written to log:
*/
jfs_flush_journal(log, 2);
```
If `jfs_flush_journal` *doesn't* wait for `log->active == 0`, `jfs_lazycommit` could still be processing them.
So, let's just add a loop within `jfs_flush_journal`:
```c
if (wait > 1) {
/* wait for all transactions to complete */
while (log->active > 0) {
msleep(10); // or something
}
}
```
This addresses my concern, but I also have to consider that `TxAnchor.unlock_queue` is processed by `jfs_lazycommit`. If `jfs_lazycommit` is sleeping, who wakes it up? Ah, it's `txLazyUnlock`.
```c
void txLazyUnlock(struct tblock * tblk)
{
unsigned long flags;
LAZY_LOCK(flags);
list_add_tail(&tblk->cqueue, &TxAnchor.unlock_queue);
/*
* Don't wake up a commit thread if there is already one active.
* Some window where we can wake up one just as it goes to sleep,
* but it's ok.
*/
if (!jfs_commit_thread_waking) {
jfs_commit_thread_waking = 1;
wake_up(&jfs_commit_thread_wait);
}
LAZY_UNLOCK(flags);
}
```
So `jfs_lazycommit
|
| 41/2 |
2026/05/11 23:35 |
tool |
codesearch-find-references |
0m
Args: map[ContextFile:fs/jfs/jfs_logmgr.c IncludeSnippetLines:0 Name:jfs_flush_journal SourceTreePrefix:]
Results: map[References:[map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:jfs_fsync SourceFile:fs/jfs/file.c SourceLine:33] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:jfs_sync_fs SourceFile:fs/jfs/super.c SourceLine:649] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:jfs_umount SourceFile:fs/jfs/jfs_umount.c SourceLine:59] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:jfs_umount_rw SourceFile:fs/jfs/jfs_umount.c SourceLine:144] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:jfs_write_inode SourceFile:fs/jfs/inode.c SourceLine:134] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:lmLogShutdown SourceFile:fs/jfs/jfs_logmgr.c SourceLine:1640] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:lmLogSync SourceFile:fs/jfs/jfs_logmgr.c SourceLine:1022] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:metapage_write_folio SourceFile:fs/jfs/jfs_metapage.c SourceLine:463] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:txQuiesce SourceFile:fs/jfs/jfs_txnmgr.c SourceLine:2861]] TruncatedOutput:false]
|
| 42/2 |
2026/05/11 23:35 |
llm |
debugger |
0m
Model:
Tokens:
input: 131953
output: 46
thoughts: 10
Thoughts: Okay, here's my attempt at summarizing the thought process, tailored for an expert audience, and written in the first person:
**Analyzing `txQuiesce`**
Alright, let's dive into this `txQuiesce` function. My initial thought process focuses on the *why* and the *how*. I immediately start to consider the context; where does this fit within the larger transaction management framework? Is this a complete solution or a part of a distributed system solution? Is it a single-phase or multi-phase implementation? I'm already anticipating the need to differentiate this function from other transaction termination strategies.
I'm mentally running through the typical states of a transaction β active, prepared, committed, aborted, etc. I'm wondering which of these states are relevant to this function and the conditions under which the `txQuiesce` is applied. Are we dealing with optimistic or pessimistic concurrency control? The implications for lock management, data consistency, and potential deadlocks are immediately at the forefront of my mind.
Next, I'll be drilling down into the implementation details. I'm expecting to look at how exactly the "quiesce" is achieved. Is it a gentle shutdown? Does it ensure that no new transactions are initiated? Does it allow in-flight transactions to complete? Does it handle rollbacks or restarts for failed transactions? Is there some type of timeout involved? What's the error handling look like? I'm going to want to check the logging too.
Ultimately, my goal here is to grasp the nuance of `txQuiesce`, so I can see what its impacts are within my application domain. I want to see if this is an efficient way to achieve a predictable end-state for my transactions.
|
| 43/2 |
2026/05/11 23:35 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:fs/jfs/jfs_txnmgr.c IncludeLines:true Name:txQuiesce]
Results: map[SourceCode:2803: /*
2804: * txQuiesce
2805: *
2806: * Block all new transactions and push anonymous transactions to
2807: * completion
2808: *
2809: * This does almost the same thing as jfs_sync below. We don't
2810: * worry about deadlocking when jfs_tlocks_low is set, since we would
2811: * expect jfs_sync to get us out of that jam.
2812: */
2813: void txQuiesce(struct super_block *sb)
2814: {
2815: struct inode *ip;
2816: struct jfs_inode_info *jfs_ip;
2817: struct jfs_log *log = JFS_SBI(sb)->log;
2818: tid_t tid;
2819:
2820: set_bit(log_QUIESCE, &log->flag);
2821:
2822: TXN_LOCK();
2823: restart:
2824: while (!list_empty(&TxAnchor.anon_list)) {
2825: jfs_ip = list_entry(TxAnchor.anon_list.next,
2826: struct jfs_inode_info,
2827: anon_inode_list);
2828: ip = &jfs_ip->vfs_inode;
2829:
2830: /*
2831: * inode will be removed from anonymous list
2832: * when it is committed
2833: */
2834: TXN_UNLOCK();
2835: tid = txBegin(ip->i_sb, COMMIT_INODE | COMMIT_FORCE);
2836: mutex_lock(&jfs_ip->commit_mutex);
2837: txCommit(tid, 1, &ip, 0);
2838: txEnd(tid);
2839: mutex_unlock(&jfs_ip->commit_mutex);
2840: /*
2841: * Just to be safe. I don't know how
2842: * long we can run without blocking
2843: */
2844: cond_resched();
2845: TXN_LOCK();
2846: }
2847:
2848: /*
2849: * If jfs_sync is running in parallel, there could be some inodes
2850: * on anon_list2. Let's check.
2851: */
2852: if (!list_empty(&TxAnchor.anon_list2)) {
2853: list_splice_init(&TxAnchor.anon_list2, &TxAnchor.anon_list);
2854: goto restart;
2855: }
2856: TXN_UNLOCK();
2857:
2858: /*
2859: * We may need to kick off the group commit
2860: */
2861: jfs_flush_journal(log, 0);
2862: }
SourceFile:fs/jfs/jfs_txnmgr.c]
|
| 44/2 |
2026/05/11 23:35 |
llm |
debugger |
0m
Model:
Tokens:
input: 133267
output: 44
thoughts: 549
Thoughts: **Analyzing Journal Flushing During Unmount**
Okay, so I'm looking at the `jfs_umount` process and how it handles journal flushing. It looks like `jfs_flush_journal(log, 2)` is called not once, but twice. Once directly and again from `lmLogShutdown`. This seems a little redundant, but the real concern is that neither of these calls appears to explicitly wait for the `TxAnchor.unlock_queue` to be empty. This is something I need to fully understand, because in a transactional system, ensuring all transactions are complete before unmounting is *critical*.
Now, the `jfs_flush_journal` function itself is supposed to ensure data is written. Iβm thinking, if it's responsible for waiting for transactions, why doesn't it even check if the journal is actually active? Let's dive deeper and examine its code. Ah, here's the relevant loop:
```c
/*
* If there was recent activity, we may need to wait
* for the lazycommit thread to catch up
*/
if ((!list_empty(&log->cqueue)) || !list_empty(&log->synclist)) {
for (i = 0; i < 200; i++) { /* Too much? */
msleep(250);
write_special_inodes(log, filemap_fdatawrite);
if (list_empty(&log->cqueue) &&
list_empty(&log->synclist))
break;
}
}
assert(list_empty(&log->cqueue));
```
This *almost* looks right, but it's only checking `log->cqueue` and `log->synclist`. What if there are still active transactions? My immediate thought is, if we add `|| atomic_read(&log->active)` into the conditional, wouldn't that solve the problem?
However, hold on a second. `log->active` is declared as an `int`, not an `atomic_t`. Right, that's not going to work. Let's think this through. Since `log->active` is an `int`, it's not going to be atomic. It's protected by the `TXN_LOCK()`. So, `log->active` is incremented and decremented within `TXN_LOCK()` in the `txBegin` and `txEnd` functions. So, really, the check is for `TXN_LOCK()`. I'm going to have to verify how those functions interact.
|
| 45/2 |
2026/05/11 23:35 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:fs/jfs/jfs_txnmgr.c IncludeLines:true Name:txBegin]
Results: map[SourceCode: 337: /*
338: * NAME: txBegin()
339: *
340: * FUNCTION: start a transaction.
341: *
342: * PARAMETER: sb - superblock
343: * flag - force for nested tx;
344: *
345: * RETURN: tid - transaction id
346: *
347: * note: flag force allows to start tx for nested tx
348: * to prevent deadlock on logsync barrier;
349: */
350: tid_t txBegin(struct super_block *sb, int flag)
351: {
352: tid_t t;
353: struct tblock *tblk;
354: struct jfs_log *log;
355:
356: jfs_info("txBegin: flag = 0x%x", flag);
357: log = JFS_SBI(sb)->log;
358:
359: if (!log) {
360: jfs_error(sb, "read-only filesystem\n");
361: return 0;
362: }
363:
364: TXN_LOCK();
365:
366: INCREMENT(TxStat.txBegin);
367:
368: retry:
369: if (!(flag & COMMIT_FORCE)) {
370: /*
371: * synchronize with logsync barrier
372: */
373: if (test_bit(log_SYNCBARRIER, &log->flag) ||
374: test_bit(log_QUIESCE, &log->flag)) {
375: INCREMENT(TxStat.txBegin_barrier);
376: TXN_SLEEP(&log->syncwait);
377: goto retry;
378: }
379: }
380: if (flag == 0) {
381: /*
382: * Don't begin transaction if we're getting starved for tlocks
383: * unless COMMIT_FORCE or COMMIT_INODE (which may ultimately
384: * free tlocks)
385: */
386: if (TxAnchor.tlocksInUse > TxLockVHWM) {
387: INCREMENT(TxStat.txBegin_lockslow);
388: TXN_SLEEP(&TxAnchor.lowlockwait);
389: goto retry;
390: }
391: }
392:
393: /*
394: * allocate transaction id/block
395: */
396: if ((t = TxAnchor.freetid) == 0) {
397: jfs_info("txBegin: waiting for free tid");
398: INCREMENT(TxStat.txBegin_freetid);
399: TXN_SLEEP(&TxAnchor.freewait);
400: goto retry;
401: }
402:
403: tblk = tid_to_tblock(t);
404:
405: if ((tblk->next == 0) && !(flag & COMMIT_FORCE)) {
406: /* Don't let a non-forced transaction take the last tblk */
407: jfs_info("txBegin: waiting for free tid");
408: INCREMENT(TxStat.txBegin_freetid);
409: TXN_SLEEP(&TxAnchor.freewait);
410: goto retry;
411: }
412:
413: TxAnchor.freetid = tblk->next;
414:
415: /*
416: * initialize transaction
417: */
418:
419: /*
420: * We can't zero the whole thing or we screw up another thread being
421: * awakened after sleeping on tblk->waitor
422: *
423: * memset(tblk, 0, sizeof(struct tblock));
424: */
425: tblk->next = tblk->last = tblk->xflag = tblk->flag = tblk->lsn = 0;
426:
427: tblk->sb = sb;
428: ++log->logtid;
429: tblk->logtid = log->logtid;
430:
431: ++log->active;
432:
433: HIGHWATERMARK(stattx.maxtid, t); /* statistics */
434: INCREMENT(stattx.ntid); /* statistics */
435:
436: TXN_UNLOCK();
437:
438: jfs_info("txBegin: returning tid = %d", t);
439:
440: return t;
441: }
SourceFile:fs/jfs/jfs_txnmgr.c]
|
| 46/2 |
2026/05/11 23:35 |
llm |
debugger |
0m
Model:
Tokens:
input: 135870
output: 52
thoughts: 420
Thoughts: **Analyzing the Journal Flushing Mechanism**
Okay, so I'm looking at this `jfs_flush_journal` function, and it seems to involve some waiting based on the `log->active` flag. I see that `log->active` is protected by `TXN_LOCK()`, which is good, that's crucial for concurrency. The code checks for `log->active == 0` and then proceeds.
Now, I'm thinking about the implications of the wait. If we're waiting for activity to cease, and `jfs_flush_journal` is called with `wait = 2`, as it is from both `jfs_umount` and `lmLogShutdown`, what's the guarantee that `log->active` *ever* becomes zero? It's a valid concern.
I realize that it's possible that `log->active` could perpetually remain non-zero if other superblocks are also using the *same* log. If other superblocks are starting new transactions on this log, it might seem correct that this `jfs_flush_journal` waits for all activity on *that* log to finish.
However, I'm now realizing a potential problem if `log` is shared. The whole point of flushing the journal, such as in the umount case, is that it is supposed to flush the journal for *this* superblock. If `log` is shared, shouldn't `jfs_umount` for *one* superblock not have to wait for *all* other superblocks to become idle? That seems like a design flaw to me.
I need to confirm if JFS even supports shared logs. This seems like a critical question, and I need to find the answer.
|
| 47/2 |
2026/05/11 23:35 |
tool |
codesearch-find-references |
0m
Error: requested entity does not exist
Args: map[ContextFile:fs/jfs/jfs_logmgr.c IncludeSnippetLines:0 Name:sb_list SourceTreePrefix:]
Results: map[References:<nil> TruncatedOutput:false]
|
| 48/2 |
2026/05/11 23:35 |
llm |
debugger |
0m
Model:
Tokens:
input: 136731
output: 17
thoughts: 28
Thoughts: Here's my thought process, as if I were considering this myself:
**Tracing the Data Structure Connection**
Okay, so I'm looking at `sb_list`. Right, that's a field within the `struct jfs_log` structure. That tells me a lot already, but I need to see *how* it's used. Since I'm familiar with this codebase, I should start by searching for `sb_list` directly. That should quickly illuminate its purpose and how it links to other elements within the JFS file system. I can start by looking for usages of the variable, or perhaps the structure that it's embedded within. That should give me the context I need to understand what this list is managing within the logging system.
|
| 49/2 |
2026/05/11 23:36 |
tool |
grepper |
0m
Args:
Results: map[Output:block/bdev.c=524=long nr_blockdev_pages(void)
--
block/bdev.c-529- spin_lock(&blockdev_superblock->s_inode_list_lock);
block/bdev.c:530: list_for_each_entry(inode, &blockdev_superblock->s_inodes, i_sb_list)
block/bdev.c-531- ret += inode->i_mapping->nrpages;
--
block/bdev.c=1266=void sync_bdevs(bool wait)
--
block/bdev.c-1270- spin_lock(&blockdev_superblock->s_inode_list_lock);
block/bdev.c:1271: list_for_each_entry(inode, &blockdev_superblock->s_inodes, i_sb_list) {
block/bdev.c-1272- struct address_space *mapping = inode->i_mapping;
--
fs/drop_caches.c=19=static void drop_pagecache_sb(struct super_block *sb, void *unused)
--
fs/drop_caches.c-23- spin_lock(&sb->s_inode_list_lock);
fs/drop_caches.c:24: list_for_each_entry(inode, &sb->s_inodes, i_sb_list) {
fs/drop_caches.c-25- spin_lock(&inode->i_lock);
--
fs/erofs/zutil.c=23=atomic_long_t erofs_global_shrink_cnt; /* for all mounted instances */
fs/erofs/zutil.c-24-
fs/erofs/zutil.c:25:/* protects `erofs_sb_list_lock` and the mounted `erofs_sb_list` */
fs/erofs/zutil.c:26:static DEFINE_SPINLOCK(erofs_sb_list_lock);
fs/erofs/zutil.c:27:static LIST_HEAD(erofs_sb_list);
fs/erofs/zutil.c-28-static unsigned int shrinker_run_no;
--
fs/erofs/zutil.c=216=void erofs_shrinker_register(struct super_block *sb)
--
fs/erofs/zutil.c-221-
fs/erofs/zutil.c:222: spin_lock(&erofs_sb_list_lock);
fs/erofs/zutil.c:223: list_add(&sbi->list, &erofs_sb_list);
fs/erofs/zutil.c:224: spin_unlock(&erofs_sb_list_lock);
fs/erofs/zutil.c-225-}
--
fs/erofs/zutil.c=227=void erofs_shrinker_unregister(struct super_block *sb)
--
fs/erofs/zutil.c-235- }
fs/erofs/zutil.c:236: spin_lock(&erofs_sb_list_lock);
fs/erofs/zutil.c-237- list_del(&sbi->list);
fs/erofs/zutil.c:238: spin_unlock(&erofs_sb_list_lock);
fs/erofs/zutil.c-239- mutex_unlock(&sbi->umount_mutex);
--
fs/erofs/zutil.c=248=static unsigned long erofs_shrink_scan(struct shrinker *shrink,
--
fs/erofs/zutil.c-257-
fs/erofs/zutil.c:258: spin_lock(&erofs_sb_list_lock);
fs/erofs/zutil.c-259- do {
--
fs/erofs/zutil.c-263- /* Iterate over all mounted superblocks and try to shrink them */
fs/erofs/zutil.c:264: p = erofs_sb_list.next;
fs/erofs/zutil.c:265: while (p != &erofs_sb_list) {
fs/erofs/zutil.c-266- sbi = list_entry(p, struct erofs_sb_info, list);
--
fs/erofs/zutil.c-279-
fs/erofs/zutil.c:280: spin_unlock(&erofs_sb_list_lock);
fs/erofs/zutil.c-281- sbi->shrinker_run_no = run_no;
fs/erofs/zutil.c-282- freed += z_erofs_shrink_scan(sbi, nr - freed);
fs/erofs/zutil.c:283: spin_lock(&erofs_sb_list_lock);
fs/erofs/zutil.c-284- /* Get the next list element before we move this one */
--
fs/erofs/zutil.c-290- */
fs/erofs/zutil.c:291: list_move_tail(&sbi->list, &erofs_sb_list);
fs/erofs/zutil.c-292- mutex_unlock(&sbi->umount_mutex);
--
fs/erofs/zutil.c-296- }
fs/erofs/zutil.c:297: spin_unlock(&erofs_sb_list_lock);
fs/erofs/zutil.c-298- return freed;
--
fs/gfs2/ops_fstype.c=1741=static void gfs2_evict_inodes(struct super_block *sb)
--
fs/gfs2/ops_fstype.c-1748- spin_lock(&sb->s_inode_list_lock);
fs/gfs2/ops_fstype.c:1749: list_for_each_entry(inode, &sb->s_inodes, i_sb_list) {
fs/gfs2/ops_fstype.c-1750- spin_lock(&inode->i_lock);
--
fs/inode.c-39- * inode->i_sb->s_inode_list_lock protects:
fs/inode.c:40: * inode->i_sb->s_inodes, inode->i_sb_list
fs/inode.c-41- * bdi->wb.list_lock protects:
--
fs/inode.c=500=void inode_init_once(struct inode *inode)
--
fs/inode.c-507- INIT_LIST_HEAD(&inode->i_lru);
fs/inode.c:508: INIT_LIST_HEAD(&inode->i_sb_list);
fs/inode.c-509- __address_space_init_once(&inode->i_data);
--
fs/inode.c=620=static void inode_wait_for_lru_isolating(struct inode *inode)
--
fs/inode.c-646-/**
fs/inode.c:647: * inode_sb_list_add - add inode to the superblock list of inodes
fs/inode.c-648- * @inode: inode to add
fs/inode.c-649- */
fs/inode.c:650:void inode_sb_list_add(struct inode *inode)
fs/inode.c-651-{
--
fs/inode.c-654- spin_lock(&sb->s_inode_list_lock);
fs/inode.c:655: list_add(&inode->i_sb_list, &sb->s_inodes);
fs/inode.c-656- spin_unlock(&sb->s_inode_list_lock);
fs/inode.c-657-}
fs/inode.c:658:EXPORT_SYMBOL_GPL(inode_sb_list_add);
fs/inode.c-659-
fs/inode.c:660:static inline void inode_sb_list_del(struct inode *inode)
fs/inode.c-661-{
--
fs/inode.c-663-
fs/inode.c:664: if (!list_empty(&inode->i_sb_list)) {
fs/inode.c-665- spin_lock(&sb->s_inode_list_lock);
fs/inode.c:666: list_del_init(&inode->i_sb_list);
fs/inode.c-667- spin_unlock(&sb->s_inode_list_lock);
--
fs/inode.c=818=static void evict(struct inode *inode)
--
fs/inode.c-825- inode_io_list_del(inode);
fs/inode.c:826: inode_sb_list_del(inode);
fs/inode.c-827-
--
fs/inode.c=897=void evict_inodes(struct super_block *sb)
--
fs/inode.c-903- spin_lock(&sb->s_inode_list_lock);
fs/inode.c:904: list_for_each_entry(inode, &sb->s_inodes, i_sb_list) {
fs/inode.c-905- if (icount_read(inode))
--
fs/inode.c=1175=struct inode *new_inode(struct super_block *sb)
--
fs/inode.c-1180- if (inode)
fs/inode.c:1181: inode_sb_list_add(inode);
fs/inode.c-1182- return inode;
--
fs/inode.c=1298=struct inode *inode_insert5(struct inode *inode, u64 hashval,
--
fs/inode.c-1345- * Add inode to the sb list if it's not already. It has I_NEW at this
fs/inode.c:1346: * point, so it should be safe to test i_sb_list locklessly.
fs/inode.c-1347- */
fs/inode.c:1348: if (list_empty(&inode->i_sb_list))
fs/inode.c:1349: inode_sb_list_add(inode);
fs/inode.c-1350-
--
fs/inode.c=1452=struct inode *iget_locked(struct super_block *sb, u64 ino)
--
fs/inode.c-1487- spin_unlock(&inode_hash_lock);
fs/inode.c:1488: inode_sb_list_add(inode);
fs/inode.c-1489-
--
fs/jfs/jfs_logmgr.c=195=static void write_special_inodes(struct jfs_log *log,
--
fs/jfs/jfs_logmgr.c-199-
fs/jfs/jfs_logmgr.c:200: list_for_each_entry(sbi, &log->sb_list, log_list) {
fs/jfs/jfs_logmgr.c-201- /* These pointers can be NULL before list_del during umount */
--
fs/jfs/jfs_logmgr.c=1056=int lmLogOpen(struct super_block *sb)
--
fs/jfs/jfs_logmgr.c-1091- }
fs/jfs/jfs_logmgr.c:1092: INIT_LIST_HEAD(&log->sb_list);
fs/jfs/jfs_logmgr.c-1093- init_waitqueue_head(&log->syncwait);
--
fs/jfs/jfs_logmgr.c-1126- LOG_LOCK(log);
fs/jfs/jfs_logmgr.c:1127: list_add(&sbi->log_list, &log->sb_list);
fs/jfs/jfs_logmgr.c-1128- sbi->log = log;
--
fs/jfs/jfs_logmgr.c=1152=static int open_inline_log(struct super_block *sb)
--
fs/jfs/jfs_logmgr.c-1158- return -ENOMEM;
fs/jfs/jfs_logmgr.c:1159: INIT_LIST_HEAD(&log->sb_list);
fs/jfs/jfs_logmgr.c-1160- init_waitqueue_head(&log->syncwait);
--
fs/jfs/jfs_logmgr.c-1178-
fs/jfs/jfs_logmgr.c:1179: list_add(&JFS_SBI(sb)->log_list, &log->sb_list);
fs/jfs/jfs_logmgr.c-1180- JFS_SBI(sb)->log = log;
--
fs/jfs/jfs_logmgr.c=1185=static int open_dummy_log(struct super_block *sb)
--
fs/jfs/jfs_logmgr.c-1195- }
fs/jfs/jfs_logmgr.c:1196: INIT_LIST_HEAD(&dummy_log->sb_list);
fs/jfs/jfs_logmgr.c-1197- init_waitqueue_head(&dummy_log->syncwait);
--
fs/jfs/jfs_logmgr.c-1210- LOG_LOCK(dummy_log);
fs/jfs/jfs_logmgr.c:1211: list_add(&JFS_SBI(sb)->log_list, &dummy_log->sb_list);
fs/jfs/jfs_logmgr.c-1212- JFS_SBI(sb)->log = dummy_log;
--
fs/jfs/jfs_logmgr.c=1432=int lmLogClose(struct super_block *sb)
--
fs/jfs/jfs_logmgr.c-1464-
fs/jfs/jfs_logmgr.c:1465: if (!list_empty(&log->sb_list))
fs/jfs/jfs_logmgr.c-1466- goto out;
--
fs/jfs/jfs_logmgr.c=2349=int lmLogFormat(struct jfs_log *log, s64 logAddress, int logSize)
--
fs/jfs/jfs_logmgr.c-2362-
fs/jfs/jfs_logmgr.c:2363: sbi = list_entry(log->sb_list.next, struct jfs_sb_info, log_list);
fs/jfs/jfs_logmgr.c-2364-
--
fs/jfs/jfs_logmgr.h=353=struct jfs_log {
fs/jfs/jfs_logmgr.h-354-
fs/jfs/jfs_logmgr.h:355: struct list_head sb_list;/* This is used to sync metadata
fs/jfs/jfs_logmgr.h-356- * before writing syncpt.
--
fs/jfs/jfs_umount.c=38=int jfs_umount(struct super_block *sb)
--
fs/jfs/jfs_umount.c-62- * Hold log lock so write_special_inodes (lmLogSync) cannot see
fs/jfs/jfs_umount.c:63: * this sbi with a NULL inode pointer while iterating log->sb_list.
fs/jfs/jfs_umount.c-64- */
--
fs/nilfs2/segbuf.c=34=struct nilfs_segment_buffer *nilfs_segbuf_new(struct super_block *sb)
--
fs/nilfs2/segbuf.c-42- segbuf->sb_super = sb;
fs/nilfs2/segbuf.c:43: INIT_LIST_HEAD(&segbuf->sb_list);
fs/nilfs2/segbuf.c-44- INIT_LIST_HEAD(&segbuf->sb_segsum_buffers);
--
fs/nilfs2/segbuf.c=270=void nilfs_clear_logs(struct list_head *logs)
--
fs/nilfs2/segbuf.c-273-
fs/nilfs2/segbuf.c:274: list_for_each_entry(segbuf, logs, sb_list)
fs/nilfs2/segbuf.c-275- nilfs_segbuf_clear(segbuf);
--
fs/nilfs2/segbuf.c=278=void nilfs_truncate_logs(struct list_head *logs,
--
fs/nilfs2/segbuf.c-282-
fs/nilfs2/segbuf.c:283: segbuf = list_prepare_entry(last, logs, sb_list);
fs/nilfs2/segbuf.c:284: list_for_each_entry_safe_continue(segbuf, n, logs, sb_list) {
fs/nilfs2/segbuf.c:285: list_del_init(&segbuf->sb_list);
fs/nilfs2/segbuf.c-286- nilfs_segbuf_clear(segbuf);
--
fs/nilfs2/segbuf.c=291=int nilfs_write_logs(struct list_head *logs, struct the_nilfs *nilfs)
--
fs/nilfs2/segbuf.c-295-
fs/nilfs2/segbuf.c:296: list_for_each_entry(segbuf, logs, sb_list) {
fs/nilfs2/segbuf.c-297- ret = nilfs_segbuf_write(segbuf, nilfs);
--
fs/nilfs2/segbuf.c=304=int nilfs_wait_on_logs(struct list_head *logs)
--
fs/nilfs2/segbuf.c-308-
fs/nilfs2/segbuf.c:309: list_for_each_entry(segbuf, logs, sb_list) {
fs/nilfs2/segbuf.c-310- err = nilfs_segbuf_wait(segbuf);
--
fs/nilfs2/segbuf.c=322=void nilfs_add_checksums_on_logs(struct list_head *logs, u32 seed)
--
fs/nilfs2/segbuf.c-325-
fs/nilfs2/segbuf.c:326: list_for_each_entry(segbuf, logs, sb_list) {
fs/nilfs2/segbuf.c-327- if (segbuf->sb_super_root)
--
fs/nilfs2/segbuf.h=31=struct nilfs_segsum_info {
--
fs/nilfs2/segbuf.h-46- * @sb_super: back pointer to a superblock struct
fs/nilfs2/segbuf.h:47: * @sb_list: List head to chain this structure
fs/nilfs2/segbuf.h-48- * @sb_sum: On-memory segment summary
--
fs/nilfs2/segbuf.h=62=struct nilfs_segment_buffer {
fs/nilfs2/segbuf.h-63- struct super_block *sb_super;
fs/nilfs2/segbuf.h:64: struct list_head sb_list;
fs/nilfs2/segbuf.h-65-
--
fs/nilfs2/segbuf.h-85-#define NILFS_LIST_SEGBUF(head) \
fs/nilfs2/segbuf.h:86: list_entry((head), struct nilfs_segment_buffer, sb_list)
fs/nilfs2/segbuf.h:87:#define NILFS_NEXT_SEGBUF(segbuf) NILFS_LIST_SEGBUF((segbuf)->sb_list.next)
fs/nilfs2/segbuf.h:88:#define NILFS_PREV_SEGBUF(segbuf) NILFS_LIST_SEGBUF((segbuf)->sb_list.prev)
fs/nilfs2/segbuf.h-89-#define NILFS_LAST_SEGBUF(head) NILFS_LIST_SEGBUF((head)->prev)
fs/nilfs2/segbuf.h-90-#define NILFS_FIRST_SEGBUF(head) NILFS_LIST_SEGBUF((head)->next)
fs/nilfs2/segbuf.h:91:#define NILFS_SEGBUF_IS_LAST(segbuf, head) ((segbuf)->sb_list.next == (head))
fs/nilfs2/segbuf.h-92-
--
fs/nilfs2/segment.c=1326=static int nilfs_segctor_begin_construction(struct nilfs_sc_info *sci,
--
fs/nilfs2/segment.c-1376- BUG_ON(!list_empty(&sci->sc_segbufs));
fs/nilfs2/segment.c:1377: list_add_tail(&segbuf->sb_list, &sci->sc_segbufs);
fs/nilfs2/segment.c-1378- sci->sc_segbuf_nblocks = segbuf->sb_rest_blocks;
--
fs/nilfs2/segment.c=1386=static int nilfs_segctor_extend_segments(struct nilfs_sc_info *sci,
--
fs/nilfs2/segment.c-1424-
fs/nilfs2/segment.c:1425: list_add_tail(&segbuf->sb_list, &list);
fs/nilfs2/segment.c-1426- prev = segbuf;
--
fs/nilfs2/segment.c-1433- failed:
fs/nilfs2/segment.c:1434: list_for_each_entry(segbuf, &list, sb_list) {
fs/nilfs2/segment.c-1435- ret = nilfs_sufile_free(sufile, segbuf->sb_nextnum);
--
fs/nilfs2/segment.c=1442=static void nilfs_free_incomplete_logs(struct list_head *logs,
--
fs/nilfs2/segment.c-1467- prev = segbuf;
fs/nilfs2/segment.c:1468: list_for_each_entry_continue(segbuf, logs, sb_list) {
fs/nilfs2/segment.c-1469- if (prev->sb_nextnum != segbuf->sb_nextnum) {
--
fs/nilfs2/segment.c=1481=static void nilfs_segctor_update_segusage(struct nilfs_sc_info *sci,
--
fs/nilfs2/segment.c-1487-
fs/nilfs2/segment.c:1488: list_for_each_entry(segbuf, &sci->sc_segbufs, sb_list) {
fs/nilfs2/segment.c-1489- live_blocks = segbuf->sb_sum.nblocks +
--
fs/nilfs2/segment.c=1498=static void nilfs_cancel_segusage(struct list_head *logs, struct inode *sufile)
--
fs/nilfs2/segment.c-1508-
fs/nilfs2/segment.c:1509: list_for_each_entry_continue(segbuf, logs, sb_list) {
fs/nilfs2/segment.c-1510- ret = nilfs_sufile_set_segment_usage(sufile, segbuf->sb_segnum,
--
fs/nilfs2/segment.c=1516=static void nilfs_segctor_truncate_segments(struct nilfs_sc_info *sci,
--
fs/nilfs2/segment.c-1522-
fs/nilfs2/segment.c:1523: list_for_each_entry_continue(segbuf, &sci->sc_segbufs, sb_list) {
fs/nilfs2/segment.c-1524- sci->sc_segbuf_nblocks -= segbuf->sb_rest_blocks;
--
fs/nilfs2/segment.c=1668=static int nilfs_segctor_assign(struct nilfs_sc_info *sci, int mode)
--
fs/nilfs2/segment.c-1672-
fs/nilfs2/segment.c:1673: list_for_each_entry(segbuf, &sci->sc_segbufs, sb_list) {
fs/nilfs2/segment.c-1674- err = nilfs_segctor_update_payload_blocknr(sci, segbuf, mode);
--
fs/nilfs2/segment.c=1709=static void nilfs_prepare_write_logs(struct list_head *logs, u32 seed)
--
fs/nilfs2/segment.c-1715- /* Prepare to write payload blocks */
fs/nilfs2/segment.c:1716: list_for_each_entry(segbuf, logs, sb_list) {
fs/nilfs2/segment.c-1717- list_for_each_entry(bh, &segbuf->sb_payload_buffers,
--
fs/nilfs2/segment.c-1732- /* Prepare to write segment summary blocks */
fs/nilfs2/segment.c:1733: list_for_each_entry(segbuf, logs, sb_list) {
fs/nilfs2/segment.c-1734- list_for_each_entry(bh, &segbuf->sb_segsum_buffers,
--
fs/nilfs2/segment.c=1816=static void nilfs_abort_logs(struct list_head *logs, int err)
--
fs/nilfs2/segment.c-1824-
fs/nilfs2/segment.c:1825: list_for_each_entry(segbuf, logs, sb_list) {
fs/nilfs2/segment.c-1826- list_for_each_entry(bh, &segbuf->sb_segsum_buffers,
--
fs/nilfs2/segment.c=1898=static void nilfs_segctor_complete_write(struct nilfs_sc_info *sci)
--
fs/nilfs2/segment.c-1904-
fs/nilfs2/segment.c:1905: list_for_each_entry(segbuf, &sci->sc_write_logs, sb_list) {
fs/nilfs2/segment.c-1906- struct buffer_head *bh;
--
fs/quota/dquot.c=1047=static int add_dquot_ref(struct super_block *sb, int type)
--
fs/quota/dquot.c-1055- spin_lock(&sb->s_inode_list_lock);
fs/quota/dquot.c:1056: list_for_each_entry(inode, &sb->s_inodes, i_sb_list) {
fs/quota/dquot.c-1057- spin_lock(&inode->i_lock);
--
fs/quota/dquot.c=1104=static void remove_dquot_ref(struct super_block *sb, int type)
--
fs/quota/dquot.c-1111- spin_lock(&sb->s_inode_list_lock);
fs/quota/dquot.c:1112: list_for_each_entry(inode, &sb->s_inodes, i_sb_list) {
fs/quota/dquot.c-1113- /*
--
fs/smb/client/cifsglob.h=1193=struct cifs_tcon {
--
fs/smb/client/cifsglob.h-1288- struct cached_fids *cfids;
fs/smb/client/cifsglob.h:1289: struct list_head cifs_sb_list;
fs/smb/client/cifsglob.h:1290: spinlock_t sb_list_lock;
fs/smb/client/cifsglob.h-1291-#ifdef CONFIG_CIFS_DFS_UPCALL
--
fs/smb/client/cifsglob.h=1943=require use of the stronger protocol */
--
fs/smb/client/cifsglob.h-2014- * cifs_tcon->fscache_lock cifs_tcon->fscache tconInfoAlloc
fs/smb/client/cifsglob.h:2015: * cifs_tcon->sb_list_lock cifs_tcon->cifs_sb_list tconInfoAlloc
fs/smb/client/cifsglob.h-2016- * GlobalMid_Lock GlobalMaxActiveXid init_cifs
--
fs/smb/client/connect.c=3681=static int mount_setup_tlink(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses,
--
fs/smb/client/connect.c-3701-
fs/smb/client/connect.c:3702: spin_lock(&tcon->sb_list_lock);
fs/smb/client/connect.c:3703: list_add(&cifs_sb->tcon_sb_link, &tcon->cifs_sb_list);
fs/smb/client/connect.c:3704: spin_unlock(&tcon->sb_list_lock);
fs/smb/client/connect.c-3705-
--
fs/smb/client/connect.c=3968=cifs_umount(struct cifs_sb_info *cifs_sb)
--
fs/smb/client/connect.c-3979- if (tcon) {
fs/smb/client/connect.c:3980: spin_lock(&tcon->sb_list_lock);
fs/smb/client/connect.c-3981- list_del_init(&cifs_sb->tcon_sb_link);
fs/smb/client/connect.c:3982: spin_unlock(&tcon->sb_list_lock);
fs/smb/client/connect.c-3983- }
--
fs/smb/client/misc.c=121=tcon_info_alloc(bool dir_leases_enabled, enum smb3_tcon_ref_trace trace)
--
fs/smb/client/misc.c-145- INIT_LIST_HEAD(&ret_buf->tcon_list);
fs/smb/client/misc.c:146: INIT_LIST_HEAD(&ret_buf->cifs_sb_list);
fs/smb/client/misc.c-147- spin_lock_init(&ret_buf->open_file_lock);
fs/smb/client/misc.c-148- spin_lock_init(&ret_buf->stat_lock);
fs/smb/client/misc.c:149: spin_lock_init(&ret_buf->sb_list_lock);
fs/smb/client/misc.c-150- atomic_set(&ret_buf->num_local_opens, 0);
--
fs/smb/client/smb2pdu.c=4190=static void cifs_renegotiate_iosize(struct TCP_Server_Info *server,
--
fs/smb/client/smb2pdu.c-4197-
fs/smb/client/smb2pdu.c:4198: spin_lock(&tcon->sb_list_lock);
fs/smb/client/smb2pdu.c:4199: list_for_each_entry(cifs_sb, &tcon->cifs_sb_list, tcon_sb_link)
fs/smb/client/smb2pdu.c-4200- cifs_negotiate_iosize(server, cifs_sb->ctx, tcon);
fs/smb/client/smb2pdu.c:4201: spin_unlock(&tcon->sb_list_lock);
fs/smb/client/smb2pdu.c-4202-}
--
fs/super.c=618=void generic_shutdown_super(struct super_block *sb)
--
fs/super.c-664- spin_lock(&sb->s_inode_list_lock);
fs/super.c:665: list_for_each_entry(inode, &sb->s_inodes, i_sb_list) {
fs/super.c-666- inode->i_op = VFS_PTR_POISON;
--
fs/xfs/xfs_iops.c=1419=xfs_setup_inode(
--
fs/xfs/xfs_iops.c-1428-
fs/xfs/xfs_iops.c:1429: inode_sb_list_add(inode);
fs/xfs/xfs_iops.c-1430- /* make the inode look hashed for the writeback code */
--
include/linux/fs.h=767=struct inode {
--
include/linux/fs.h-836- struct list_head i_lru; /* inode LRU list */
include/linux/fs.h:837: struct list_head i_sb_list;
include/linux/fs.h-838- struct list_head i_wb_list; /* backing dev writeback list */
--
include/linux/fs.h=3037=static inline void remove_inode_hash(struct inode *inode)
--
include/linux/fs.h-3042-
include/linux/fs.h:3043:void inode_sb_list_add(struct inode *inode);
include/linux/fs.h-3044-void inode_lru_list_add(struct inode *inode);
--
include/linux/perf_event.h=765=struct perf_event {
--
include/linux/perf_event.h-923-#endif
include/linux/perf_event.h:924: struct list_head sb_list;
include/linux/perf_event.h-925- struct list_head pmu_list;
--
kernel/events/core.c=5312=static void detach_sb_event(struct perf_event *event)
--
kernel/events/core.c-5316- raw_spin_lock(&pel->lock);
kernel/events/core.c:5317: list_del_rcu(&event->sb_list);
kernel/events/core.c-5318- raw_spin_unlock(&pel->lock);
--
kernel/events/core.c=8943=static void perf_iterate_sb_cpu(perf_iterate_f output, void *data)
--
kernel/events/core.c-8947-
kernel/events/core.c:8948: list_for_each_entry_rcu(event, &pel->list, sb_list) {
kernel/events/core.c-8949- /*
--
kernel/events/core.c=13190=static void attach_sb_event(struct perf_event *event)
--
kernel/events/core.c-13194- raw_spin_lock(&pel->lock);
kernel/events/core.c:13195: list_add_rcu(&event->sb_list, &pel->list);
kernel/events/core.c-13196- raw_spin_unlock(&pel->lock);
--
net/devlink/core.c=430=struct devlink *__devlink_alloc(const struct devlink_ops *ops, size_t priv_size,
--
net/devlink/core.c-467- INIT_LIST_HEAD(&devlink->linecard_list);
net/devlink/core.c:468: INIT_LIST_HEAD(&devlink->sb_list);
net/devlink/core.c-469- INIT_LIST_HEAD_RCU(&devlink->dpipe_table_list);
--
net/devlink/core.c=517=void devlink_free(struct devlink *devlink)
--
net/devlink/core.c-527- WARN_ON(!list_empty(&devlink->dpipe_table_list));
net/devlink/core.c:528: WARN_ON(!list_empty(&devlink->sb_list));
net/devlink/core.c-529- WARN_ON(devlink_rates_check(devlink, NULL, NULL));
--
net/devlink/dev.c=430=static void devlink_reload_reinit_sanity_check(struct devlink *devlink)
--
net/devlink/dev.c-435- WARN_ON(!list_empty(&devlink->dpipe_table_list));
net/devlink/dev.c:436: WARN_ON(!list_empty(&devlink->sb_list));
net/devlink/dev.c-437- WARN_ON(devlink_rates_check(devlink, NULL, NULL));
--
net/devlink/devl_internal.h=33=struct devlink {
--
net/devlink/devl_internal.h-36- struct list_head rate_list;
net/devlink/devl_internal.h:37: struct list_head sb_list;
net/devlink/devl_internal.h-38- struct list_head dpipe_table_list;
--
net/devlink/sb.c=24=static struct devlink_sb *devlink_sb_get_by_index(struct devlink *devlink,
--
net/devlink/sb.c-28-
net/devlink/sb.c:29: list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
net/devlink/sb.c-30- if (devlink_sb->index == sb_index)
--
net/devlink/sb.c=232=devlink_nl_sb_get_dump_one(struct sk_buff *msg, struct devlink *devlink,
--
net/devlink/sb.c-239-
net/devlink/sb.c:240: list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
net/devlink/sb.c-241- if (idx < state->idx) {
--
net/devlink/sb.c=369=devlink_nl_sb_pool_get_dump_one(struct sk_buff *msg, struct devlink *devlink,
--
net/devlink/sb.c-379-
net/devlink/sb.c:380: list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
net/devlink/sb.c-381- err = __sb_pool_get_dumpit(msg, state->idx, &idx,
--
net/devlink/sb.c=576=devlink_nl_sb_port_pool_get_dump_one(struct sk_buff *msg,
--
net/devlink/sb.c-587-
net/devlink/sb.c:588: list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
net/devlink/sb.c-589- err = __sb_port_pool_get_dumpit(msg, state->idx, &idx,
--
net/devlink/sb.c=812=static int devlink_nl_sb_tc_pool_bind_get_dump_one(struct sk_buff *msg,
--
net/devlink/sb.c-824-
net/devlink/sb.c:825: list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
net/devlink/sb.c-826- err = __sb_tc_pool_bind_get_dumpit(msg, state->idx, &idx,
--
net/devlink/sb.c=934=int devl_sb_register(struct devlink *devlink, unsigned int sb_index,
--
net/devlink/sb.c-954- devlink_sb->egress_tc_count = egress_tc_count;
net/devlink/sb.c:955: list_add_tail(&devlink_sb->list, &devlink->sb_list);
net/devlink/sb.c-956- return 0;
--
security/landlock/fs.c=1269=static void hook_sb_delete(struct super_block *const sb)
--
security/landlock/fs.c-1276- spin_lock(&sb->s_inode_list_lock);
security/landlock/fs.c:1277: list_for_each_entry(inode, &sb->s_inodes, i_sb_list) {
security/landlock/fs.c-1278- struct landlock_object *object;
]
|
| 50/2 |
2026/05/11 23:36 |
llm |
debugger |
0m
Model:
Tokens:
input: 147555
output: 19
thoughts: 1838
Thoughts: **Analyzing a Potential Use-After-Free Vulnerability in JFS Logging**
Okay, so I'm digging into this JFS logging code. I see `sb_list` is part of the `jfs_log` struct and gets initialized with `INIT_LIST_HEAD`. The list holds `sbi->log_list`, which means a log can be shared, like with `open_dummy_log` or external logs. The crucial thing is that if `sb_list` isn't empty, `lmLogClose` bails out, avoiding a free. This suggests the use-after-free *only* happens if we're dealing with the *last* Super Block Info (`sbi`) using that log.
My initial thought was to wait for `log->active` to hit zero *before* freeing the log in `lmLogClose`, since the crash would mean it's being accessed after free. The `active` counter gets decremented in `txEnd`, which is called through the commit process. However, `lmLogClose` should not hold any locks or the mutex when waiting.
But then I realized, `jfs_umount` calls `jfs_flush_journal` which calls `lmLogClose(sb)`. And that while in `lmLogClose`, it sets `sbi->log = NULL` *before* checking and waiting. The thing is, `txLazyCommit` accesses the log through `JFS_SBI(tblk->sb)->log`. If we make `sbi->log = NULL` before processing all transactions, we risk a NULL pointer dereference within the `txLazyCommit` function! The crucial line is the spinlock: `spin_lock_irq(&log->gclock)`. So, the *must* wait *before* setting the pointer to `NULL`.
So, where *do* we wait?
Well, what if we wait in `jfs_flush_journal` when it's called with the appropriate `wait` value? That *could* work because it's called from both `jfs_umount` *and* `lmLogShutdown`. If we wait for `log->active` to become zero within `jfs_flush_journal`, then `jfs_lazycommit` will process transactions. This will call `txLazyCommit`, and it will correctly read `sbi->log` because it has not yet been set to NULL. Everything works perfectly! The call stack should resolve, and `log` can be freed safely.
But, a second thought arose! Is `log->active` always guaranteed to hit zero? If the log is shared (with external logs), another `sbi` could be starting new transactions, and `log->active` might never become zero. That would hang the unmount. In a shared log scenario, we need to make sure *only* the transactions belonging to *this* `sbi` are done, not all the transactions in the log. The `log->active` field represents transactions across the *entire* log.
So, how do we target *this* sbi's transactions? I can look at the `TxAnchor.unlock_queue`, to see if there are any blocks for my `sb`. If there are, I need to wait until they are finished. The `jfs_flush_journal` function gets the log, not the sb. How can I tie the sb back to the function? I could introduce a new function `txWaitSb(sb)` within `jfs_umount`, to handle this, or have logic to check a flag for that sb in the queue.
Ah, `jfs_lazycommit` has the key. It processes `TxAnchor.unlock_queue`, and there's a check: `sbi->commit_state & IN_LAZYCOMMIT`. This flag is set when `jfs_lazycommit` is working on a block associated with *this* `sb`. So, the correct waiting condition is until:
1. `sbi->commit_state & IN_LAZYCOMMIT` is zero *and*
2. `TxAnchor.unlock_queue` has no blocks for *this* `sb`.
This is the cleanest and most accurate solution! I need to ensure this sbi and only this sbi has finished its processing of blocks in the unlock_queue before letting go of the log. I need to make sure the fix is correctly reflected in the existing code.
|
| 51/2 |
2026/05/11 23:36 |
tool |
grepper |
0m
Args: map[Expression:IN_LAZYCOMMIT]
Results: map[Output:fs/jfs/jfs_incore.h=159=struct jfs_sb_info {
--
fs/jfs/jfs_incore.h-202-/* jfs_sb_info commit_state */
fs/jfs/jfs_incore.h:203:#define IN_LAZYCOMMIT 1
fs/jfs/jfs_incore.h-204-
--
fs/jfs/jfs_txnmgr.c=2700=int jfs_lazycommit(void *arg)
--
fs/jfs/jfs_txnmgr.c-2722- */
fs/jfs/jfs_txnmgr.c:2723: if (sbi->commit_state & IN_LAZYCOMMIT)
fs/jfs/jfs_txnmgr.c-2724- continue;
fs/jfs/jfs_txnmgr.c-2725-
fs/jfs/jfs_txnmgr.c:2726: sbi->commit_state |= IN_LAZYCOMMIT;
fs/jfs/jfs_txnmgr.c-2727- WorkDone = 1;
--
fs/jfs/jfs_txnmgr.c-2737-
fs/jfs/jfs_txnmgr.c:2738: sbi->commit_state &= ~IN_LAZYCOMMIT;
fs/jfs/jfs_txnmgr.c-2739- /*
--
fs/jfs/jfs_txnmgr.c=2775=void txLazyUnlock(struct tblock * tblk)
--
fs/jfs/jfs_txnmgr.c-2785- */
fs/jfs/jfs_txnmgr.c:2786: if (!(JFS_SBI(tblk->sb)->commit_state & IN_LAZYCOMMIT) &&
fs/jfs/jfs_txnmgr.c-2787- !jfs_commit_thread_waking) {
]
|
| 52/2 |
2026/05/11 23:36 |
llm |
debugger |
1m
Model:
Tokens:
input: 150893
output: 43
thoughts: 1296
Thoughts: **Addressing a Potential Race Condition in JFS Unmount with Lazy Commit**
Okay, so I've been digging into this JFS code, and I see a potential race condition when unmounting the filesystem, specifically related to the lazy commit mechanism. The problem stems from the interaction between `jfs_lazycommit` and the `lmLogClose` function, which is called during unmount.
Here's the scenario: There's no explicit function to wait for the `IN_LAZYCOMMIT` flag to clear. I noticed that `jfs_flush_journal` is called with `wait = 2` before the log is closed which contains a loop that waits for the journal queues to empty. Also, `txLazyCommit` accesses the log through the superblock (`sbi->log`). If `sbi->log` is `NULL` (which happens after `lmLogClose`), the code will crash. `lmLogClose` removes the log from a list and sets `sbi->log = NULL;` under a lock. The concern is that `jfs_lazycommit` might be concurrently running and attempt to access a log after it has been set to NULL.
So, the goal is to *ensure* that `jfs_lazycommit` isn't touching any `tblk` associated with the superblock (`sb`) while `lmLogClose` is happening. This means we have to add some form of synchronization.
The initial thought was to introduce a waiting mechanism within `jfs_flush_journal` or a new function like `jfs_wait_lazycommit()`. However, `jfs_flush_journal` doesn't have the `sb` so this won't work. Thus, I've decided it makes more sense to add the wait within `jfs_umount` since this *does* have the `sb`.
My idea is to add a loop in `jfs_umount` that checks the state:
1. Make sure that the `TxAnchor.unlock_queue` doesn't contain any `tblk` for this `sb`.
2. Make sure the `sbi->commit_state` is clear of `IN_LAZYCOMMIT`.
If both conditions are met, then we know all lazy commit transactions for that super block are done.
I went through where `tblk` is created, moved, and freed to make sure there are no other places these blocks may sit. It is created in `txBegin` then goes to `log->cqueue` in `txCommit`, is moved to `TxAnchor.unlock_queue` in `lmPostGC`, removed in `jfs_lazycommit`, and freed in `txEnd`.
There was a worry that a transaction might be *in* `txCommit` but not yet in `log->cqueue`. But I realized that `jfs_umount` is called after all user operations have been issued. No new transactions will happen once unmount has begun. All current transactions that are active must have finished `txCommit` as `vfs_umount` waits for all operations to finish. Also, the functions `diUnmount` and `dbUnmount`, called within `jfs_umount`, call `diSync` and `dbSync`, but these don't initiate transactions, so that's a non-issue. So, all active transactions must be in either `log->cqueue`, `TxAnchor.unlock_queue`, or currently being processed. `jfs_flush_journal` has a loop to wait for `log->cqueue` to empty. Thus, after that, all are either in `TxAnchor.unlock_queue` or being processed or already finished. So waiting for `TxAnchor.unlock_queue` and the `IN_LAZYCOMMIT` flag will work.
I then realized I needed to check the `log->synclist` as well. Also, `TxAnchor.anon_list` and `TxAnchor.anon_list2` are processed by `txQuiesce`, but `jfs_umount` does not call `txQuiesce`. I'll have to investigate if `txQuiesce` is called elsewhere.
Specifically, I'll need to check `jfs_put_super`.
|
| 53/2 |
2026/05/11 23:37 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:fs/jfs/super.c IncludeLines:true Name:jfs_put_super]
Results: map[SourceCode: 185: static void jfs_put_super(struct super_block *sb)
186: {
187: struct jfs_sb_info *sbi = JFS_SBI(sb);
188: int rc;
189:
190: jfs_info("In jfs_put_super");
191:
192: jfs_quota_off_umount(sb);
193:
194: rc = jfs_umount(sb);
195: if (rc)
196: jfs_err("jfs_umount failed with return code %d", rc);
197:
198: unload_nls(sbi->nls_tab);
199:
200: truncate_inode_pages(sbi->direct_inode->i_mapping, 0);
201: iput(sbi->direct_inode);
202:
203: kfree(sbi);
204: }
SourceFile:fs/jfs/super.c]
|
| 54/2 |
2026/05/11 23:37 |
llm |
debugger |
0m
Model:
Tokens:
input: 153458
output: 44
thoughts: 222
Thoughts: **Analyzing a JFS Crash: A Deep Dive**
Okay, so I'm looking into this JFS crash, and it's pointing to `lmLogSync` in `jfs_logmgr.c`, specifically line 1003. The stack trace indicates a slab-use-after-free error. That's never good, and it's happening during a `jfsCommit` process. Let's trace how we got here.
First, I recall that `jfs_put_super` calls `jfs_umount`. But, interestingly, it *doesn't* directly call `txQuiesce`. Hmm, but `jfs_freeze` does call it. That's important. Now, the key question is, does `jfs_umount` need to explicitly wait for `TxAnchor.unlock_queue`? Yes, it does, because `jfs_lazycommit` might *still* be churning through transactions for that specific superblock (`sb`). So, some sort of timing issue involving the commit queue is likely involved.
Let's zoom back in on that crash at `lmLogSync`. The error is a write of size 4 at a specific address, triggered by a task named `jfsCommit/122`. Okay, time to look at the `lmLogSync` function code at that specific line. I have a feeling that we are going to understand exactly what is happening in the coming moments.
|
| 55/2 |
2026/05/11 23:37 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:fs/jfs/jfs_logmgr.c IncludeLines:true Name:lmLogSync]
Results: map[SourceCode: 902: /*
903: * NAME: lmLogSync()
904: *
905: * FUNCTION: write log SYNCPT record for specified log
906: * if new sync address is available
907: * (normally the case if sync() is executed by back-ground
908: * process).
909: * calculate new value of i_nextsync which determines when
910: * this code is called again.
911: *
912: * PARAMETERS: log - log structure
913: * hard_sync - 1 to force all metadata to be written
914: *
915: * RETURN: 0
916: *
917: * serialization: LOG_LOCK() held on entry/exit
918: */
919: static int lmLogSync(struct jfs_log * log, int hard_sync)
920: {
921: int logsize;
922: int written; /* written since last syncpt */
923: int free; /* free space left available */
924: int delta; /* additional delta to write normally */
925: int more; /* additional write granted */
926: struct lrd lrd;
927: int lsn;
928: struct logsyncblk *lp;
929: unsigned long flags;
930:
931: /* push dirty metapages out to disk */
932: if (hard_sync)
933: write_special_inodes(log, filemap_fdatawrite);
934: else
935: write_special_inodes(log, filemap_flush);
936:
937: /*
938: * forward syncpt
939: */
940: /* if last sync is same as last syncpt,
941: * invoke sync point forward processing to update sync.
942: */
943:
944: if (log->sync == log->syncpt) {
945: LOGSYNC_LOCK(log, flags);
946: if (list_empty(&log->synclist))
947: log->sync = log->lsn;
948: else {
949: lp = list_entry(log->synclist.next,
950: struct logsyncblk, synclist);
951: log->sync = lp->lsn;
952: }
953: LOGSYNC_UNLOCK(log, flags);
954:
955: }
956:
957: /* if sync is different from last syncpt,
958: * write a SYNCPT record with syncpt = sync.
959: * reset syncpt = sync
960: */
961: if (log->sync != log->syncpt) {
962: lrd.logtid = 0;
963: lrd.backchain = 0;
964: lrd.type = cpu_to_le16(LOG_SYNCPT);
965: lrd.length = 0;
966: lrd.log.syncpt.sync = cpu_to_le32(log->sync);
967: lsn = lmWriteRecord(log, NULL, &lrd, NULL);
968:
969: log->syncpt = log->sync;
970: } else
971: lsn = log->lsn;
972:
973: /*
974: * setup next syncpt trigger (SWAG)
975: */
976: logsize = log->logsize;
977:
978: logdiff(written, lsn, log);
979: free = logsize - written;
980: delta = LOGSYNC_DELTA(logsize);
981: more = min(free / 2, delta);
982: if (more < 2 * LOGPSIZE) {
983: jfs_warn("\n ... Log Wrap ... Log Wrap ... Log Wrap ...\n");
984: /*
985: * log wrapping
986: *
987: * option 1 - panic ? No.!
988: * option 2 - shutdown file systems
989: * associated with log ?
990: * option 3 - extend log ?
991: * option 4 - second chance
992: *
993: * mark log wrapped, and continue.
994: * when all active transactions are completed,
995: * mark log valid for recovery.
996: * if crashed during invalid state, log state
997: * implies invalid log, forcing fsck().
998: */
999: /* mark log state log wrap in log superblock */
1000: /* log->state = LOGWRAP; */
1001:
1002: /* reset sync point computation */
1003: log->syncpt = log->sync = lsn;
1004: log->nextsync = delta;
1005: } else
1006: /* next syncpt trigger = written + more */
1007: log->nextsync = written + more;
1008:
1009: /* if number of bytes written from last sync point is more
1010: * than 1/4 of the log size, stop new transactions from
1011: * starting until all current transactions are completed
1012: * by setting syncbarrier flag.
1013: */
1014: if (!test_bit(log_SYNCBARRIER, &log->flag) &&
1015: (written > LOGSYNC_BARRIER(logsize)) && log->active) {
1016: set_bit(log_SYNCBARRIER, &log->flag);
1017: jfs_info("log barrier on: lsn=0x%x syncpt=0x%x", lsn,
1018: log->syncpt);
1019: /*
1020: * We may have to initiate group commit
1021: */
1022: jfs_flush_journal(log, 0);
1023: }
1024:
1025: return lsn;
1026: }
SourceFile:fs/jfs/jfs_logmgr.c]
|
| 56/2 |
2026/05/11 23:37 |
llm |
debugger |
0m
Model:
Tokens:
input: 155849
output: 20
thoughts: 2137
Thoughts: **Analyzing the JFS Journaling Crash and Proposed Fix**
Okay, here's what I've got. The crash is happening because the `log` structure is being freed while there's still a write operation pending on `log->syncpt`. This is happening because `jfs_umount` is triggering the freeing of the log, but it's not properly waiting for all transactions to complete.
The initial thought was to modify `jfs_flush_journal` to wait for the `TxAnchor.unlock_queue` to empty, but that is not the right approach. Then I tried `log->active`, but that is not sufficient.
The key lies in understanding when `log` is actually freed and when the `sbi->log` pointer becomes `NULL`. From `lmLogClose`, I can see that `log` is only freed when `log->sb_list` is empty, indicating no other superblock is using this log. HOWEVER, the crucial point is that even if `log` is shared, we *must* ensure all transactions related to the *current* superblock (`sb`) are finished *before* `sbi->log` is set to NULL. This is critical because `txLazyCommit` accesses `JFS_SBI(tblk->sb)->log` and a NULL pointer there will cause the system to crash.
My refined approach is to add a wait loop in `jfs_umount` *after* calling `jfs_flush_journal`. This loop needs to check two things:
1. That there are no `tblk` structures on `TxAnchor.unlock_queue` associated with the current `sb`.
2. That `sbi->commit_state & IN_LAZYCOMMIT` is 0, indicating lazy commit is finished.
Effectively, this means waiting for all transactions associated with the specific superblock to finish. There might be concern about transactions being processed by `txLazyCommit`, but since `jfs_umount` is called when no new operations can begin, the lazycommit transactions will have to finish.
The check for `log->active == 0` is not sufficient, and `txQuiesce` looks like it's for filesystem freezing, not a transaction wait.
In essence, the fix involves a careful synchronization mechanism within `jfs_umount` that accounts for potential concurrent access to the `log` structure from other threads, especially those involved in `txLazyCommit`. This will require adding a custom loop to wait for transactions, with the above-mentioned conditions.
|
| 57/2 |
2026/05/11 23:38 |
tool |
grepper |
0m
Args: map[Expression:jfs_flush_journal]
Results: map[Output:fs/jfs/file.c=20=int jfs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
--
fs/jfs/file.c-32- /* Make sure committed changes hit the disk */
fs/jfs/file.c:33: jfs_flush_journal(JFS_SBI(inode->i_sb)->log, 1);
fs/jfs/file.c-34- inode_unlock(inode);
--
fs/jfs/inode.c=121=int jfs_write_inode(struct inode *inode, struct writeback_control *wbc)
--
fs/jfs/inode.c-133- /* Make sure committed changes hit the disk */
fs/jfs/inode.c:134: jfs_flush_journal(JFS_SBI(inode->i_sb)->log, wait);
fs/jfs/inode.c-135- return 0;
--
fs/jfs/jfs_logmgr.c=919=static int lmLogSync(struct jfs_log * log, int hard_sync)
--
fs/jfs/jfs_logmgr.c-1021- */
fs/jfs/jfs_logmgr.c:1022: jfs_flush_journal(log, 0);
fs/jfs/jfs_logmgr.c-1023- }
--
fs/jfs/jfs_logmgr.c=1432=int lmLogClose(struct super_block *sb)
--
fs/jfs/jfs_logmgr.c-1496-/*
fs/jfs/jfs_logmgr.c:1497: * NAME: jfs_flush_journal()
fs/jfs/jfs_logmgr.c-1498- *
--
fs/jfs/jfs_logmgr.c-1505- */
fs/jfs/jfs_logmgr.c:1506:void jfs_flush_journal(struct jfs_log *log, int wait)
fs/jfs/jfs_logmgr.c-1507-{
--
fs/jfs/jfs_logmgr.c-1514-
fs/jfs/jfs_logmgr.c:1515: jfs_info("jfs_flush_journal: log:0x%p wait=%d", log, wait);
fs/jfs/jfs_logmgr.c-1516-
--
fs/jfs/jfs_logmgr.c-1590-
fs/jfs/jfs_logmgr.c:1591: printk(KERN_ERR "jfs_flush_journal: synclist not empty\n");
fs/jfs/jfs_logmgr.c-1592- list_for_each_entry(lp, &log->synclist, synclist) {
--
fs/jfs/jfs_logmgr.c=1628=int lmLogShutdown(struct jfs_log * log)
--
fs/jfs/jfs_logmgr.c-1639-
fs/jfs/jfs_logmgr.c:1640: jfs_flush_journal(log, 2);
fs/jfs/jfs_logmgr.c-1641-
--
fs/jfs/jfs_logmgr.h=503=extern int jfsIOWait(void *);
fs/jfs/jfs_logmgr.h:504:extern void jfs_flush_journal(struct jfs_log * log, int wait);
fs/jfs/jfs_logmgr.h-505-extern void jfs_syncpt(struct jfs_log *log, int hard_sync);
--
fs/jfs/jfs_metapage.c=424=static int metapage_write_folio(struct folio *folio,
--
fs/jfs/jfs_metapage.c-462- if (mp->log && !(mp->log->cflag & logGC_PAGEOUT))
fs/jfs/jfs_metapage.c:463: jfs_flush_journal(mp->log, 0);
fs/jfs/jfs_metapage.c-464- continue;
--
fs/jfs/jfs_txnmgr.c=2813=void txQuiesce(struct super_block *sb)
--
fs/jfs/jfs_txnmgr.c-2860- */
fs/jfs/jfs_txnmgr.c:2861: jfs_flush_journal(log, 0);
fs/jfs/jfs_txnmgr.c-2862-}
--
fs/jfs/jfs_umount.c=38=int jfs_umount(struct super_block *sb)
--
fs/jfs/jfs_umount.c-58- */
fs/jfs/jfs_umount.c:59: jfs_flush_journal(log, 2);
fs/jfs/jfs_umount.c-60-
--
fs/jfs/jfs_umount.c=131=int jfs_umount_rw(struct super_block *sb)
--
fs/jfs/jfs_umount.c-143- */
fs/jfs/jfs_umount.c:144: jfs_flush_journal(log, 2);
fs/jfs/jfs_umount.c-145-
--
fs/jfs/super.c=638=static int jfs_sync_fs(struct super_block *sb, int wait)
--
fs/jfs/super.c-648- dquot_writeback_dquots(sb, -1);
fs/jfs/super.c:649: jfs_flush_journal(log, wait);
fs/jfs/super.c-650- jfs_syncpt(log, 0);
]
|
| 58/2 |
2026/05/11 23:38 |
llm |
debugger |
1m
Model:
Tokens:
input: 160075
output: 16
thoughts: 1371
Thoughts: **Refining the Journal Flush Logic for JFS Unmount**
Okay, so I'm thinking about this JFS journal flush operation during unmount. There isn't a direct function to wait for transactions specifically tied to a given superblock (`sb`), but `jfs_umount` *does* call `jfs_umount`, which in turn leads to the invocation of `jfs_put_super`. Let's keep that in mind.
My initial thought was to modify `jfs_flush_journal` to wait for the `TxAnchor.unlock_queue` to become empty. However, `jfs_flush_journal` takes the journal log (`log`) as its argument, and the `unlock_queue` is global. So, waiting on `TxAnchor.unlock_queue` directly might cause us to wait for transactions from *other* superblocks as well. Is that a problem?
Since `jfs_flush_journal` is called with `wait = 2` during umount, and the `jfs_lazycommit` thread seems to process the global queue pretty quickly, waiting on the unlock queue is probably fine. However, since `jfs_lazycommit` *could* be processing a transaction at the same time, it's not enough to just check the empty queue. We also need to check if `sbi->commit_state` has the `IN_LAZYCOMMIT` flag set.
The problem is that `jfs_flush_journal` only knows the `log`, not the `sbi` (SuperBlock Info). But! The `log` has a list of superblocks (`sb_list`). This means we can iterate through `log->sb_list` and check the `commit_state` of each `sbi`. Okay, let's see how that would look:
```c
if (wait > 1) {
/*
* If there was recent activity, we may need to wait
* for the lazycommit thread to catch up
*/
if ((!list_empty(&log->cqueue)) || !list_empty(&log->synclist)) {
for (i = 0; i < 200; i++) { /* Too much? */
msleep(250);
write_special_inodes(log, filemap_fdatawrite);
if (list_empty(&log->cqueue) &&
list_empty(&log->synclist))
break;
}
}
assert(list_empty(&log->cqueue));
/* Wait for lazycommit to finish */
while (1) {
unsigned long flags;
struct tblock *tblk;
int found = 0;
struct jfs_sb_info *sbi;
LAZY_LOCK(flags);
list_for_each_entry(sbi, &log->sb_list, log_list) {
if (sbi->commit_state & IN_LAZYCOMMIT) {
found = 1;
break;
}
}
if (!found) {
list_for_each_entry(tblk, &TxAnchor.unlock_queue, cqueue) {
if (JFS_SBI(tblk->sb)->log == log) {
found = 1;
break;
}
}
}
LAZY_UNLOCK(flags);
if (!found)
break;
msleep(10);
}
}
```
So, if we add this logic in `jfs_flush_journal`, called with `wait = 2`, it should reliably wait for all transactions associated with *this* log to be fully processed by `jfs_lazycommit`, which is exactly what we want during unmount.
Is there any risk of deadlock? `jfs_flush_journal` is called with `wait = 2` without holding locks other than maybe VFS locks like `sb->s_umount`, and `jfs_lazycommit` is taking `LAZY_LOCK`, `log->gclock`, and `TXN_LOCK`. No VFS locks are taken. So, the wait loop is safe.
Just to be absolutely sure, let's double-check how `jfs_lazycommit` works:
```c
while (!list_empty(&TxAnchor.unlock_queue)) {
WorkDone = 0;
list_for_each_entry(tblk, &TxAnchor.unlock_queue,
cqueue) {
sbi = JFS_SBI(tblk->
|
| 59/2 |
2026/05/11 23:39 |
tool |
grepper |
0m
Args:
Results: map[Output:fs/jfs/jfs_debug.c=55=void jfs_proc_init(void)
--
fs/jfs/jfs_debug.c-69-#ifdef CONFIG_JFS_DEBUG
fs/jfs/jfs_debug.c:70: proc_create_single("TxAnchor", 0, base, jfs_txanchor_proc_show);
fs/jfs/jfs_debug.c-71- proc_create("loglevel", 0, base, &jfs_loglevel_proc_ops);
--
fs/jfs/jfs_txnmgr.c=53=static struct {
--
fs/jfs/jfs_txnmgr.c-65- that couldn't be sync'ed */
fs/jfs/jfs_txnmgr.c:66:} TxAnchor;
fs/jfs/jfs_txnmgr.c-67-
--
fs/jfs/jfs_txnmgr.c=103=static DEFINE_SPINLOCK(jfsTxnLock);
--
fs/jfs/jfs_txnmgr.c-107-
fs/jfs/jfs_txnmgr.c:108:#define LAZY_LOCK_INIT() spin_lock_init(&TxAnchor.LazyLock)
fs/jfs/jfs_txnmgr.c:109:#define LAZY_LOCK(flags) spin_lock_irqsave(&TxAnchor.LazyLock, flags)
fs/jfs/jfs_txnmgr.c:110:#define LAZY_UNLOCK(flags) spin_unlock_irqrestore(&TxAnchor.LazyLock, flags)
fs/jfs/jfs_txnmgr.c-111-
--
fs/jfs/jfs_txnmgr.c=180=static lid_t txLockAlloc(void)
--
fs/jfs/jfs_txnmgr.c-184- INCREMENT(TxStat.txLockAlloc);
fs/jfs/jfs_txnmgr.c:185: if (!TxAnchor.freelock) {
fs/jfs/jfs_txnmgr.c-186- INCREMENT(TxStat.txLockAlloc_freelock);
--
fs/jfs/jfs_txnmgr.c-188-
fs/jfs/jfs_txnmgr.c:189: while (!(lid = TxAnchor.freelock))
fs/jfs/jfs_txnmgr.c:190: TXN_SLEEP(&TxAnchor.freelockwait);
fs/jfs/jfs_txnmgr.c:191: TxAnchor.freelock = TxLock[lid].next;
fs/jfs/jfs_txnmgr.c-192- HIGHWATERMARK(stattx.maxlid, lid);
fs/jfs/jfs_txnmgr.c:193: if ((++TxAnchor.tlocksInUse > TxLockHWM) && (jfs_tlocks_low == 0)) {
fs/jfs/jfs_txnmgr.c-194- jfs_info("txLockAlloc tlocks low");
--
fs/jfs/jfs_txnmgr.c=202=static void txLockFree(lid_t lid)
--
fs/jfs/jfs_txnmgr.c-204- TxLock[lid].tid = 0;
fs/jfs/jfs_txnmgr.c:205: TxLock[lid].next = TxAnchor.freelock;
fs/jfs/jfs_txnmgr.c:206: TxAnchor.freelock = lid;
fs/jfs/jfs_txnmgr.c:207: TxAnchor.tlocksInUse--;
fs/jfs/jfs_txnmgr.c:208: if (jfs_tlocks_low && (TxAnchor.tlocksInUse < TxLockLWM)) {
fs/jfs/jfs_txnmgr.c-209- jfs_info("txLockFree jfs_tlocks_low no more");
fs/jfs/jfs_txnmgr.c-210- jfs_tlocks_low = 0;
fs/jfs/jfs_txnmgr.c:211: TXN_WAKEUP(&TxAnchor.lowlockwait);
fs/jfs/jfs_txnmgr.c-212- }
fs/jfs/jfs_txnmgr.c:213: TXN_WAKEUP(&TxAnchor.freelockwait);
fs/jfs/jfs_txnmgr.c-214-}
--
fs/jfs/jfs_txnmgr.c=225=int txInit(void)
--
fs/jfs/jfs_txnmgr.c-285-
fs/jfs/jfs_txnmgr.c:286: TxAnchor.freetid = 1;
fs/jfs/jfs_txnmgr.c:287: init_waitqueue_head(&TxAnchor.freewait);
fs/jfs/jfs_txnmgr.c-288-
--
fs/jfs/jfs_txnmgr.c-307- TxLock[k].next = 0;
fs/jfs/jfs_txnmgr.c:308: init_waitqueue_head(&TxAnchor.freelockwait);
fs/jfs/jfs_txnmgr.c:309: init_waitqueue_head(&TxAnchor.lowlockwait);
fs/jfs/jfs_txnmgr.c-310-
fs/jfs/jfs_txnmgr.c:311: TxAnchor.freelock = 1;
fs/jfs/jfs_txnmgr.c:312: TxAnchor.tlocksInUse = 0;
fs/jfs/jfs_txnmgr.c:313: INIT_LIST_HEAD(&TxAnchor.anon_list);
fs/jfs/jfs_txnmgr.c:314: INIT_LIST_HEAD(&TxAnchor.anon_list2);
fs/jfs/jfs_txnmgr.c-315-
fs/jfs/jfs_txnmgr.c-316- LAZY_LOCK_INIT();
fs/jfs/jfs_txnmgr.c:317: INIT_LIST_HEAD(&TxAnchor.unlock_queue);
fs/jfs/jfs_txnmgr.c-318-
--
fs/jfs/jfs_txnmgr.c=350=tid_t txBegin(struct super_block *sb, int flag)
--
fs/jfs/jfs_txnmgr.c-385- */
fs/jfs/jfs_txnmgr.c:386: if (TxAnchor.tlocksInUse > TxLockVHWM) {
fs/jfs/jfs_txnmgr.c-387- INCREMENT(TxStat.txBegin_lockslow);
fs/jfs/jfs_txnmgr.c:388: TXN_SLEEP(&TxAnchor.lowlockwait);
fs/jfs/jfs_txnmgr.c-389- goto retry;
--
fs/jfs/jfs_txnmgr.c-395- */
fs/jfs/jfs_txnmgr.c:396: if ((t = TxAnchor.freetid) == 0) {
fs/jfs/jfs_txnmgr.c-397- jfs_info("txBegin: waiting for free tid");
fs/jfs/jfs_txnmgr.c-398- INCREMENT(TxStat.txBegin_freetid);
fs/jfs/jfs_txnmgr.c:399: TXN_SLEEP(&TxAnchor.freewait);
fs/jfs/jfs_txnmgr.c-400- goto retry;
--
fs/jfs/jfs_txnmgr.c-408- INCREMENT(TxStat.txBegin_freetid);
fs/jfs/jfs_txnmgr.c:409: TXN_SLEEP(&TxAnchor.freewait);
fs/jfs/jfs_txnmgr.c-410- goto retry;
--
fs/jfs/jfs_txnmgr.c-412-
fs/jfs/jfs_txnmgr.c:413: TxAnchor.freetid = tblk->next;
fs/jfs/jfs_txnmgr.c-414-
--
fs/jfs/jfs_txnmgr.c=454=void txBeginAnon(struct super_block *sb)
--
fs/jfs/jfs_txnmgr.c-476- */
fs/jfs/jfs_txnmgr.c:477: if (TxAnchor.tlocksInUse > TxLockVHWM) {
fs/jfs/jfs_txnmgr.c-478- INCREMENT(TxStat.txBeginAnon_lockslow);
fs/jfs/jfs_txnmgr.c:479: TXN_SLEEP(&TxAnchor.lowlockwait);
fs/jfs/jfs_txnmgr.c-480- goto retry;
--
fs/jfs/jfs_txnmgr.c=494=void txEnd(tid_t tid)
--
fs/jfs/jfs_txnmgr.c-534- */
fs/jfs/jfs_txnmgr.c:535: tblk->next = TxAnchor.freetid;
fs/jfs/jfs_txnmgr.c:536: TxAnchor.freetid = tid;
fs/jfs/jfs_txnmgr.c-537-
--
fs/jfs/jfs_txnmgr.c-569- */
fs/jfs/jfs_txnmgr.c:570: TXN_WAKEUP(&TxAnchor.freewait);
fs/jfs/jfs_txnmgr.c-571-}
--
fs/jfs/jfs_txnmgr.c=584=struct tlock *txLock(tid_t tid, struct inode *ip, struct metapage * mp,
--
fs/jfs/jfs_txnmgr.c-757- list_add_tail(&jfs_ip->anon_inode_list,
fs/jfs/jfs_txnmgr.c:758: &TxAnchor.anon_list);
fs/jfs/jfs_txnmgr.c-759- TXN_UNLOCK();
--
fs/jfs/jfs_txnmgr.c=989=struct tlock *txMaplock(tid_t tid, struct inode *ip, int type)
--
fs/jfs/jfs_txnmgr.c-1041- list_add_tail(&jfs_ip->anon_inode_list,
fs/jfs/jfs_txnmgr.c:1042: &TxAnchor.anon_list);
fs/jfs/jfs_txnmgr.c-1043- }
--
fs/jfs/jfs_txnmgr.c=2700=int jfs_lazycommit(void *arg)
--
fs/jfs/jfs_txnmgr.c-2710- jfs_commit_thread_waking = 0; /* OK to wake another thread */
fs/jfs/jfs_txnmgr.c:2711: while (!list_empty(&TxAnchor.unlock_queue)) {
fs/jfs/jfs_txnmgr.c-2712- WorkDone = 0;
fs/jfs/jfs_txnmgr.c:2713: list_for_each_entry(tblk, &TxAnchor.unlock_queue,
fs/jfs/jfs_txnmgr.c-2714- cqueue) {
--
fs/jfs/jfs_txnmgr.c-2767-
fs/jfs/jfs_txnmgr.c:2768: if (!list_empty(&TxAnchor.unlock_queue))
fs/jfs/jfs_txnmgr.c-2769- jfs_err("jfs_lazycommit being killed w/pending transactions!");
--
fs/jfs/jfs_txnmgr.c=2775=void txLazyUnlock(struct tblock * tblk)
--
fs/jfs/jfs_txnmgr.c-2780-
fs/jfs/jfs_txnmgr.c:2781: list_add_tail(&tblk->cqueue, &TxAnchor.unlock_queue);
fs/jfs/jfs_txnmgr.c-2782- /*
--
fs/jfs/jfs_txnmgr.c=2813=void txQuiesce(struct super_block *sb)
--
fs/jfs/jfs_txnmgr.c-2823-restart:
fs/jfs/jfs_txnmgr.c:2824: while (!list_empty(&TxAnchor.anon_list)) {
fs/jfs/jfs_txnmgr.c:2825: jfs_ip = list_entry(TxAnchor.anon_list.next,
fs/jfs/jfs_txnmgr.c-2826- struct jfs_inode_info,
--
fs/jfs/jfs_txnmgr.c-2851- */
fs/jfs/jfs_txnmgr.c:2852: if (!list_empty(&TxAnchor.anon_list2)) {
fs/jfs/jfs_txnmgr.c:2853: list_splice_init(&TxAnchor.anon_list2, &TxAnchor.anon_list);
fs/jfs/jfs_txnmgr.c-2854- goto restart;
--
fs/jfs/jfs_txnmgr.c=2884=int jfs_sync(void *arg)
--
fs/jfs/jfs_txnmgr.c-2895- TXN_LOCK();
fs/jfs/jfs_txnmgr.c:2896: while (jfs_tlocks_low && !list_empty(&TxAnchor.anon_list)) {
fs/jfs/jfs_txnmgr.c:2897: jfs_ip = list_entry(TxAnchor.anon_list.next,
fs/jfs/jfs_txnmgr.c-2898- struct jfs_inode_info,
--
fs/jfs/jfs_txnmgr.c-2933- list_move(&jfs_ip->anon_inode_list,
fs/jfs/jfs_txnmgr.c:2934: &TxAnchor.anon_list2);
fs/jfs/jfs_txnmgr.c-2935-
--
fs/jfs/jfs_txnmgr.c-2941- /* Add anon_list2 back to anon_list */
fs/jfs/jfs_txnmgr.c:2942: list_splice_init(&TxAnchor.anon_list2, &TxAnchor.anon_list);
fs/jfs/jfs_txnmgr.c-2943-
--
fs/jfs/jfs_txnmgr.c=2959=int jfs_txanchor_proc_show(struct seq_file *m, void *v)
--
fs/jfs/jfs_txnmgr.c-2965- freewait =
fs/jfs/jfs_txnmgr.c:2966: waitqueue_active(&TxAnchor.freewait) ? "active" : "empty";
fs/jfs/jfs_txnmgr.c-2967- freelockwait =
fs/jfs/jfs_txnmgr.c:2968: waitqueue_active(&TxAnchor.freelockwait) ? "active" : "empty";
fs/jfs/jfs_txnmgr.c-2969- lowlockwait =
fs/jfs/jfs_txnmgr.c:2970: waitqueue_active(&TxAnchor.lowlockwait) ? "active" : "empty";
fs/jfs/jfs_txnmgr.c-2971-
fs/jfs/jfs_txnmgr.c-2972- seq_printf(m,
fs/jfs/jfs_txnmgr.c:2973: "JFS TxAnchor\n"
fs/jfs/jfs_txnmgr.c-2974- "============\n"
--
fs/jfs/jfs_txnmgr.c-2982- "unlock_queue is %sempty\n",
fs/jfs/jfs_txnmgr.c:2983: TxAnchor.freetid,
fs/jfs/jfs_txnmgr.c-2984- freewait,
fs/jfs/jfs_txnmgr.c:2985: TxAnchor.freelock,
fs/jfs/jfs_txnmgr.c-2986- freelockwait,
fs/jfs/jfs_txnmgr.c-2987- lowlockwait,
fs/jfs/jfs_txnmgr.c:2988: TxAnchor.tlocksInUse,
fs/jfs/jfs_txnmgr.c-2989- jfs_tlocks_low,
fs/jfs/jfs_txnmgr.c:2990: list_empty(&TxAnchor.unlock_queue) ? "" : "not ");
fs/jfs/jfs_txnmgr.c-2991- return 0;
]
|
| 60/2 |
2026/05/11 23:39 |
llm |
debugger |
0m
Model:
Tokens:
input: 167040
output: 46
thoughts: 346
Thoughts: **My Reasoning on Synchronizing Journal Flushing in JFS**
Okay, so I'm looking at `TxAnchor` β it's static within `fs/jfs/jfs_txnmgr.c`. Right, so I can't directly access `TxAnchor.unlock_queue` from `fs/jfs/jfs_logmgr.c`. That's a constraint I need to address. Hmm, I could add a function in `jfs_txnmgr.c` that waits for the `unlock_queue` to empty, and that function could take either a superblock (`sb`) or a log as input.
Wait a minute, `jfs_flush_journal` is actually in `fs/jfs/jfs_logmgr.c`. If `jfs_flush_journal` needs to wait on `unlock_queue`, it could call a function from `jfs_txnmgr.c`. But... hold on, maybe there's a simpler approach. Couldn't I just wait for `log->active == 0` *within* `jfs_flush_journal` itself?
Aha! `log->active` *is* accessible from `jfs_logmgr.c` because `struct jfs_log` is defined in `jfs_logmgr.h`. Excellent. Let me just quickly confirm that `log->active` is guaranteed to eventually become zero. Previously, I considered shared logs, but I recall that JFS in Linux doesn't support shared logs.
Okay, now let me consider `open_dummy_log` and `open_inline_log`. `open_inline_log` allocates a new `log` per superblock. And `open_dummy_log` uses a global `dummy_log`. Time to check out `open_dummy_log`.
|
| 61/2 |
2026/05/11 23:39 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:fs/jfs/jfs_logmgr.c IncludeLines:true Name:open_dummy_log]
Results: map[SourceCode:1185: static int open_dummy_log(struct super_block *sb)
1186: {
1187: int rc;
1188:
1189: mutex_lock(&jfs_log_mutex);
1190: if (!dummy_log) {
1191: dummy_log = kzalloc_obj(struct jfs_log);
1192: if (!dummy_log) {
1193: mutex_unlock(&jfs_log_mutex);
1194: return -ENOMEM;
1195: }
1196: INIT_LIST_HEAD(&dummy_log->sb_list);
1197: init_waitqueue_head(&dummy_log->syncwait);
1198: dummy_log->no_integrity = 1;
1199: /* Make up some stuff */
1200: dummy_log->size = 1024;
1201: rc = lmLogInit(dummy_log);
1202: if (rc) {
1203: kfree(dummy_log);
1204: dummy_log = NULL;
1205: mutex_unlock(&jfs_log_mutex);
1206: return rc;
1207: }
1208: }
1209:
1210: LOG_LOCK(dummy_log);
1211: list_add(&JFS_SBI(sb)->log_list, &dummy_log->sb_list);
1212: JFS_SBI(sb)->log = dummy_log;
1213: LOG_UNLOCK(dummy_log);
1214: mutex_unlock(&jfs_log_mutex);
1215:
1216: return 0;
1217: }
SourceFile:fs/jfs/jfs_logmgr.c]
|
| 62/2 |
2026/05/11 23:39 |
llm |
debugger |
0m
Model:
Tokens:
input: 168337
output: 44
thoughts: 16
Thoughts: Okay, here's my take on those thoughts, framed as an expert's internal monologue:
**Log Sharing Considerations**
Right, so we're dealing with `dummy_log`. I see that it's shared, which is a key starting point. But, and this is where it gets interesting, what about *external* logging? Are we simply assuming that internal logging will suffice, or is there a need to correlate with external sources? What other logs do we need to consider and how do these systems interact? Thatβs where the real complexity begins and where I'd need more information to assess the bigger picture.
|
| 63/2 |
2026/05/11 23:40 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:fs/jfs/jfs_logmgr.c IncludeLines:true Name:lmLogOpen]
Results: map[SourceCode:1043: /*
1044: * NAME: lmLogOpen()
1045: *
1046: * FUNCTION: open the log on first open;
1047: * insert filesystem in the active list of the log.
1048: *
1049: * PARAMETER: ipmnt - file system mount inode
1050: * iplog - log inode (out)
1051: *
1052: * RETURN:
1053: *
1054: * serialization:
1055: */
1056: int lmLogOpen(struct super_block *sb)
1057: {
1058: int rc;
1059: struct file *bdev_file;
1060: struct jfs_log *log;
1061: struct jfs_sb_info *sbi = JFS_SBI(sb);
1062:
1063: if (sbi->flag & JFS_NOINTEGRITY)
1064: return open_dummy_log(sb);
1065:
1066: if (sbi->mntflag & JFS_INLINELOG)
1067: return open_inline_log(sb);
1068:
1069: mutex_lock(&jfs_log_mutex);
1070: list_for_each_entry(log, &jfs_external_logs, journal_list) {
1071: if (file_bdev(log->bdev_file)->bd_dev == sbi->logdev) {
1072: if (!uuid_equal(&log->uuid, &sbi->loguuid)) {
1073: jfs_warn("wrong uuid on JFS journal");
1074: mutex_unlock(&jfs_log_mutex);
1075: return -EINVAL;
1076: }
1077: /*
1078: * add file system to log active file system list
1079: */
1080: if ((rc = lmLogFileSystem(log, sbi, 1))) {
1081: mutex_unlock(&jfs_log_mutex);
1082: return rc;
1083: }
1084: goto journal_found;
1085: }
1086: }
1087:
1088: if (!(log = kzalloc_obj(struct jfs_log))) {
1089: mutex_unlock(&jfs_log_mutex);
1090: return -ENOMEM;
1091: }
1092: INIT_LIST_HEAD(&log->sb_list);
1093: init_waitqueue_head(&log->syncwait);
1094:
1095: /*
1096: * external log as separate logical volume
1097: *
1098: * file systems to log may have n-to-1 relationship;
1099: */
1100:
1101: bdev_file = bdev_file_open_by_dev(sbi->logdev,
1102: BLK_OPEN_READ | BLK_OPEN_WRITE, log, NULL);
1103: if (IS_ERR(bdev_file)) {
1104: rc = PTR_ERR(bdev_file);
1105: goto free;
1106: }
1107:
1108: log->bdev_file = bdev_file;
1109: uuid_copy(&log->uuid, &sbi->loguuid);
1110:
1111: /*
1112: * initialize log:
1113: */
1114: if ((rc = lmLogInit(log)))
1115: goto close;
1116:
1117: list_add(&log->journal_list, &jfs_external_logs);
1118:
1119: /*
1120: * add file system to log active file system list
1121: */
1122: if ((rc = lmLogFileSystem(log, sbi, 1)))
1123: goto shutdown;
1124:
1125: journal_found:
1126: LOG_LOCK(log);
1127: list_add(&sbi->log_list, &log->sb_list);
1128: sbi->log = log;
1129: LOG_UNLOCK(log);
1130:
1131: mutex_unlock(&jfs_log_mutex);
1132: return 0;
1133:
1134: /*
1135: * unwind on error
1136: */
1137: shutdown: /* unwind lbmLogInit() */
1138: list_del(&log->journal_list);
1139: lbmLogShutdown(log);
1140:
1141: close: /* close external log device */
1142: bdev_fput(bdev_file);
1143:
1144: free: /* free log descriptor */
1145: mutex_unlock(&jfs_log_mutex);
1146: kfree(log);
1147:
1148: jfs_warn("lmLogOpen: exit(%d)", rc);
1149: return rc;
1150: }
SourceFile:fs/jfs/jfs_logmgr.c]
|
| 64/2 |
2026/05/11 23:40 |
llm |
debugger |
0m
Model:
Tokens:
input: 170044
output: 49
thoughts: 1664
Thoughts: **Ensuring Safe Journal Closure During Unmount**
Okay, so we need to be careful when unmounting the JFS filesystem, especially regarding how we handle the shared external logs. The goal is to avoid a crash when `txLazyCommit` tries to access a log that has already been deallocated. I need to make sure I don't set `sbi->log = NULL` until *all* transactions for this specific superblock (`sb`) have finished.
The initial thought was to wait for `log->active` to hit zero in `lmLogClose`, but that's not enough because the log might still be in use by other superblocks (`sbi`s). The critical thing is that if `list_empty(&log->sb_list)` is false, it means another `sbi` is still using this `log`. In that case we don't free `log`.
So, the key is understanding how `txLazyCommit` accesses the log through `JFS_SBI(tblk->sb)->log`. If we null out `sbi->log` before lazy commit is done, we'll get a null pointer dereference. Therefore, even if the `log` isn't freed right away, we *must* wait for all transactions associated with *this* `sbi` to be completed before setting `sbi->log = NULL`. We can't rely solely on `log->active == 0`. We need to use other information in the `sbi`.
To do this, I need to check:
1. That there are no `tblk` structures for *this* `sbi` in `TxAnchor.unlock_queue`. This means we are waiting for transactions of this `sbi` that are queued to unlock.
2. That `sbi->commit_state` does not have the `IN_LAZYCOMMIT` flag set. That means lazy commit is not processing transactions for this `sbi`.
If both conditions are true, we know all transactions using this superblock have finished being processed.
Therefore, I can implement a loop in `jfs_umount` (or a function called from it) that waits for these conditions. I can put the code in `jfs_umount` after the `jfs_flush_journal` call. I can introduce a helper function called `txLazyWait()` inside `jfs_txnmgr.c`. I can implement the function as follows:
```c
void txLazyWait(struct super_block *sb)
{
struct jfs_sb_info *sbi = JFS_SBI(sb);
unsigned long flags;
struct tblock *tblk;
int found;
do {
found = 0;
LAZY_LOCK(flags);
if (sbi->commit_state & IN_LAZYCOMMIT)
found = 1;
else {
list_for_each_entry(tblk, &TxAnchor.unlock_queue, cqueue) {
if (tblk->sb == sb) {
found = 1;
break;
}
}
}
LAZY_UNLOCK(flags);
if (found)
msleep(10); // or yield()
} while (found);
}
```
Wait, are there other places a `tblk` can be? `TxAnchor.anon_list` and `TxAnchor.anon_list2`! But `txQuiesce` processes those lists, and that's not called by `jfs_umount`. However, `jfs_umount` is called after `vfs_umount`, which calls `sync_filesystem` and `evict_inodes`, meaning any anonymous transactions *should* be committed. Given that `jfs_put_super` calls `jfs_umount`, and `generic_shutdown_super` calls `sync_filesystem` and `evict_inodes` before `jfs_put_super` is called, no anonymous transactions should exist. Just in case, could `txQuiesce(sb)` be called? No, it's for freezing.
OK, back to the core logic. `jfs_flush_journal` ensures that the `log->cqueue` and `log->synclist` are empty. Then, by calling `txLazyWait(sb)`, it ensures that all transactions for *this* superblock are processed.
Now, let's trace this. When does `txLazyCommit` clear `IN_LAZYCOMMIT`? It's done *after* calling `txLazyCommit(tblk)` using the `LAZY_UNLOCK` and `LAZY_LOCK` macros.
|
| 65/2 |
2026/05/11 23:40 |
tool |
codesearch-find-references |
0m
Error: requested entity does not exist
Args: map[ContextFile:fs/jfs/super.c IncludeSnippetLines:0 Name:jfsIOthread SourceTreePrefix:]
Results: map[References:<nil> TruncatedOutput:false]
|
| 66/2 |
2026/05/11 23:40 |
llm |
debugger |
0m
Model:
Tokens:
input: 172803
output: 18
thoughts: 20
Thoughts: Here's my summary, as though I'm thinking these thoughts:
**Investigating a Global Variable**
Okay, so I see this `jfsIOthread` variable. Hmm, it's global, which always piques my interest. I need to understand its scope and usage within the system. Let's see... the most efficient way to get a quick overview of where it's being used would be a quick grep. Let's see what turns up.
|
| 67/2 |
2026/05/11 23:40 |
tool |
grepper |
0m
Args: map[Expression:jfsIOthread]
Results: map[Output:fs/jfs/jfs_logmgr.c=1943=static inline void lbmRedrive(struct lbuf *bp)
--
fs/jfs/jfs_logmgr.c-1951-
fs/jfs/jfs_logmgr.c:1952: wake_up_process(jfsIOthread);
fs/jfs/jfs_logmgr.c-1953-}
--
fs/jfs/jfs_superblock.h=104=extern int jfs_extendfs(struct super_block *, s64, int);
fs/jfs/jfs_superblock.h-105-
fs/jfs/jfs_superblock.h:106:extern struct task_struct *jfsIOthread;
fs/jfs/jfs_superblock.h-107-extern struct task_struct *jfsSyncThread;
--
fs/jfs/super.c=52=static struct task_struct *jfsCommitThread[MAX_COMMIT_THREADS];
fs/jfs/super.c:53:struct task_struct *jfsIOthread;
fs/jfs/super.c-54-struct task_struct *jfsSyncThread;
--
fs/jfs/super.c=951=static int __init init_jfs_fs(void)
--
fs/jfs/super.c-985- */
fs/jfs/super.c:986: jfsIOthread = kthread_run(jfsIOWait, NULL, "jfsIO");
fs/jfs/super.c:987: if (IS_ERR(jfsIOthread)) {
fs/jfs/super.c:988: rc = PTR_ERR(jfsIOthread);
fs/jfs/super.c-989- jfs_err("init_jfs_fs: fork failed w/rc = %d", rc);
--
fs/jfs/super.c-1030- kthread_stop(jfsCommitThread[i]);
fs/jfs/super.c:1031: kthread_stop(jfsIOthread);
fs/jfs/super.c-1032-end_txmngr:
--
fs/jfs/super.c=1041=static void __exit exit_jfs_fs(void)
--
fs/jfs/super.c-1049-
fs/jfs/super.c:1050: kthread_stop(jfsIOthread);
fs/jfs/super.c-1051- for (i = 0; i < commit_threads; i++)
]
|
| 68/2 |
2026/05/11 23:40 |
llm |
debugger |
2m
Model:
Tokens:
input: 173603
output: 46
thoughts: 23
Thoughts: Okay, here's my interpretation of that thought process, assuming I'm deep in the weeds of kernel-level I/O analysis:
**Diving into the `jfsIOWait` Function**
Right, `jfsIOWait`. That immediately clicks as the function associated with the `jfsIOthread` β makes sense, the I/O thread is likely going to spend a good chunk of its time *waiting* for things to happen. Let me get a look at the code for `jfsIOWait`. I need to understand what's actually blocking this thread. Is it disk I/O directly? Are we waiting on a lock held by another process? Is it some internal JFS resource contention? Understanding the specifics of `jfsIOWait` is critical to identifying potential bottlenecks or performance issues in the JFS filesystem implementation itself. Time to roll up my sleeves and see what's really going on in there.
|
| 69/2 |
2026/05/11 23:42 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:fs/jfs/jfs_logmgr.c IncludeLines:true Name:jfsIOWait]
Results: map[SourceCode:2304: int jfsIOWait(void *arg)
2305: {
2306: struct lbuf *bp;
2307:
2308: set_freezable();
2309: do {
2310: spin_lock_irq(&log_redrive_lock);
2311: while ((bp = log_redrive_list)) {
2312: log_redrive_list = bp->l_redrive_next;
2313: bp->l_redrive_next = NULL;
2314: spin_unlock_irq(&log_redrive_lock);
2315: lbmStartIO(bp);
2316: spin_lock_irq(&log_redrive_lock);
2317: }
2318:
2319: if (freezing(current)) {
2320: spin_unlock_irq(&log_redrive_lock);
2321: try_to_freeze();
2322: } else {
2323: set_current_state(TASK_INTERRUPTIBLE);
2324: spin_unlock_irq(&log_redrive_lock);
2325: schedule();
2326: }
2327: } while (!kthread_should_stop());
2328:
2329: jfs_info("jfsIOWait being killed!");
2330: return 0;
2331: }
SourceFile:fs/jfs/jfs_logmgr.c]
|
| 70/2 |
2026/05/11 23:42 |
llm |
debugger |
0m
Model:
Tokens:
input: 174306
output: 45
thoughts: 121
Thoughts: **Analyzing a Potential Race Condition in the `jfsIOWait` Function**
Okay, so `jfsIOWait` is chugging away, processing this `log_redrive_list`. That list is filled with `lbuf`s, which is where things get interesting. I know that `lbmStartIO` is grabbing access to `bp->l_log`. My immediate concern is, if that `bp->l_log` gets freed while `lbmStartIO` is in the middle of accessing it, we're going to have a classic crash on our hands.
The next thought is to consider the implications of `lmLogShutdown`. It calls `lbmLogShutdown(log)`, which *should* free all the `lbuf`s associated with a particular `log`. But, wait a minute, I seem to recall `lbmLogShutdown` is designed to wait for all outstanding I/O operations to complete, which would include any operations started by `lbmStartIO`. This is the crucial point! That indicates the freeing of the lbuf occurs AFTER all associated I/O completes.
To be absolutely sure, I'm going to dig into the source code for `lbmLogShutdown` to confirm this assumption. Let's see how they synchronize things.
|
| 71/2 |
2026/05/11 23:42 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:fs/jfs/jfs_logmgr.c IncludeLines:true Name:lbmLogShutdown]
Results: map[SourceCode:1847: /*
1848: * lbmLogShutdown()
1849: *
1850: * finalize per log I/O setup at lmLogShutdown()
1851: */
1852: static void lbmLogShutdown(struct jfs_log * log)
1853: {
1854: struct lbuf *lbuf;
1855:
1856: jfs_info("lbmLogShutdown: log:0x%p", log);
1857:
1858: lbuf = log->lbuf_free;
1859: while (lbuf) {
1860: struct lbuf *next = lbuf->l_freelist;
1861: __free_page(lbuf->l_page);
1862: kfree(lbuf);
1863: lbuf = next;
1864: }
1865: }
SourceFile:fs/jfs/jfs_logmgr.c]
|
| 72/2 |
2026/05/11 23:42 |
llm |
debugger |
0m
Model:
Tokens:
input: 175033
output: 46
thoughts: 621
Thoughts: **My Analysis of the Log Shutdown Sequence**
Okay, let me think this through. `lbmLogShutdown` just releases the memory allocated to the log buffer free list (`log->lbuf_free`). My immediate concern is, what if there are still log buffers (`lbuf`s) pending in the `log_redrive_list` at that point? The execution flow is: `lmLogShutdown` is called *after* `jfs_flush_journal(log, 2)`. I know that `jfs_flush_journal` does wait for the commit queue (`cqueue`) and the synchronous list (`synclist`) to be empty. However, it *doesn't* explicitly wait for the `log_redrive_list` to be empty.
But wait, `lbmStartIO` is called by `jfsIOWait`. If `jfs_flush_journal` waits for *all* transactions to complete, then all I/O, including that from the `log_redrive_list`, *should* have finished, right? Yes, that makes sense because the flush routine empties `cqueue` and `synclist`.
Hold on, I see a potential issue. `lbmIOWait` *is* called inside `lmLogShutdown` itself:
```c
lsn = lmWriteRecord(log, NULL, &lrd, NULL);
bp = log->bp;
lp = (struct logpage *) bp->l_ldata;
lp->h.eor = lp->t.eor = cpu_to_le16(bp->l_eor);
lbmWrite(log, log->bp, lbmWRITE | lbmRELEASE | lbmSYNC, 0);
lbmIOWait(log->bp, lbmFREE);
log->bp = NULL;
/*
* synchronous update log superblock
* mark log state as shutdown cleanly
* (i.e., Log does not need to be replayed).
*/
if ((rc = lbmRead(log, 1, &bpsuper)))
goto out;
logsuper = (struct logsuper *) bpsuper->l_ldata;
logsuper->state = cpu_to_le32(LOGREDONE);
logsuper->end = cpu_to_le32(lsn);
lbmDirectWrite(log, bpsuper, lbmWRITE | lbmRELEASE | lbmSYNC);
rc = lbmIOWait(bpsuper, lbmFREE);
```
So `lmLogShutdown` itself *does* perform synchronous I/O and *waits* for completion. By the time `lmLogShutdown` returns, all I/O associated with the relevant `log` *should* be finished. This should mean the `log_redrive_list` should be empty for that `log`.
The remaining problem, then, is `jfs_lazycommit` potentially accessing the `log` structure after it has been freed. The resolution lies in ensuring that `jfs_lazycommit` processes all transactions relevant to a given superblock (`sb`) *before* the `log` is freed. Aha! Wait, what about `jfs_syncThread`? We need to also check the interactions with that thread. Let's dig into that code path.
|
| 73/2 |
2026/05/11 23:43 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:fs/jfs/jfs_txnmgr.c IncludeLines:true Name:jfs_sync]
Results: map[SourceCode:2877: /*
2878: * jfs_sync(void)
2879: *
2880: * To be run as a kernel daemon. This is awakened when tlocks run low.
2881: * We write any inodes that have anonymous tlocks so they will become
2882: * available.
2883: */
2884: int jfs_sync(void *arg)
2885: {
2886: struct inode *ip;
2887: struct jfs_inode_info *jfs_ip;
2888: tid_t tid;
2889:
2890: set_freezable();
2891: do {
2892: /*
2893: * write each inode on the anonymous inode list
2894: */
2895: TXN_LOCK();
2896: while (jfs_tlocks_low && !list_empty(&TxAnchor.anon_list)) {
2897: jfs_ip = list_entry(TxAnchor.anon_list.next,
2898: struct jfs_inode_info,
2899: anon_inode_list);
2900: ip = &jfs_ip->vfs_inode;
2901:
2902: if (! igrab(ip)) {
2903: /*
2904: * Inode is being freed
2905: */
2906: list_del_init(&jfs_ip->anon_inode_list);
2907: } else if (mutex_trylock(&jfs_ip->commit_mutex)) {
2908: /*
2909: * inode will be removed from anonymous list
2910: * when it is committed
2911: */
2912: TXN_UNLOCK();
2913: tid = txBegin(ip->i_sb, COMMIT_INODE);
2914: txCommit(tid, 1, &ip, 0);
2915: txEnd(tid);
2916: mutex_unlock(&jfs_ip->commit_mutex);
2917:
2918: iput(ip);
2919: /*
2920: * Just to be safe. I don't know how
2921: * long we can run without blocking
2922: */
2923: cond_resched();
2924: TXN_LOCK();
2925: } else {
2926: /* We can't get the commit mutex. It may
2927: * be held by a thread waiting for tlock's
2928: * so let's not block here. Save it to
2929: * put back on the anon_list.
2930: */
2931:
2932: /* Move from anon_list to anon_list2 */
2933: list_move(&jfs_ip->anon_inode_list,
2934: &TxAnchor.anon_list2);
2935:
2936: TXN_UNLOCK();
2937: iput(ip);
2938: TXN_LOCK();
2939: }
2940: }
2941: /* Add anon_list2 back to anon_list */
2942: list_splice_init(&TxAnchor.anon_list2, &TxAnchor.anon_list);
2943:
2944: if (freezing(current)) {
2945: TXN_UNLOCK();
2946: try_to_freeze();
2947: } else {
2948: set_current_state(TASK_INTERRUPTIBLE);
2949: TXN_UNLOCK();
2950: schedule();
2951: }
2952: } while (!kthread_should_stop());
2953:
2954: jfs_info("jfs_sync being killed");
2955: return 0;
2956: }
SourceFile:fs/jfs/jfs_txnmgr.c]
|
| 74/2 |
2026/05/11 23:43 |
llm |
debugger |
1m
Model:
Tokens:
input: 177573
output: 44
thoughts: 555
Thoughts: **Analyzing the jfs Unmount Process**
Okay, let me think this through. `jfs_sync` is iterating through `TxAnchor.anon_list`. We know it's using `txBegin`, `txCommit`, `txEnd`. My concern here is when we're unmounting. If `jfs_sync` *were* processing an inode belonging to the superblock (`sb`) that's being unmounted, it would access the `log`. But, based on how `jfs_umount` is supposed to work, all the inodes *should* already be evicted. So, `anon_list` shouldn't have any inodes tied to this superblock.
Hold on, I see something. `jfs_sync` is grabbing the inode with `igrab(ip)`. If `igrab` *fails*, the inode is removed from `anon_list`. If `igrab` *succeeds*, that means the inode is *not* fully evicted yet! But `vfs_umount` is supposed to wait until *all* inodes are evicted, so that shouldn't happen. Therefore, `jfs_sync` shouldn't be dealing with any inodes specific to this superblock.
Alright, that leaves `jfs_lazycommit` as the potential culprit. To resolve this, what if we introduce a function, `txLazyWait(sb)`, in `jfs_txnmgr.c`? We could call this from `jfs_umount` after `jfs_flush_journal(log, 2)`. But wait, doesn't `jfs_flush_journal` also get called from `lmLogShutdown`? If `lmLogShutdown` is called from `lmLogClose`, then we could simply call `txLazyWait(sb)` within `jfs_umount` *before* `lmLogClose`.
Let me look at `jfs_umount` code... Okay, here's what I see:
```c
if ((log = sbi->log))
/*
* Wait for outstanding transactions to be written to log:
*/
jfs_flush_journal(log, 2);
/*
* Hold log lock so write_special_inodes (lmLogSync) cannot see
* this sbi with a NULL inode pointer while iterating log->sb_list.
*/
if (log)
LOG_LOCK(log);
```
So, if we add `txLazyWait(sb)` here:
```c
if ((log = sbi->log)) {
/*
* Wait for outstanding transactions to be written to log:
*/
jfs_flush_journal(log, 2);
txLazyWait(sb);
}
```
That looks like it will work. Now, I need to make sure `txLazyWait` is properly declared, right? Which header file makes sense? `jfs_txnmgr.h`? Yes, I'll need to check `jfs_txnmgr.h` to see if that's the correct place for the declaration.
|
| 75/2 |
2026/05/11 23:44 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:fs/jfs/jfs_txnmgr.h IncludeLines:true Name:txBegin]
Results: map[SourceCode: 337: /*
338: * NAME: txBegin()
339: *
340: * FUNCTION: start a transaction.
341: *
342: * PARAMETER: sb - superblock
343: * flag - force for nested tx;
344: *
345: * RETURN: tid - transaction id
346: *
347: * note: flag force allows to start tx for nested tx
348: * to prevent deadlock on logsync barrier;
349: */
350: tid_t txBegin(struct super_block *sb, int flag)
351: {
352: tid_t t;
353: struct tblock *tblk;
354: struct jfs_log *log;
355:
356: jfs_info("txBegin: flag = 0x%x", flag);
357: log = JFS_SBI(sb)->log;
358:
359: if (!log) {
360: jfs_error(sb, "read-only filesystem\n");
361: return 0;
362: }
363:
364: TXN_LOCK();
365:
366: INCREMENT(TxStat.txBegin);
367:
368: retry:
369: if (!(flag & COMMIT_FORCE)) {
370: /*
371: * synchronize with logsync barrier
372: */
373: if (test_bit(log_SYNCBARRIER, &log->flag) ||
374: test_bit(log_QUIESCE, &log->flag)) {
375: INCREMENT(TxStat.txBegin_barrier);
376: TXN_SLEEP(&log->syncwait);
377: goto retry;
378: }
379: }
380: if (flag == 0) {
381: /*
382: * Don't begin transaction if we're getting starved for tlocks
383: * unless COMMIT_FORCE or COMMIT_INODE (which may ultimately
384: * free tlocks)
385: */
386: if (TxAnchor.tlocksInUse > TxLockVHWM) {
387: INCREMENT(TxStat.txBegin_lockslow);
388: TXN_SLEEP(&TxAnchor.lowlockwait);
389: goto retry;
390: }
391: }
392:
393: /*
394: * allocate transaction id/block
395: */
396: if ((t = TxAnchor.freetid) == 0) {
397: jfs_info("txBegin: waiting for free tid");
398: INCREMENT(TxStat.txBegin_freetid);
399: TXN_SLEEP(&TxAnchor.freewait);
400: goto retry;
401: }
402:
403: tblk = tid_to_tblock(t);
404:
405: if ((tblk->next == 0) && !(flag & COMMIT_FORCE)) {
406: /* Don't let a non-forced transaction take the last tblk */
407: jfs_info("txBegin: waiting for free tid");
408: INCREMENT(TxStat.txBegin_freetid);
409: TXN_SLEEP(&TxAnchor.freewait);
410: goto retry;
411: }
412:
413: TxAnchor.freetid = tblk->next;
414:
415: /*
416: * initialize transaction
417: */
418:
419: /*
420: * We can't zero the whole thing or we screw up another thread being
421: * awakened after sleeping on tblk->waitor
422: *
423: * memset(tblk, 0, sizeof(struct tblock));
424: */
425: tblk->next = tblk->last = tblk->xflag = tblk->flag = tblk->lsn = 0;
426:
427: tblk->sb = sb;
428: ++log->logtid;
429: tblk->logtid = log->logtid;
430:
431: ++log->active;
432:
433: HIGHWATERMARK(stattx.maxtid, t); /* statistics */
434: INCREMENT(stattx.ntid); /* statistics */
435:
436: TXN_UNLOCK();
437:
438: jfs_info("txBegin: returning tid = %d", t);
439:
440: return t;
441: }
SourceFile:fs/jfs/jfs_txnmgr.c]
|
| 76/2 |
2026/05/11 23:44 |
llm |
debugger |
0m
Model:
Tokens:
input: 180298
output: 44
thoughts: 37
Thoughts: Here's my take:
**A Quick Code Navigation Blip**
Okay, I was just looking through `jfs_txnmgr.h` trying to refresh my memory on the transaction management structure in JFS, when I realized something. I went straight for the header file, assuming I'd find the definition for `txBegin` there, as a starting point. But, hold on a second... `txBegin` is *actually* defined in `fs/jfs/jfs_txnmgr.c`, not the header. Thatβs a bit unusual β I should have paid closer attention to the implementation file path, I sometimes forget where certain functions are defined within the module. Alright, let's head back and examine the source. I need to be more mindful of where Iβm looking next time.
|
| 77/2 |
2026/05/11 23:44 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:fs/jfs/jfs_txnmgr.h IncludeLines:true Name:txBegin]
Results: map[SourceCode: 337: /*
338: * NAME: txBegin()
339: *
340: * FUNCTION: start a transaction.
341: *
342: * PARAMETER: sb - superblock
343: * flag - force for nested tx;
344: *
345: * RETURN: tid - transaction id
346: *
347: * note: flag force allows to start tx for nested tx
348: * to prevent deadlock on logsync barrier;
349: */
350: tid_t txBegin(struct super_block *sb, int flag)
351: {
352: tid_t t;
353: struct tblock *tblk;
354: struct jfs_log *log;
355:
356: jfs_info("txBegin: flag = 0x%x", flag);
357: log = JFS_SBI(sb)->log;
358:
359: if (!log) {
360: jfs_error(sb, "read-only filesystem\n");
361: return 0;
362: }
363:
364: TXN_LOCK();
365:
366: INCREMENT(TxStat.txBegin);
367:
368: retry:
369: if (!(flag & COMMIT_FORCE)) {
370: /*
371: * synchronize with logsync barrier
372: */
373: if (test_bit(log_SYNCBARRIER, &log->flag) ||
374: test_bit(log_QUIESCE, &log->flag)) {
375: INCREMENT(TxStat.txBegin_barrier);
376: TXN_SLEEP(&log->syncwait);
377: goto retry;
378: }
379: }
380: if (flag == 0) {
381: /*
382: * Don't begin transaction if we're getting starved for tlocks
383: * unless COMMIT_FORCE or COMMIT_INODE (which may ultimately
384: * free tlocks)
385: */
386: if (TxAnchor.tlocksInUse > TxLockVHWM) {
387: INCREMENT(TxStat.txBegin_lockslow);
388: TXN_SLEEP(&TxAnchor.lowlockwait);
389: goto retry;
390: }
391: }
392:
393: /*
394: * allocate transaction id/block
395: */
396: if ((t = TxAnchor.freetid) == 0) {
397: jfs_info("txBegin: waiting for free tid");
398: INCREMENT(TxStat.txBegin_freetid);
399: TXN_SLEEP(&TxAnchor.freewait);
400: goto retry;
401: }
402:
403: tblk = tid_to_tblock(t);
404:
405: if ((tblk->next == 0) && !(flag & COMMIT_FORCE)) {
406: /* Don't let a non-forced transaction take the last tblk */
407: jfs_info("txBegin: waiting for free tid");
408: INCREMENT(TxStat.txBegin_freetid);
409: TXN_SLEEP(&TxAnchor.freewait);
410: goto retry;
411: }
412:
413: TxAnchor.freetid = tblk->next;
414:
415: /*
416: * initialize transaction
417: */
418:
419: /*
420: * We can't zero the whole thing or we screw up another thread being
421: * awakened after sleeping on tblk->waitor
422: *
423: * memset(tblk, 0, sizeof(struct tblock));
424: */
425: tblk->next = tblk->last = tblk->xflag = tblk->flag = tblk->lsn = 0;
426:
427: tblk->sb = sb;
428: ++log->logtid;
429: tblk->logtid = log->logtid;
430:
431: ++log->active;
432:
433: HIGHWATERMARK(stattx.maxtid, t); /* statistics */
434: INCREMENT(stattx.ntid); /* statistics */
435:
436: TXN_UNLOCK();
437:
438: jfs_info("txBegin: returning tid = %d", t);
439:
440: return t;
441: }
SourceFile:fs/jfs/jfs_txnmgr.c]
|
| 78/2 |
2026/05/11 23:44 |
llm |
debugger |
0m
Model:
Tokens:
input: 181997
output: 20
thoughts: 44
Thoughts: Okay, here's my summary, taking on the persona you've described:
**Navigating the JFS Transaction Manager**
Alright, let's see... I'm looking at this JFS code, specifically the transaction manager. I need to understand how transactions are initiated and managed. The note here says `txBegin` is located in `fs/jfs/jfs_txnmgr.c`. Okay, that's the implementation. Now I need the *interface*. I want to understand what this `txBegin` function actually does, what parameters it takes, and how it interacts with the rest of the system. Let's get the header file: `jfs_txnmgr.h`. That's where the function declarations and relevant data structures should be. That's the key - figuring out which functions are exported and what their purpose is. From the header file I'll get the prototypes for txBegin and other related functions. Let's see what we find.
|
| 79/2 |
2026/05/11 23:44 |
tool |
grepper |
0m
Args: map[Expression:extern void txQuiesce]
Results: map[Output:fs/jfs/jfs_txnmgr.h=291=extern int lmLog(struct jfs_log *, struct tblock *, struct lrd *,
fs/jfs/jfs_txnmgr.h-292- struct tlock *);
fs/jfs/jfs_txnmgr.h:293:extern void txQuiesce(struct super_block *);
fs/jfs/jfs_txnmgr.h-294-extern void txResume(struct super_block *);
]
|
| 80/2 |
2026/05/11 23:44 |
llm |
debugger |
1m
Model:
Tokens:
input: 182404
output: 17
thoughts: 1181
Thoughts: **Refining the Lazy Commit Wait Mechanism**
Okay, so I'm aiming to add a wait function to ensure the lazy commit process is done before unmounting the JFS filesystem. The current strategy is to wait in `jfs_umount` after flushing the journal.
First, the function `txQuiesce` is already exported in `jfs_txnmgr.h`. I can add a new function called `txLazyCommitWait` to `jfs_txnmgr.h` and implement it in `jfs_txnmgr.c`. It looks like the `sbi->log` pointer isn't set to `NULL` anywhere else, so that seems clean.
Here's my initial implementation of `txLazyCommitWait` in `jfs_txnmgr.c`:
```c
void txLazyCommitWait(struct super_block *sb)
{
struct jfs_sb_info *sbi = JFS_SBI(sb);
unsigned long flags;
struct tblock *tblk;
int found;
do {
found = 0;
LAZY_LOCK(flags);
if (sbi->commit_state & IN_LAZYCOMMIT)
found = 1;
else {
list_for_each_entry(tblk, &TxAnchor.unlock_queue, cqueue) {
if (tblk->sb == sb) {
found = 1;
break;
}
}
}
LAZY_UNLOCK(flags);
if (found)
msleep(10);
} while (found);
}
```
Now, what if `jfs_lazycommit` is busy with a transaction on this `sb` and it blocks within `txLazyCommit`? This loop and `msleep` will handle it correctly, sleeping and retrying. Similarly, since `txLazyCommit` calls `txUpdateMap` which may also block, the loop within `txLazyCommitWait` will allow the system to proceed correctly. I'm reasonably sure there won't be deadlock. Specifically, `txLazyCommitWait` is called in `jfs_umount`, which holds `s_umount`. But `jfs_lazycommit` does *not* take `s_umount`, so the conditions for deadlock are not present.
The other thing that comes to mind is to consider other possible mechanisms to wait for `jfs_lazycommit`. `jfs_flush_journal` has a loop, so perhaps I could use that? No, it makes more sense to add the wait *after* flushing.
My plan is to add `txLazyCommitWait(sb)` in `jfs_umount` after `jfs_flush_journal(log, 2)`. I just need to make sure I declare it. So, let's add the declaration in `jfs_txnmgr.h`:
```c
extern void txLazyCommitWait(struct super_block *sb);
```
I also need to verify this change works for read-write umount operations as well, so I'll check `jfs_umount_rw`.
It does! `jfs_umount_rw` also calls `jfs_flush_journal(log, 2)`. So, the necessary changes will apply here as well:
```c
jfs_flush_journal(log, 2);
txLazyCommitWait(sb);
return lmLogClose(sb);
```
Finally, is the naming of `txLazyCommitWait` ideal? Perhaps it would be better named as something like `jfs_lazycommit_wait`? No, `txLazyCommitWait` is fine, or `jfs_tx_lazycommit_wait`.
Now, I need to make sure that `lmLogClose` isn't called from anywhere else. Let's grep for that.
|
| 81/2 |
2026/05/11 23:45 |
tool |
grepper |
0m
Args: map[Expression:lmLogClose]
Results: map[Output:fs/jfs/jfs_logmgr.c=1237=int lmLogInit(struct jfs_log * log)
--
fs/jfs/jfs_logmgr.c-1420-/*
fs/jfs/jfs_logmgr.c:1421: * NAME: lmLogClose()
fs/jfs/jfs_logmgr.c-1422- *
--
fs/jfs/jfs_logmgr.c-1431- */
fs/jfs/jfs_logmgr.c:1432:int lmLogClose(struct super_block *sb)
fs/jfs/jfs_logmgr.c-1433-{
--
fs/jfs/jfs_logmgr.c-1438-
fs/jfs/jfs_logmgr.c:1439: jfs_info("lmLogClose: log:0x%p", log);
fs/jfs/jfs_logmgr.c-1440-
--
fs/jfs/jfs_logmgr.c-1490- mutex_unlock(&jfs_log_mutex);
fs/jfs/jfs_logmgr.c:1491: jfs_info("lmLogClose: exit(%d)", rc);
fs/jfs/jfs_logmgr.c-1492- return rc;
--
fs/jfs/jfs_logmgr.h=497=extern int lmLogOpen(struct super_block *sb);
fs/jfs/jfs_logmgr.h:498:extern int lmLogClose(struct super_block *sb);
fs/jfs/jfs_logmgr.h-499-extern int lmLogShutdown(struct jfs_log * log);
--
fs/jfs/jfs_mount.c=221=int jfs_mount_rw(struct super_block *sb, int remount)
--
fs/jfs/jfs_mount.c-264- jfs_err("jfs_mount: updateSuper failed w/rc = %d", rc);
fs/jfs/jfs_mount.c:265: lmLogClose(sb);
fs/jfs/jfs_mount.c-266- return rc;
--
fs/jfs/jfs_umount.c=38=int jfs_umount(struct super_block *sb)
--
fs/jfs/jfs_umount.c-123- */
fs/jfs/jfs_umount.c:124: rc = lmLogClose(sb);
fs/jfs/jfs_umount.c-125- }
--
fs/jfs/jfs_umount.c=131=int jfs_umount_rw(struct super_block *sb)
--
fs/jfs/jfs_umount.c-161-
fs/jfs/jfs_umount.c:162: return lmLogClose(sb);
fs/jfs/jfs_umount.c-163-}
]
|
| 82/2 |
2026/05/11 23:45 |
llm |
debugger |
0m
Model:
Tokens:
input: 185244
output: 25
thoughts: 3217
Thoughts: **Refining the Journal Flush and Lazy Commit Synchronization**
Okay, so I've been wrestling with a potential race condition related to journal flushes and the lazy commit mechanism in JFS. The initial problem was straightforward: we want to ensure that `lmLogClose` doesn't proceed to nullify the log structure (`sbi->log = NULL`) until all transactions associated with that superblock have been fully processed. The idea of introducing `txLazyCommitWait` at the start of `lmLogClose` seemed elegant at first, as it would block until all pending lazy commits were complete. The initial implementation seemed to address the problem correctly in the usual cases of remount and unmount.
However, a closer look at `lmPostGC` within the I/O path, which is called after commit records are written to disk, revealed a potential vulnerability. It calls `txLazyUnlock` and adds blocks to the `unlock_queue`. Specifically, if `jfs_flush_journal` returns, it means the `log->cqueue` is empty. However, `lmPostGC` could still be running, have removed a transaction from `log->cqueue` (protected by `log->gclock`), but it hadn't yet added the corresponding block to `unlock_queue` or called `txLazyUnlock`. If `txLazyCommitWait` then executes, it might see no pending transactions or commit activity, return, and allow `lmLogClose` to proceed with resetting `sbi->log = NULL`. Subsequently, `lmPostGC` completes by calling `txLazyUnlock` which adds transaction to `unlock_queue`. Then `jfs_lazycommit` tries to process it, and it will try to access the now-NULL `sbi->log` pointer, and boom, we have a crash!
The fix, therefore, is to synchronize the two paths: `jfs_flush_journal` and `lmPostGC`. Since `lmPostGC` removes entries from `log->cqueue` and then adds them to `unlock_queue` all within the same `log->gclock` critical section, it's safe to introduce a spinlock operation on `log->gclock` within `txLazyCommitWait`, before any checking of `commit_state` or `unlock_queue`. Specifically, the enhanced `txLazyCommitWait` does the following: it first takes and immediately releases `log->gclock` to ensure that any `lmPostGC` that was in progress has finished with its critical section. After taking `log->gclock`, and after having made sure we have proper synchronization with `lmPostGC`, we can then check `unlock_queue` for this superblock and wait for the `IN_LAZYCOMMIT` flag to clear. This will ensure that we properly handle the case where `jfs_flush_journal` returns and then we see an addition to `unlock_queue`, resolving the race condition. This solution appears to be the most robust way to ensure that all transactions are processed before `lmLogClose` nullifies the log pointer.
|
| 83/2 |
2026/05/11 23:46 |
tool |
grepper |
0m
Args: map[Expression:#include "jfs_logmgr.h"]
Results: map[Output:fs/jfs/jfs_txnmgr.h-7-
fs/jfs/jfs_txnmgr.h:8:#include "jfs_logmgr.h"
fs/jfs/jfs_txnmgr.h-9-
--
fs/jfs/jfs_umount.c-22-#include "jfs_imap.h"
fs/jfs/jfs_umount.c:23:#include "jfs_logmgr.h"
fs/jfs/jfs_umount.c-24-#include "jfs_metapage.h"
]
|
| 84/2 |
2026/05/11 23:46 |
llm |
debugger |
1m
Model:
Tokens:
input: 189284
output: 44
thoughts: 652
Thoughts: **Analyzing Potential Deadlocks During Filesystem Unmount**
Okay, so I'm looking at this `jfs_txnmgr.h` code, and I see it includes `jfs_logmgr.h`, which is important because it means I can access `log->gclock`. The question is, how can I be sure that the unmount process will complete without blocking indefinitely?
My main concern revolves around `jfs_lazycommit` and how it interacts with the unmount sequence, specifically the handling of `tblk` structures. If `jfs_lazycommit` is currently dealing with a `tblk` for this superblock (`sb`), the `sbi->commit_state & IN_LAZYCOMMIT` flag will be set, and `txLazyCommitWait` could be looping and sleeping. The sleep introduces the *potential* for a deadlock, so I have to verify that `txLazyCommitWait` isn't holding any resources that `jfs_lazycommit` needs. It briefly takes `LAZY_LOCK`, but that's not held during sleep, which means `jfs_lazycommit` *should* be able to make progress.
I have to think through all the code paths. What if `txLazyCommit` subsequently calls `txUpdateMap`, which then calls `diWriteSpecial` or `dbWriteSpecial`? Those functions might block on I/O. However, they're not dependent on `jfs_umount` or `txLazyCommitWait`, so I assume they *will* eventually finish.
Now, where else could this `tblk` be? Another crucial location is `TxAnchor.anon_list`. Since `vfs_umount` calls `sync_filesystem` and `evict_inodes`, my assumption is that all inodes are evicted and anonymous transactions are committed. But I need to be 100% sure. I will double-check `TxAnchor.anon_list` and `TxAnchor.anon_list2` for this superblock. If an inode is present in either list, that means it has an anonymous transaction.
I'd have to use this code to perform this check:
```c
TXN_LOCK();
list_for_each_entry(jfs_ip, &TxAnchor.anon_list, anon_inode_list) {
if (jfs_ip->vfs_inode.i_sb == sb) {
found = 1;
break;
}
}
if (!found) {
list_for_each_entry(jfs_ip, &TxAnchor.anon_list2, anon_inode_list) {
if (jfs_ip->vfs_inode.i_sb == sb) {
found = 1;
break;
}
}
}
TXN_UNLOCK();
```
Wait a second. The `jfs_ip` is a `struct jfs_inode_info`. Is there a scenario where `jfs_umount` gets called *before* all anonymous transactions are cleared? This seems unlikely. `jfs_umount` sets `sb->s_root` to NULL, and the eviction process should clear out all the inodes from the filesystem. The key part is, when an inode is evicted, `jfs_evict_inode` is called. The question is, does `jfs_evict_inode` handle the committing of these anonymous transactions? I should probably check that to be absolutely certain.
|
| 85/2 |
2026/05/11 23:47 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:fs/jfs/inode.c IncludeLines:true Name:jfs_evict_inode]
Results: map[SourceCode: 145: void jfs_evict_inode(struct inode *inode)
146: {
147: struct jfs_inode_info *ji = JFS_IP(inode);
148:
149: jfs_info("In jfs_evict_inode, inode = 0x%p", inode);
150:
151: if (!inode->i_nlink && !is_bad_inode(inode)) {
152: dquot_initialize(inode);
153:
154: truncate_inode_pages_final(&inode->i_data);
155: if (JFS_IP(inode)->fileset == FILESYSTEM_I) {
156: struct inode *ipimap = JFS_SBI(inode->i_sb)->ipimap;
157:
158: if (test_cflag(COMMIT_Freewmap, inode))
159: jfs_free_zero_link(inode);
160:
161: if (ipimap && JFS_IP(ipimap)->i_imap)
162: diFree(inode);
163:
164: /*
165: * Free the inode from the quota allocation.
166: */
167: dquot_free_inode(inode);
168: }
169: } else {
170: truncate_inode_pages_final(&inode->i_data);
171: }
172: clear_inode(inode);
173: dquot_drop(inode);
174:
175: BUG_ON(!list_empty(&ji->anon_inode_list));
176:
177: spin_lock_irq(&ji->ag_lock);
178: if (ji->active_ag != -1) {
179: struct bmap *bmap = JFS_SBI(inode->i_sb)->bmap;
180: atomic_dec(&bmap->db_active[ji->active_ag]);
181: ji->active_ag = -1;
182: }
183: spin_unlock_irq(&ji->ag_lock);
184: }
SourceFile:fs/jfs/inode.c]
|
| 86/2 |
2026/05/11 23:47 |
llm |
debugger |
1m
Model:
Tokens:
input: 191393
output: 1302
thoughts: 7927
Thoughts: **Analysis of JFS Unmount Race Condition and Solution**
Okay, so here's the breakdown of the JFS unmount issue I've been wrestling with. The core problem boils down to a race condition during unmount, specifically related to how the lazy commit thread interacts with the unmount process.
It all starts in `jfs_umount` (and `jfs_umount_rw`). The standard unmount process calls `jfs_flush_journal` to ensure that all committed data is written to the journal. `jfs_flush_journal` correctly waits for the commit queue (`log->cqueue`) to be empty. However, and this is the crucial oversight, it *doesn't* wait for the *unlock queue* (`TxAnchor.unlock_queue`) to be empty or for the `jfs_lazycommit` process to finish processing those transactions. `lmPostGC` moves transactions from `cqueue` to `unlock_queue`.
This is where the race happens. After `jfs_flush_journal` returns (because `cqueue` is empty), `jfs_umount` proceeds to tear down various structures associated with the filesystem. In particular, it frees the inode maps (`sbi->ipimap`, `sbi->ipbmap`) and the `jfs_log` structure (through `lmLogClose` which sets `sbi->log = NULL`). Meanwhile, the `jfs_lazycommit` thread, which is responsible for committing lazy transactions, might still be running. If it wakes up after `jfs_umount` has freed these structures, it will try to access the freed memory, leading to a classic use-after-free (UAF) situation. This UAF shows up in a crash like this:
```
BUG: KASAN: slab-use-after-free in lmLogSync+0x9bb/0xa50 fs/jfs/jfs_logmgr.c:1003
Write of size 4 at addr ffff88804dbfaa18 by task jfsCommit/122
Call Trace:
lmLogSync+0x9bb/0xa50 fs/jfs/jfs_logmgr.c:1003
jfs_syncpt+0x7b/0x90 fs/jfs/jfs_logmgr.c:1039
txEnd+0x2e5/0x530 fs/jfs/jfs_txnmgr.c:551
txLazyCommit fs/jfs/jfs_txnmgr.c:2686 [inline]
jfs_lazycommit+0x5b8/0xaa0 fs/jfs/jfs_txnmgr.c:2735
```
The fix is straightforward in concept: we need a synchronization mechanism to ensure that `jfs_lazycommit` has completely finished with the specific superblock we're unmounting *before* we proceed with freeing its resources.
Here's my proposed solution:
1. Introduce a new function, `txLazyCommitWait(struct super_block *sb)`, in `fs/jfs/jfs_txnmgr.c`. This function will wait until *both* of the following conditions are met:
* The `IN_LAZYCOMMIT` flag in the superblock's commit state (`sbi->commit_state`) is cleared. This means no new transactions are being started for lazy commit.
* There are no transactions pending for the specific superblock in `TxAnchor.unlock_queue`.
To implement this, the function will need to iterate through the `unlock_queue` and check if any transaction blocks (`tblk`) are associated with the target `sb`. A simple `msleep(10)` will be enough to wait. We're on the unmount path, so performance is not critical.
2. Crucially, call `txLazyCommitWait(sb)` immediately *after* the `jfs_flush_journal(log, 2)` call in *both* `jfs_umount` and `jfs_umount_rw`. This places the synchronization point at the correct location: after the explicit journal flush but *before* we start freeing any shared resources.
```c
if ((log = sbi->log)) {
/*
* Wait for outstanding transactions to be written to log:
*/
jfs_flush_journal(log, 2);
txLazyCommitWait(sb);
}
```
```c
/*
* Note that we have to
|
| 87/1 |
2026/05/11 23:48 |
action |
kernel-scratch-checkouter |
0m
Results: map[KernelScratchSrc:/app/workdir/cache/tmp/tmp1202229781]
|
| 88/1 |
2026/05/11 23:49 |
loop |
|
32m
|
| 89/2 |
2026/05/11 23:49 |
iteration |
0 |
32m
|
| 90/3 |
2026/05/11 23:49 |
agent |
patch-generator |
5m
Model:
Instruction:
You are an experienced Linux kernel developer tasked with creating a fix for a kernel bug.
You will be given a crash report, and an initial explanation of the root cause done by another
kernel expert.
Use the codeeditor tool to do code edits.
Note: you will not see your changes when looking at the code using codesearch tools.
Your final reply should contain explanation of what you did in the patch and why
(details not present in the initial explanation of the bug).
Your fix must not just prevent the given crash, but also be the best fix for the underlying
root cause from the software engineering point of view. There can be several ways to fix the
same bug. Consider alternatives, and pick the best one. For example, additional checks may be
added at different locations/functions, it's usually better to place them earlier in the
execution to avoid multiple checks at various locations later.
Frequently the same coding mistake is done in several locations in the source code.
Check if your fix should be extended/applied to similar cases around to fix other similar bugs.
But don't go too wide, don't try to fix problems kernel-wide, fix similar issues
in the same file only.
If you are changing post-conditions of a function, consider all callers of the functions,
and if they need to be updated to handle new post-conditions. For example, if you make
a function that previously never returned a NULL, return NULL, consider if callers
need to be updated to handle NULL return value.
Prefer calling several tools at the same time to save round-trips.
Prompt:
The crash that corresponds to the bug is:
... Log Wrap ... Log Wrap ... Log Wrap ...
==================================================================
BUG: KASAN: slab-use-after-free in lmLogSync+0x9bb/0xa50 fs/jfs/jfs_logmgr.c:1003
Write of size 4 at addr ffff88804dbfaa18 by task jfsCommit/122
CPU: 1 UID: 0 PID: 122 Comm: jfsCommit Not tainted syzkaller #1 PREEMPT(full)
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
Call Trace:
<TASK>
dump_stack_lvl+0xe8/0x150 lib/dump_stack.c:120
print_address_description+0x55/0x1e0 mm/kasan/report.c:378
print_report+0x58/0x70 mm/kasan/report.c:482
kasan_report+0x117/0x150 mm/kasan/report.c:595
lmLogSync+0x9bb/0xa50 fs/jfs/jfs_logmgr.c:1003
jfs_syncpt+0x7b/0x90 fs/jfs/jfs_logmgr.c:1039
txEnd+0x2e5/0x530 fs/jfs/jfs_txnmgr.c:551
txLazyCommit fs/jfs/jfs_txnmgr.c:2686 [inline]
jfs_lazycommit+0x5b8/0xaa0 fs/jfs/jfs_txnmgr.c:2735
kthread+0x388/0x470 kernel/kthread.c:436
ret_from_fork+0x514/0xb70 arch/x86/kernel/process.c:158
ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245
</TASK>
Allocated by task 6683:
kasan_save_stack mm/kasan/common.c:57 [inline]
kasan_save_track+0x3e/0x80 mm/kasan/common.c:78
poison_kmalloc_redzone mm/kasan/common.c:398 [inline]
__kasan_kmalloc+0x93/0xb0 mm/kasan/common.c:415
kasan_kmalloc include/linux/kasan.h:263 [inline]
__kmalloc_cache_noprof+0x31c/0x660 mm/slub.c:5419
kmalloc_noprof include/linux/slab.h:950 [inline]
kzalloc_noprof include/linux/slab.h:1188 [inline]
open_inline_log fs/jfs/jfs_logmgr.c:1157 [inline]
lmLogOpen+0x2d1/0xfa0 fs/jfs/jfs_logmgr.c:1067
jfs_mount_rw+0xee/0x670 fs/jfs/jfs_mount.c:257
jfs_fill_super+0x754/0xd80 fs/jfs/super.c:532
get_tree_bdev_flags+0x431/0x4f0 fs/super.c:1694
vfs_get_tree+0x92/0x2a0 fs/super.c:1754
fc_mount fs/namespace.c:1193 [inline]
do_new_mount_fc fs/namespace.c:3758 [inline]
do_new_mount+0x341/0xd30 fs/namespace.c:3834
do_mount fs/namespace.c:4167 [inline]
__do_sys_mount fs/namespace.c:4383 [inline]
__se_sys_mount+0x31d/0x420 fs/namespace.c:4360
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0x15f/0xf80 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x77/0x7f
Freed by task 6065:
kasan_save_stack mm/kasan/common.c:57 [inline]
kasan_save_track+0x3e/0x80 mm/kasan/common.c:78
kasan_save_free_info+0x46/0x50 mm/kasan/generic.c:584
poison_slab_object mm/kasan/common.c:253 [inline]
__kasan_slab_free+0x5c/0x80 mm/kasan/common.c:285
kasan_slab_free include/linux/kasan.h:235 [inline]
slab_free_hook mm/slub.c:2689 [inline]
slab_free mm/slub.c:6250 [inline]
kfree+0x1c5/0x640 mm/slub.c:6565
lmLogClose+0x297/0x520 fs/jfs/jfs_logmgr.c:-1
jfs_umount+0x2fb/0x3d0 fs/jfs/jfs_umount.c:124
jfs_put_super+0x8c/0x190 fs/jfs/super.c:194
generic_shutdown_super+0x13d/0x2d0 fs/super.c:646
kill_block_super+0x44/0x90 fs/super.c:1725
deactivate_locked_super+0xbc/0x130 fs/super.c:476
cleanup_mnt+0x437/0x4d0 fs/namespace.c:1312
task_work_run+0x1d9/0x270 kernel/task_work.c:233
resume_user_mode_work include/linux/resume_user_mode.h:50 [inline]
__exit_to_user_mode_loop kernel/entry/common.c:67 [inline]
exit_to_user_mode_loop+0xf3/0x4d0 kernel/entry/common.c:98
__exit_to_user_mode_prepare include/linux/irq-entry-common.h:207 [inline]
syscall_exit_to_user_mode_prepare include/linux/irq-entry-common.h:238 [inline]
syscall_exit_to_user_mode include/linux/entry-common.h:318 [inline]
do_syscall_64+0x33e/0xf80 arch/x86/entry/syscall_64.c:100
entry_SYSCALL_64_after_hwframe+0x77/0x7f
The buggy address belongs to the object at ffff88804dbfa800
which belongs to the cache kmalloc-1k of size 1024
The buggy address is located 536 bytes inside of
freed 1024-byte region [ffff88804dbfa800, ffff88804dbfac00)
The buggy address belongs to the physical page:
page: refcount:0 mapcount:0 mapping:0000000000000000 index:0xffff88804dbf9800 pfn:0x4dbf8
head: order:3 mapcount:0 entire_mapcount:0 nr_pages_mapped:0 pincount:0
flags: 0x4fff00000000240(workingset|head|node=1|zone=1|lastcpupid=0x7ff)
page_type: f5(slab)
raw: 04fff00000000240 ffff88801a841dc0 ffffea0001a6e610 ffffea000123f010
raw: ffff88804dbf9800 000000080010000f 00000000f5000000 0000000000000000
head: 04fff00000000240 ffff88801a841dc0 ffffea0001a6e610 ffffea000123f010
head: ffff88804dbf9800 000000080010000f 00000000f5000000 0000000000000000
head: 04fff00000000003 fffffffffffffe01 00000000ffffffff 00000000ffffffff
head: ffffffffffffffff 0000000000000000 00000000ffffffff 0000000000000008
page dumped because: kasan: bad access detected
page_owner tracks the page as allocated
page last allocated via order 3, migratetype Unmovable, gfp_mask 0xd20c0(__GFP_IO|__GFP_FS|__GFP_NOWARN|__GFP_NORETRY|__GFP_COMP|__GFP_NOMEMALLOC), pid 6080, tgid 6080 (syz-executor), ts 85500584456, free_ts 84013765231
set_page_owner include/linux/page_owner.h:32 [inline]
post_alloc_hook+0x231/0x280 mm/page_alloc.c:1858
prep_new_page mm/page_alloc.c:1866 [inline]
get_page_from_freelist+0x24ba/0x2540 mm/page_alloc.c:3946
__alloc_frozen_pages_noprof+0x18d/0x380 mm/page_alloc.c:5226
alloc_slab_page mm/slub.c:3278 [inline]
allocate_slab+0x77/0x660 mm/slub.c:3467
new_slab mm/slub.c:3525 [inline]
refill_objects+0x339/0x3d0 mm/slub.c:7255
refill_sheaf mm/slub.c:2816 [inline]
__pcs_replace_empty_main+0x321/0x720 mm/slub.c:4651
alloc_from_pcs mm/slub.c:4749 [inline]
slab_alloc_node mm/slub.c:4883 [inline]
__do_kmalloc_node mm/slub.c:5294 [inline]
__kmalloc_noprof+0x474/0x760 mm/slub.c:5307
kmalloc_noprof include/linux/slab.h:954 [inline]
kzalloc_noprof include/linux/slab.h:1188 [inline]
__alloc_workqueue+0x100/0x1c00 kernel/workqueue.c:5815
alloc_workqueue_va kernel/workqueue.c:5917 [inline]
alloc_workqueue_noprof+0xe3/0x210 kernel/workqueue.c:5933
tipc_crypto_start+0xd8/0x640 net/tipc/crypto.c:1472
tipc_init_net+0x213/0x330 net/tipc/core.c:72
ops_init+0x35c/0x5c0 net/core/net_namespace.c:137
setup_net+0x118/0x340 net/core/net_namespace.c:446
copy_net_ns+0x3e2/0x570 net/core/net_namespace.c:579
create_new_namespaces+0x3e7/0x6a0 kernel/nsproxy.c:132
unshare_nsproxy_namespaces+0x149/0x190 kernel/nsproxy.c:234
page last free pid 5978 tgid 5978 stack trace:
reset_page_owner include/linux/page_owner.h:25 [inline]
__free_pages_prepare mm/page_alloc.c:1402 [inline]
__free_frozen_pages+0xb84/0xcd0 mm/page_alloc.c:2943
__slab_free+0x274/0x2c0 mm/slub.c:5612
qlink_free mm/kasan/quarantine.c:163 [inline]
qlist_free_all+0x99/0x100 mm/kasan/quarantine.c:179
kasan_quarantine_reduce+0x148/0x160 mm/kasan/quarantine.c:286
__kasan_slab_alloc+0x22/0x80 mm/kasan/common.c:350
kasan_slab_alloc include/linux/kasan.h:253 [inline]
slab_post_alloc_hook mm/slub.c:4569 [inline]
slab_alloc_node mm/slub.c:4898 [inline]
kmem_cache_alloc_node_noprof+0x384/0x690 mm/slub.c:4950
__alloc_skb+0x1d0/0x7d0 net/core/skbuff.c:702
alloc_skb include/linux/skbuff.h:1383 [inline]
nlmsg_new include/net/netlink.h:1055 [inline]
netlink_ack+0x146/0xa50 net/netlink/af_netlink.c:2487
netlink_rcv_skb+0x2b6/0x4b0 net/netlink/af_netlink.c:2556
netlink_unicast_kernel net/netlink/af_netlink.c:1318 [inline]
netlink_unicast+0x75c/0x8e0 net/netlink/af_netlink.c:1344
netlink_sendmsg+0x813/0xb40 net/netlink/af_netlink.c:1894
sock_sendmsg_nosec net/socket.c:787 [inline]
__sock_sendmsg+0x167/0x1b0 net/socket.c:802
__sys_sendto+0x3c0/0x550 net/socket.c:2265
__do_sys_sendto net/socket.c:2272 [inline]
__se_sys_sendto net/socket.c:2268 [inline]
__x64_sys_sendto+0xde/0x100 net/socket.c:2268
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0x15f/0xf80 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x77/0x7f
Memory state around the buggy address:
ffff88804dbfa900: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
ffff88804dbfa980: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
>ffff88804dbfaa00: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
^
ffff88804dbfaa80: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
ffff88804dbfab00: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
==================================================================
The explanation of the root cause of the bug is:
An analysis of the crash reveals a race condition during the unmounting of a JFS filesystem, leading to a use-after-free in the `jfs_lazycommit` background thread.
### Root Cause
When a JFS filesystem is unmounted, `jfs_umount()` (and `jfs_umount_rw()`) calls `jfs_flush_journal(log, 2)` to flush all outstanding transactions to the disk.
`jfs_flush_journal()` waits until the commit queue (`log->cqueue`) and the sync list (`log->synclist`) are empty. However, it **does not wait** for the unlock queue (`TxAnchor.unlock_queue`) to be processed by the `jfs_lazycommit` thread.
The lifecycle of a lazy transaction is as follows:
1. Added to `log->cqueue` during `txCommit()`.
2. Moved from `log->cqueue` to `TxAnchor.unlock_queue` by `lmPostGC()` once the commit record hits the disk.
3. Removed from `TxAnchor.unlock_queue` and processed by the `jfs_lazycommit` thread via `txLazyCommit()`.
Because `jfs_flush_journal()` only waits for `log->cqueue` to drain, it can return while transactions are still sitting in `TxAnchor.unlock_queue` or are actively being processed by `jfs_lazycommit`.
After `jfs_flush_journal()` returns, `jfs_umount()` proceeds to tear down the filesystem: it frees the allocation maps (`sbi->ipimap`, `sbi->ipbmap`) and eventually calls `lmLogClose()`, which frees the `jfs_log` structure.
Meanwhile, the `jfs_lazycommit` thread wakes up, pops the transaction from `TxAnchor.unlock_queue`, and calls `txLazyCommit()`. This function accesses the now-freed allocation maps and the freed `log` structure (`log = JFS_SBI(tblk->sb)->log`), eventually calling `txEnd()` -> `jfs_syncpt()` -> `lmLogSync()`, which writes to `log->syncpt`, resulting in the KASAN slab-use-after-free crash.
### How to Fix
To fix this, we need to ensure that `jfs_lazycommit` has completely finished processing all transactions for the unmounting superblock before `jfs_umount()` proceeds to free the filesystem structures.
1. **Introduce a wait function in `fs/jfs/jfs_txnmgr.c`:**
Create a function `txLazyCommitWait(sb)` that waits until `TxAnchor.unlock_queue` contains no transactions for the given `sb`, and the `jfs_lazycommit` thread is not actively processing one (`sbi->commit_state & IN_LAZYCOMMIT` is cleared).
```c
/*
* Wait for lazycommit thread to finish processing all transactions
* for the given superblock.
*/
void txLazyCommitWait(struct super_block *sb)
{
struct jfs_sb_info *sbi = JFS_SBI(sb);
struct jfs_log *log = sbi->log;
unsigned long flags;
struct tblock *tblk;
int found;
if (!log)
return;
/*
* Synchronize with lmPostGC to ensure that all transactions
* removed from cqueue have been added to unlock_queue.
*/
spin_lock_irqsave(&log->gclock, flags);
spin_unlock_irqrestore(&log->gclock, flags);
do {
found = 0;
LAZY_LOCK(flags);
if (sbi->commit_state & IN_LAZYCOMMIT)
found = 1;
else {
list_for_each_entry(tblk, &TxAnchor.unlock_queue, cqueue) {
if (tblk->sb == sb) {
found = 1;
break;
}
}
}
LAZY_UNLOCK(flags);
if (found)
msleep(10);
} while (found);
}
```
*(Note: Briefly taking `log->gclock` is crucial here to close a tiny race window where `jfs_flush_journal` sees an empty `cqueue`, but `lmPostGC` is still holding `log->gclock` and hasn't yet added the transaction to `unlock_queue`)*.
2. **Export the function in `fs/jfs/jfs_txnmgr.h`:**
```c
extern void txLazyCommitWait(struct super_block *sb);
```
3. **Call the wait function during unmount in `fs/jfs/jfs_umount.c`:**
Invoke `txLazyCommitWait(sb)` immediately after `jfs_flush_journal(log, 2)` in both `jfs_umount()` and `jfs_umount_rw()`.
In `jfs_umount()`:
```c
- if ((log = sbi->log))
+ if ((log = sbi->log)) {
/*
* Wait for outstanding transactions to be written to log:
*/
jfs_flush_journal(log, 2);
+ txLazyCommitWait(sb);
+ }
```
In `jfs_umount_rw()`:
```c
/*
* Note that we have to do this even if dummy_log is used.
* This is because dummy_log is shared among all mounts.
*/
jfs_flush_journal(log, 2);
+ txLazyCommitWait(sb);
/*
* close log:
```
Reply: I have implemented the fix as suggested to resolve the race condition between the unmounting process and the `jfs_lazycommit` background thread.
### Changes Made:
1. **Added `txLazyCommitWait(sb)` in `fs/jfs/jfs_txnmgr.c`**:
- This function ensures that all transactions for a given superblock have been completely processed by the `jfs_lazycommit` thread.
- It first briefly acquires and releases `log->gclock`. This is a critical step to synchronize with `lmPostGC()`. It closes a tiny race window where `jfs_flush_journal()` might see an empty `cqueue` and return, while `lmPostGC()` has removed the transaction from `cqueue` but hasn't yet added it to `TxAnchor.unlock_queue`.
- It then loops, taking `LAZY_LOCK` to check if `sbi->commit_state & IN_LAZYCOMMIT` is set (meaning the thread is actively processing a transaction for this superblock) or if there are any pending transactions for this superblock in `TxAnchor.unlock_queue`. If either condition is met, it sleeps for 10ms and retries.
- I also added `#include <linux/delay.h>` to `fs/jfs/jfs_txnmgr.c` to support the `msleep(10)` call.
2. **Exported `txLazyCommitWait` in `fs/jfs/jfs_txnmgr.h`**:
- Added the function prototype `extern void txLazyCommitWait(struct super_block *sb);` so it can be called from other files.
3. **Invoked `txLazyCommitWait` during unmount in `fs/jfs/jfs_umount.c`**:
- Added `#include "jfs_txnmgr.h"` to the includes list.
- Called `txLazyCommitWait(sb)` immediately after `jfs_flush_journal(log, 2)` in both `jfs_umount()` and `jfs_umount_rw()`. This guarantees that by the time `jfs_umount()` proceeds to tear down the filesystem and free the `jfs_log` structure via `lmLogClose()`, the `jfs_lazycommit` thread has completely finished its work for this superblock and will not attempt to access the freed structures.
These changes effectively eliminate the use-after-free vulnerability by enforcing proper synchronization and lifecycle management during the filesystem unmount process.
|
| 91/4 |
2026/05/11 23:49 |
llm |
patch-generator |
0m
Model:
Tokens:
input: 9426
output: 32
thoughts: 235
Thoughts: **Analyzing a KASAN Slab-Use-After-Free in JFS's Log Manager**
Okay, so I've got a crash report indicating a KASAN slab-use-after-free error within the `lmLogSync` function, specifically in `fs/jfs/jfs_logmgr.c:1003`. The problem is occurring in the `jfsCommit` thread, which immediately suggests a concurrency issue. Drilling down into the root cause, it seems that the `jfs_umount` function is triggering `jfs_flush_journal(log, 2)`. This flush is waiting for the `log->cqueue` and `log->synclist` to clear, which makes sense for ensuring data integrity during unmount. However, the critical oversight is that `jfs_umount` isn't waiting for the `TxAnchor.unlock_queue` to be processed by the `jfs_lazycommit` thread. This race condition leads to the use-after-free.
The proposed solution seems straightforward: introduce a call to `txLazyCommitWait(sb)` within `fs/jfs/jfs_umount.c`, and likely `jfs_umount_rw()`, to explicitly wait for these lazy commits to finish before continuing with the unmount. This should guarantee that any outstanding transactions are properly handled.
My next step is to examine the relevant code. I need to dive into `fs/jfs/jfs_txnmgr.c`, `fs/jfs/jfs_txnmgr.h`, and, most importantly, `fs/jfs/jfs_umount.c` to fully understand the current synchronization mechanisms and assess the impact of this proposed fix. I'll be looking for where `TxAnchor.unlock_queue` is used, how `jfs_lazycommit` interacts with it, and precisely how to integrate this new wait function without introducing other potential issues or performance bottlenecks. I'll need to think about potential race conditions and deadlocks that could be introduced.
|
| 92/4 |
2026/05/11 23:49 |
tool |
codesearch-file-index |
0m
Args: map[SourceFile:fs/jfs/jfs_txnmgr.c]
Results: map[Entities:[map[Kind:function Name:LogSyncRelease] map[Kind:function Name:TXN_SLEEP_DROP_LOCK] map[Kind:function Name:__check_nTxBlock] map[Kind:function Name:__check_nTxLock] map[Kind:function Name:dataLog] map[Kind:function Name:diLog] map[Kind:function Name:dtLog] map[Kind:function Name:jfs_lazycommit] map[Kind:function Name:jfs_sync] map[Kind:function Name:jfs_txanchor_proc_show] map[Kind:function Name:mapLog] map[Kind:function Name:txAbort] map[Kind:function Name:txAllocPMap] map[Kind:function Name:txBegin] map[Kind:function Name:txBeginAnon] map[Kind:function Name:txCommit] map[Kind:function Name:txEA] map[Kind:function Name:txEnd] map[Kind:function Name:txExit] map[Kind:function Name:txForce] map[Kind:function Name:txFreeMap] map[Kind:function Name:txFreelock] map[Kind:function Name:txInit] map[Kind:function Name:txLazyCommit] map[Kind:function Name:txLazyUnlock] map[Kind:function Name:txLinelock] map[Kind:function Name:txLock] map[Kind:function Name:txLockAlloc] map[Kind:function Name:txLockFree] map[Kind:function Name:txLog] map[Kind:function Name:txMaplock] map[Kind:function Name:txQuiesce] map[Kind:function Name:txRelease] map[Kind:function Name:txResume] map[Kind:function Name:txUnlock] map[Kind:function Name:txUpdateMap] map[Kind:function Name:xtLog] map[Kind:global_variable Name:__UNIQUE_ID_modinfo_894] map[Kind:global_variable Name:__UNIQUE_ID_modinfo_895] map[Kind:global_variable Name:__UNIQUE_ID_modinfo_896] map[Kind:global_variable Name:__UNIQUE_ID_modinfo_897] map[Kind:global_variable Name:__param_nTxBlock] map[Kind:global_variable Name:__param_nTxLock] map[Kind:global_variable Name:__param_str_nTxBlock] map[Kind:global_variable Name:__param_str_nTxLock] map[Kind:global_variable Name:jfsTxnLock] map[Kind:global_variable Name:jfs_commit_thread_wait] map[Kind:global_variable Name:nTxBlock] map[Kind:global_variable Name:nTxLock]]]
|
| 93/4 |
2026/05/11 23:49 |
llm |
patch-generator |
0m
Model:
Tokens:
input: 10917
output: 47
thoughts: 36
Thoughts: Okay, let's dive into this. Here's my take on those files:
**Analyzing jfs_txnmgr.c and jfs_txnmgr.h**
Alright, I'm focusing on `fs/jfs/jfs_txnmgr.c` and its header, `fs/jfs/jfs_txnmgr.h`. Obviously, we're talking about the JFS (Journaled File System) transaction manager here. My immediate thought is, this is the *core* of JFS's data integrity. This is where the magic happens, ensuring atomicity, consistency, isolation, and durability β the ACID properties β for file system operations.
So, in `jfs_txnmgr.c`, I'm expecting to find the implementation of the transaction management itself. That includes things like transaction logging, concurrency control mechanisms (likely some form of locking or latching to protect against concurrent modification), and the recovery procedures to handle crashes and ensure data consistency after a system failure. I'm looking for the nitty-gritty details of how transactions are initiated, committed, and rolled back. There's probably a lot of low-level block I/O interactions in here, dealing with the journal. I'll need to understand how the journal entries are formatted, how they're written to disk, and how the manager coordinates the writes. I anticipate seeing structures defining transaction states, potentially referencing other JFS components like the inode layer and the block allocator. The interactions will be complex, likely involving linked lists or hash tables to track active transactions and their associated data.
`jfs_txnmgr.h` is where the interface is defined. I'll be looking for data structures and function prototypes. This is crucial for understanding how the transaction manager is integrated into the rest of the JFS code. I'll focus on how transactions are started, how data is added to a transaction, how the transaction is committed (or aborted), and how the recovery functions are declared. The header file should give me a map of the data types used to represent transactions, log entries, and other transaction-related objects. I'll use that to follow the flow of data through the system. I'll look for any configuration parameters that might be tunable, especially related to the journal size or the concurrency level. It'll be a key for understanding how the module is used by other parts of the JFS. Ultimately, it should be clear what the public interface to the transaction manager is and, of course, how it interacts with the underlying block device. Let's see what's in there.
|
| 94/4 |
2026/05/11 23:49 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:fs/jfs/jfs_txnmgr.c IncludeLines:true Name:jfs_lazycommit]
Results: map[SourceCode:2693: /*
2694: * jfs_lazycommit(void)
2695: *
2696: * To be run as a kernel daemon. If lbmIODone is called in an interrupt
2697: * context, or where blocking is not wanted, this routine will process
2698: * committed transactions from the unlock queue.
2699: */
2700: int jfs_lazycommit(void *arg)
2701: {
2702: int WorkDone;
2703: struct tblock *tblk;
2704: unsigned long flags;
2705: struct jfs_sb_info *sbi;
2706:
2707: set_freezable();
2708: do {
2709: LAZY_LOCK(flags);
2710: jfs_commit_thread_waking = 0; /* OK to wake another thread */
2711: while (!list_empty(&TxAnchor.unlock_queue)) {
2712: WorkDone = 0;
2713: list_for_each_entry(tblk, &TxAnchor.unlock_queue,
2714: cqueue) {
2715:
2716: sbi = JFS_SBI(tblk->sb);
2717: /*
2718: * For each volume, the transactions must be
2719: * handled in order. If another commit thread
2720: * is handling a tblk for this superblock,
2721: * skip it
2722: */
2723: if (sbi->commit_state & IN_LAZYCOMMIT)
2724: continue;
2725:
2726: sbi->commit_state |= IN_LAZYCOMMIT;
2727: WorkDone = 1;
2728:
2729: /*
2730: * Remove transaction from queue
2731: */
2732: list_del(&tblk->cqueue);
2733:
2734: LAZY_UNLOCK(flags);
2735: txLazyCommit(tblk);
2736: LAZY_LOCK(flags);
2737:
2738: sbi->commit_state &= ~IN_LAZYCOMMIT;
2739: /*
2740: * Don't continue in the for loop. (We can't
2741: * anyway, it's unsafe!) We want to go back to
2742: * the beginning of the list.
2743: */
2744: break;
2745: }
2746:
2747: /* If there was nothing to do, don't continue */
2748: if (!WorkDone)
2749: break;
2750: }
2751: /* In case a wakeup came while all threads were active */
2752: jfs_commit_thread_waking = 0;
2753:
2754: if (freezing(current)) {
2755: LAZY_UNLOCK(flags);
2756: try_to_freeze();
2757: } else {
2758: DECLARE_WAITQUEUE(wq, current);
2759:
2760: add_wait_queue(&jfs_commit_thread_wait, &wq);
2761: set_current_state(TASK_INTERRUPTIBLE);
2762: LAZY_UNLOCK(flags);
2763: schedule();
2764: remove_wait_queue(&jfs_commit_thread_wait, &wq);
2765: }
2766: } while (!kthread_should_stop());
2767:
2768: if (!list_empty(&TxAnchor.unlock_queue))
2769: jfs_err("jfs_lazycommit being killed w/pending transactions!");
2770: else
2771: jfs_info("jfs_lazycommit being killed");
2772: return 0;
2773: }
SourceFile:fs/jfs/jfs_txnmgr.c]
|
| 95/4 |
2026/05/11 23:49 |
llm |
patch-generator |
0m
Model:
Tokens:
input: 12703
output: 45
thoughts: 77
Thoughts: Okay, here's my thought process regarding adding `txLazyCommitWait` to the JFS transaction manager:
**Adding `txLazyCommitWait` to JFS Transaction Management**
Alright, I've got a task at hand: I need to introduce a new function, `txLazyCommitWait(struct super_block *sb)`, into the JFS file system code. Specifically, I'm targeting `fs/jfs/jfs_txnmgr.c`. I'll also need to make sure this function is properly declared and accessible, so I'll be adding an export to `fs/jfs/jfs_txnmgr.h`.
Now, the real question is where exactly within `jfs_txnmgr.c` does this new function fit best? I need to think about the existing code structure, the responsibilities of the transaction manager, and where `txLazyCommitWait`'s functionality aligns most logically. I'll need to consider how it interacts with the other transaction management routines and what the overall flow of lazy commits looks like. Time to dive into the existing code and map this out.
|
| 96/4 |
2026/05/11 23:49 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:fs/jfs/jfs_txnmgr.c IncludeLines:true Name:txLazyCommit]
Results: map[SourceCode:2644: /*
2645: * txLazyCommit(void)
2646: *
2647: * All transactions except those changing ipimap (COMMIT_FORCE) are
2648: * processed by this routine. This insures that the inode and block
2649: * allocation maps are updated in order. For synchronous transactions,
2650: * let the user thread finish processing after txUpdateMap() is called.
2651: */
2652: static void txLazyCommit(struct tblock * tblk)
2653: {
2654: struct jfs_log *log;
2655:
2656: while (((tblk->flag & tblkGC_READY) == 0) &&
2657: ((tblk->flag & tblkGC_UNLOCKED) == 0)) {
2658: /* We must have gotten ahead of the user thread
2659: */
2660: jfs_info("jfs_lazycommit: tblk 0x%p not unlocked", tblk);
2661: yield();
2662: }
2663:
2664: jfs_info("txLazyCommit: processing tblk 0x%p", tblk);
2665:
2666: txUpdateMap(tblk);
2667:
2668: log = (struct jfs_log *) JFS_SBI(tblk->sb)->log;
2669:
2670: spin_lock_irq(&log->gclock); // LOGGC_LOCK
2671:
2672: tblk->flag |= tblkGC_COMMITTED;
2673:
2674: if (tblk->flag & tblkGC_READY)
2675: log->gcrtc--;
2676:
2677: wake_up_all(&tblk->gcwait); // LOGGC_WAKEUP
2678:
2679: /*
2680: * Can't release log->gclock until we've tested tblk->flag
2681: */
2682: if (tblk->flag & tblkGC_LAZY) {
2683: spin_unlock_irq(&log->gclock); // LOGGC_UNLOCK
2684: txUnlock(tblk);
2685: tblk->flag &= ~tblkGC_LAZY;
2686: txEnd(tblk - TxBlock); /* Convert back to tid */
2687: } else
2688: spin_unlock_irq(&log->gclock); // LOGGC_UNLOCK
2689:
2690: jfs_info("txLazyCommit: done: tblk = 0x%p", tblk);
2691: }
SourceFile:fs/jfs/jfs_txnmgr.c]
|
| 97/4 |
2026/05/11 23:49 |
llm |
patch-generator |
0m
Model:
Tokens:
input: 13856
output: 468
thoughts: 35
Thoughts: Okay, here's my interpretation of that thought process, tailored for an expert audience:
**Adding `txLazyCommitWait` to the JFS Transaction Manager**
Alright, so I'm thinking about where to best introduce this new `txLazyCommitWait` function within the JFS codebase. Given that we're dealing with transactional behavior and commit processes, the logical place to insert this is immediately following the `jfs_lazycommit` function. Specifically, I'll be adding it to `fs/jfs/jfs_txnmgr.c`. The placement suggests a direct relationship or sequential dependency between the lazy commit mechanism and the wait function, and this feels like the most appropriate integration point within the transaction management module.
|
| 98/4 |
2026/05/11 23:49 |
tool |
codeeditor |
0m
Args: map[CurrentCode: if (!list_empty(&TxAnchor.unlock_queue))
jfs_err("jfs_lazycommit being killed w/pending transactions!");
else
jfs_info("jfs_lazycommit being killed");
return 0;
} NewCode: if (!list_empty(&TxAnchor.unlock_queue))
jfs_err("jfs_lazycommit being killed w/pending transactions!");
else
jfs_info("jfs_lazycommit being killed");
return 0;
}
/*
* Wait for lazycommit thread to finish processing all transactions
* for the given superblock.
*/
void txLazyCommitWait(struct super_block *sb)
{
struct jfs_sb_info *sbi = JFS_SBI(sb);
struct jfs_log *log = sbi->log;
unsigned long flags;
struct tblock *tblk;
int found;
if (!log)
return;
/*
* Synchronize with lmPostGC to ensure that all transactions
* removed from cqueue have been added to unlock_queue.
*/
spin_lock_irqsave(&log->gclock, flags);
spin_unlock_irqrestore(&log->gclock, flags);
do {
found = 0;
LAZY_LOCK(flags);
if (sbi->commit_state & IN_LAZYCOMMIT)
found = 1;
else {
list_for_each_entry(tblk, &TxAnchor.unlock_queue, cqueue) {
if (tblk->sb == sb) {
found = 1;
break;
}
}
}
LAZY_UNLOCK(flags);
if (found)
msleep(10);
} while (found);
} SourceFile:fs/jfs/jfs_txnmgr.c]
Results:
|
| 99/4 |
2026/05/11 23:49 |
llm |
patch-generator |
0m
Model:
Tokens:
input: 14519
output: 32
thoughts: 23
Thoughts: Okay, here's my take on those thoughts, tailored for an expert audience:
**Adding the Declaration to jfs_txnmgr.h**
Alright, let's get down to brass tacks. Time to integrate this new functionality. I'm thinking, the obvious place for the declaration is `fs/jfs/jfs_txnmgr.h`. It makes the most logical sense to keep things tidy and in line with existing structures within JFS. It's the central header for transaction management, so any new component like this will have its appropriate place here. No need to overcomplicate things with a separate header, at least not initially. Let's start with this and see if it grows too cumbersome, but I doubt it will. This keeps the dependencies clean and easy to track. Time to get coding!
|
| 100/4 |
2026/05/11 23:49 |
tool |
codesearch-file-index |
0m
Args: map[SourceFile:fs/jfs/jfs_txnmgr.h]
Results: map[Entities:[map[Kind:struct Name:commit] map[Kind:struct Name:linelock] map[Kind:struct Name:lv] map[Kind:struct Name:maplock] map[Kind:struct Name:tblock] map[Kind:struct Name:tlock] map[Kind:struct Name:xdlistlock] map[Kind:struct Name:xtlock]]]
|
| 101/4 |
2026/05/11 23:49 |
llm |
patch-generator |
0m
Model:
Tokens:
input: 14867
output: 28
thoughts: 19
Thoughts: Okay, here's my interpretation of reading `fs/jfs/jfs_txnmgr.h`, framed as my own thought process:
**Diving into the JFS Transaction Manager**
Alright, time to dig into the guts of the JFS transaction management. Let's see what `fs/jfs/jfs_txnmgr.h` has to say. I'm expecting this header to lay out the fundamental data structures and function prototypes that drive the journaling system. Specifically, I'm looking for the definitions related to transaction contexts, log records, and the mechanisms for coordinating write operations and ensuring atomicity and consistency. I'll be focused on how it handles things like transaction IDs, dependencies, recovery strategies and how it integrates with the underlying block device. I need to understand the relationship between the transaction manager and the file system itself, and how it handles things like aborts, commits, and rollbacks. Ultimately, I'm hoping to get a solid grasp of the core primitives used to maintain data integrity during file system operations. I'll be paying close attention to any details that hint at performance considerations or optimizations implemented within the transaction manager to support high-throughput.
|
| 102/4 |
2026/05/11 23:49 |
tool |
read-file |
0m
Args: map[File:fs/jfs/jfs_txnmgr.h]
Results: map[Contents:/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright (C) International Business Machines Corp., 2000-2004
*/
#ifndef _H_JFS_TXNMGR
#define _H_JFS_TXNMGR
#include "jfs_logmgr.h"
/*
* Hide implementation of TxBlock and TxLock
*/
#define tid_to_tblock(tid) (&TxBlock[tid])
#define lid_to_tlock(lid) (&TxLock[lid])
/*
* transaction block
*/
struct tblock {
/*
* tblock and jbuf_t common area: struct logsyncblk
*
* the following 5 fields are the same as struct logsyncblk
* which is common to tblock and jbuf to form logsynclist
*/
u16 xflag; /* tx commit type */
u16 flag; /* tx commit state */
lid_t dummy; /* Must keep structures common */
s32 lsn; /* recovery lsn */
struct list_head synclist; /* logsynclist link */
/* lock management */
struct super_block *sb; /* super block */
lid_t next; /* index of first tlock of tid */
lid_t last; /* index of last tlock of tid */
wait_queue_head_t waitor; /* tids waiting on this tid */
/* log management */
u32 logtid; /* log transaction id */
/* commit management */
struct list_head cqueue; /* commit queue list */
s32 clsn; /* commit lsn */
struct lbuf *bp;
s32 pn; /* commit record log page number */
s32 eor; /* commit record eor */
wait_queue_head_t gcwait; /* group commit event list:
* ready transactions wait on this
* event for group commit completion.
*/
union {
struct inode *ip; /* inode being deleted */
pxd_t ixpxd; /* pxd of inode extent for created inode */
} u;
u32 ino; /* inode number being created */
};
extern struct tblock *TxBlock; /* transaction block table */
/* commit flags: tblk->xflag */
#define COMMIT_SYNC 0x0001 /* synchronous commit */
#define COMMIT_FORCE 0x0002 /* force pageout at end of commit */
#define COMMIT_FLUSH 0x0004 /* init flush at end of commit */
#define COMMIT_MAP 0x00f0
#define COMMIT_PMAP 0x0010 /* update pmap */
#define COMMIT_WMAP 0x0020 /* update wmap */
#define COMMIT_PWMAP 0x0040 /* update pwmap */
#define COMMIT_FREE 0x0f00
#define COMMIT_DELETE 0x0100 /* inode delete */
#define COMMIT_TRUNCATE 0x0200 /* file truncation */
#define COMMIT_CREATE 0x0400 /* inode create */
#define COMMIT_LAZY 0x0800 /* lazy commit */
#define COMMIT_PAGE 0x1000 /* Identifies element as metapage */
#define COMMIT_INODE 0x2000 /* Identifies element as inode */
/* group commit flags tblk->flag: see jfs_logmgr.h */
/*
* transaction lock
*/
struct tlock {
lid_t next; /* 2: index next lockword on tid locklist
* next lockword on freelist
*/
tid_t tid; /* 2: transaction id holding lock */
u16 flag; /* 2: lock control */
u16 type; /* 2: log type */
struct metapage *mp; /* 4/8: object page buffer locked */
struct inode *ip; /* 4/8: object */
/* (16) */
s16 lock[24]; /* 48: overlay area */
}; /* (64) */
extern struct tlock *TxLock; /* transaction lock table */
/*
* tlock flag
*/
/* txLock state */
#define tlckPAGELOCK 0x8000
#define tlckINODELOCK 0x4000
#define tlckLINELOCK 0x2000
#define tlckINLINELOCK 0x1000
/* lmLog state */
#define tlckLOG 0x0800
/* updateMap state */
#define tlckUPDATEMAP 0x0080
#define tlckDIRECTORY 0x0040
/* freeLock state */
#define tlckFREELOCK 0x0008
#define tlckWRITEPAGE 0x0004
#define tlckFREEPAGE 0x0002
/*
* tlock type
*/
#define tlckTYPE 0xfe00
#define tlckINODE 0x8000
#define tlckXTREE 0x4000
#define tlckDTREE 0x2000
#define tlckMAP 0x1000
#define tlckEA 0x0800
#define tlckACL 0x0400
#define tlckDATA 0x0200
#define tlckBTROOT 0x0100
#define tlckOPERATION 0x00ff
#define tlckGROW 0x0001 /* file grow */
#define tlckREMOVE 0x0002 /* file delete */
#define tlckTRUNCATE 0x0004 /* file truncate */
#define tlckRELOCATE 0x0008 /* file/directory relocate */
#define tlckENTRY 0x0001 /* directory insert/delete */
#define tlckEXTEND 0x0002 /* directory extend in-line */
#define tlckSPLIT 0x0010 /* splited page */
#define tlckNEW 0x0020 /* new page from split */
#define tlckFREE 0x0040 /* free page */
#define tlckRELINK 0x0080 /* update sibling pointer */
/*
* linelock for lmLog()
*
* note: linelock and its variations are overlaid
* at tlock.lock: watch for alignment;
*/
struct lv {
u8 offset; /* 1: */
u8 length; /* 1: */
}; /* (2) */
#define TLOCKSHORT 20
#define TLOCKLONG 28
struct linelock {
lid_t next; /* 2: next linelock */
s8 maxcnt; /* 1: */
s8 index; /* 1: */
u16 flag; /* 2: */
u8 type; /* 1: */
u8 l2linesize; /* 1: log2 of linesize */
/* (8) */
struct lv lv[20]; /* 40: */
}; /* (48) */
#define dt_lock linelock
struct xtlock {
lid_t next; /* 2: */
s8 maxcnt; /* 1: */
s8 index; /* 1: */
u16 flag; /* 2: */
u8 type; /* 1: */
u8 l2linesize; /* 1: log2 of linesize */
/* (8) */
struct lv header; /* 2: */
struct lv lwm; /* 2: low water mark */
struct lv hwm; /* 2: high water mark */
struct lv twm; /* 2: */
/* (16) */
s32 pxdlock[8]; /* 32: */
}; /* (48) */
/*
* maplock for txUpdateMap()
*
* note: maplock and its variations are overlaid
* at tlock.lock/linelock: watch for alignment;
* N.B. next field may be set by linelock, and should not
* be modified by maplock;
* N.B. index of the first pxdlock specifies index of next
* free maplock (i.e., number of maplock) in the tlock;
*/
struct maplock {
lid_t next; /* 2: */
u8 maxcnt; /* 2: */
u8 index; /* 2: next free maplock index */
u16 flag; /* 2: */
u8 type; /* 1: */
u8 count; /* 1: number of pxd/xad */
/* (8) */
pxd_t pxd; /* 8: */
}; /* (16): */
/* maplock flag */
#define mlckALLOC 0x00f0
#define mlckALLOCXADLIST 0x0080
#define mlckALLOCPXDLIST 0x0040
#define mlckALLOCXAD 0x0020
#define mlckALLOCPXD 0x0010
#define mlckFREE 0x000f
#define mlckFREEXADLIST 0x0008
#define mlckFREEPXDLIST 0x0004
#define mlckFREEXAD 0x0002
#define mlckFREEPXD 0x0001
#define pxd_lock maplock
struct xdlistlock {
lid_t next; /* 2: */
u8 maxcnt; /* 2: */
u8 index; /* 2: */
u16 flag; /* 2: */
u8 type; /* 1: */
u8 count; /* 1: number of pxd/xad */
/* (8) */
/*
* We need xdlist to be 64 bits (8 bytes), regardless of
* whether void * is 32 or 64 bits
*/
union {
void *_xdlist; /* pxd/xad list */
s64 pad; /* 8: Force 64-bit xdlist size */
} union64;
}; /* (16): */
#define xdlist union64._xdlist
/*
* commit
*
* parameter to the commit manager routines
*/
struct commit {
tid_t tid; /* tid = index of tblock */
int flag; /* flags */
struct jfs_log *log; /* log */
struct super_block *sb; /* superblock */
int nip; /* number of entries in iplist */
struct inode **iplist; /* list of pointers to inodes */
/* log record descriptor on 64-bit boundary */
struct lrd lrd; /* : log record descriptor */
};
/*
* external declarations
*/
extern int jfs_tlocks_low;
extern int txInit(void);
extern void txExit(void);
extern struct tlock *txLock(tid_t, struct inode *, struct metapage *, int);
extern struct tlock *txMaplock(tid_t, struct inode *, int);
extern int txCommit(tid_t, int, struct inode **, int);
extern tid_t txBegin(struct super_block *, int);
extern void txBeginAnon(struct super_block *);
extern void txEnd(tid_t);
extern void txAbort(tid_t, int);
extern struct linelock *txLinelock(struct linelock *);
extern void txFreeMap(struct inode *, struct maplock *, struct tblock *, int);
extern void txEA(tid_t, struct inode *, dxd_t *, dxd_t *);
extern void txFreelock(struct inode *);
extern int lmLog(struct jfs_log *, struct tblock *, struct lrd *,
struct tlock *);
extern void txQuiesce(struct super_block *);
extern void txResume(struct super_block *);
extern void txLazyUnlock(struct tblock *);
extern int jfs_lazycommit(void *);
extern int jfs_sync(void *);
#endif /* _H_JFS_TXNMGR */
]
|
| 103/4 |
2026/05/11 23:49 |
llm |
patch-generator |
0m
Model:
Tokens:
input: 18235
output: 147
thoughts: 35
Thoughts: Okay, here's my take on those thoughts, framed as an expert's internal monologue:
**Adding a Transaction Lazy Commit Wait Function**
Right, so I'm going to add the declaration for `extern void txLazyCommitWait(struct super_block *sb);` to `fs/jfs/jfs_txnmgr.h`. Nothing groundbreaking, just a straightforward addition. But it's crucial for the correct synchronization of the transaction management. This function, by the looks of it, is likely related to ensuring that lazy commits are properly handled. The `struct super_block *sb` argument indicates it's likely operating at the filesystem level, probably waiting for any outstanding lazy commits for a given superblock to complete. This is the right place for the declaration since it will undoubtedly be used in a number of other functions within the jfs module, likely including functions for journaling and transaction handling. Iβll make sure to double-check the implementations that *call* this once I've had a look at the implementation. This header addition is a small, but vital, step in the transaction management process for JFS.
|
| 104/4 |
2026/05/11 23:49 |
tool |
codeeditor |
0m
Args: map[CurrentCode:extern void txLazyUnlock(struct tblock *);
extern int jfs_lazycommit(void *);
extern int jfs_sync(void *);
#endif /* _H_JFS_TXNMGR */ NewCode:extern void txLazyUnlock(struct tblock *);
extern int jfs_lazycommit(void *);
extern int jfs_sync(void *);
extern void txLazyCommitWait(struct super_block *sb);
#endif /* _H_JFS_TXNMGR */ SourceFile:fs/jfs/jfs_txnmgr.h]
Results:
|
| 105/4 |
2026/05/11 23:49 |
llm |
patch-generator |
0m
Model:
Tokens:
input: 18660
output: 31
thoughts: 33
Thoughts: Okay, here's my take on those thoughts, framed as my own:
**Adding Lazy Commit Waits to jfs_umount.c**
Alright, time to get down to the nitty-gritty. I'm going to take a look at `fs/jfs/jfs_umount.c`. The goal here is pretty clear: we need to ensure that the lazy commit process is properly synchronized during the unmount operation. So, my focus is going to be on integrating the `txLazyCommitWait(sb)` calls within the unmount sequence. This is critical for data integrity, so I need to carefully consider the appropriate locations to place these calls, ensuring they trigger at the right points in the unmount process to handle any pending transactions.
|
| 106/4 |
2026/05/11 23:49 |
tool |
codesearch-file-index |
0m
Args: map[SourceFile:fs/jfs/jfs_umount.c]
Results: map[Entities:[map[Kind:function Name:jfs_umount] map[Kind:function Name:jfs_umount_rw]]]
|
| 107/4 |
2026/05/11 23:49 |
llm |
patch-generator |
0m
Model:
Tokens:
input: 18932
output: 46
thoughts: 21
Thoughts: Okay, let's dive into this. Here's my take on those functions, as if they were my own mental process:
**Unmounting JFS Filesystems: A Deep Dive**
Alright, so I'm thinking about `jfs_umount` and `jfs_umount_rw`. These are the key pieces, aren't they, when we're talking about safely unmounting a JFS filesystem? I need to remember exactly what each one does, and how they relate. `jfs_umount`, from what I recall, is the generic unmount function, the entry point for removing a JFS filesystem from the mount table. It's probably responsible for the initial checks, like verifying that the filesystem is indeed mounted, that no processes are actively using it, and that any required cleanup steps are performed. Think file system type specific checks, or pre-unmount steps. I bet it handles the basic infrastructure that's independent of whether the unmount will succeed or is forced.
And then we have `jfs_umount_rw`, that's the real meat, isn't it? That's where the *real* work happens, the gritty details. My guess is it's the more nuanced function, the one that deals with things like cleaning up the journal, ensuring data integrity, and perhaps handling read-write status transitions if we're dealing with a read-only unmount. If forced, I'll bet `jfs_umount_rw` has the logic to deal with dirty pages, processes still referencing the mount, and anything else that might be blocking a clean unmount.
I bet there's some sort of mutex or locking mechanism in place between these two, to prevent race conditions during the unmount process. `jfs_umount` has to coordinate the call to `jfs_umount_rw`, otherwise, things are bound to go south fast. I also wonder how the filesystem's metadata is updated during the unmount β the mount point entry has to be removed, and that changes have to be persisted.
I'm also curious about what happens if something goes wrong. Does it leave the filesystem in a potentially inconsistent state? Does it attempt to roll back any changes it's made, or does it require a manual fsck? That's the real test of a robust unmount implementation.
|
| 108/4 |
2026/05/11 23:49 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:fs/jfs/jfs_umount.c IncludeLines:true Name:jfs_umount]
Results: map[SourceCode: 27: /*
28: * NAME: jfs_umount(vfsp, flags, crp)
29: *
30: * FUNCTION: vfs_umount()
31: *
32: * PARAMETERS: vfsp - virtual file system pointer
33: * flags - unmount for shutdown
34: * crp - credential
35: *
36: * RETURN : EBUSY - device has open files
37: */
38: int jfs_umount(struct super_block *sb)
39: {
40: struct jfs_sb_info *sbi = JFS_SBI(sb);
41: struct inode *ipbmap = sbi->ipbmap;
42: struct inode *ipimap = sbi->ipimap;
43: struct inode *ipaimap = sbi->ipaimap;
44: struct inode *ipaimap2 = sbi->ipaimap2;
45: struct jfs_log *log;
46: int rc = 0;
47:
48: jfs_info("UnMount JFS: sb:0x%p", sb);
49:
50: /*
51: * update superblock and close log
52: *
53: * if mounted read-write and log based recovery was enabled
54: */
55: if ((log = sbi->log))
56: /*
57: * Wait for outstanding transactions to be written to log:
58: */
59: jfs_flush_journal(log, 2);
60:
61: /*
62: * Hold log lock so write_special_inodes (lmLogSync) cannot see
63: * this sbi with a NULL inode pointer while iterating log->sb_list.
64: */
65: if (log)
66: LOG_LOCK(log);
67: /*
68: * close fileset inode allocation map (aka fileset inode)
69: */
70: diUnmount(ipimap, 0);
71:
72: diFreeSpecial(ipimap);
73: sbi->ipimap = NULL;
74:
75: /*
76: * close secondary aggregate inode allocation map
77: */
78: if (ipaimap2) {
79: diUnmount(ipaimap2, 0);
80: diFreeSpecial(ipaimap2);
81: sbi->ipaimap2 = NULL;
82: }
83:
84: /*
85: * close aggregate inode allocation map
86: */
87: diUnmount(ipaimap, 0);
88: diFreeSpecial(ipaimap);
89: sbi->ipaimap = NULL;
90:
91: /*
92: * close aggregate block allocation map
93: */
94: dbUnmount(ipbmap, 0);
95:
96: diFreeSpecial(ipbmap);
97: sbi->ipbmap = NULL;
98:
99: /*
100: * Make sure all metadata makes it to disk before we mark
101: * the superblock as clean
102: */
103: filemap_write_and_wait(sbi->direct_inode->i_mapping);
104:
105: if (log)
106: LOG_UNLOCK(log);
107:
108: /*
109: * ensure all file system file pages are propagated to their
110: * home blocks on disk (and their in-memory buffer pages are
111: * invalidated) BEFORE updating file system superblock state
112: * (to signify file system is unmounted cleanly, and thus in
113: * consistent state) and log superblock active file system
114: * list (to signify skip logredo()).
115: */
116: if (log) { /* log = NULL if read-only mount */
117: updateSuper(sb, FM_CLEAN);
118:
119: /*
120: * close log:
121: *
122: * remove file system from log active file system list.
123: */
124: rc = lmLogClose(sb);
125: }
126: jfs_info("UnMount JFS Complete: rc = %d", rc);
127: return rc;
128: }
SourceFile:fs/jfs/jfs_umount.c]
|
| 109/4 |
2026/05/11 23:49 |
llm |
patch-generator |
0m
Model:
Tokens:
input: 20826
output: 246
thoughts: 25
Thoughts: Okay, here's my take on those thoughts, tailored for an expert audience:
**Analyzing the `jfs_umount` Implementation**
Alright, so I'm diving into `fs/jfs/jfs_umount.c` to poke around the `jfs_umount` function. My main focus is, as always, making sure unmounting JFS volumes is rock solid. I'm thinking about the potential race conditions, especially around those crucial metadata flushes and the handling of any outstanding I/O operations. I'll need to scrutinize how it deals with dirty buffers, super block updates, and the various locking mechanisms to see if there's any room for improvement, or potential vulnerabilities in edge cases. Specifically, I'll be looking for any place that might lead to inconsistencies if a process gets interrupted. I will want to check if the behavior on a 'force' unmount is safe, and verify it's not possible to corrupt the JFS filesystem in the event of an unclean shutdown. This may involve examining how the code interacts with the JFS journal and how it handles the final commit sequence. It's a critical part of the filesystem lifecycle, so I need to ensure it's robust and efficient.
|
| 110/4 |
2026/05/11 23:49 |
tool |
codeeditor |
0m
Args: map[CurrentCode: /*
* update superblock and close log
*
* if mounted read-write and log based recovery was enabled
*/
if ((log = sbi->log))
/*
* Wait for outstanding transactions to be written to log:
*/
jfs_flush_journal(log, 2);
/*
* Hold log lock so write_special_inodes (lmLogSync) cannot see NewCode: /*
* update superblock and close log
*
* if mounted read-write and log based recovery was enabled
*/
if ((log = sbi->log)) {
/*
* Wait for outstanding transactions to be written to log:
*/
jfs_flush_journal(log, 2);
txLazyCommitWait(sb);
}
/*
* Hold log lock so write_special_inodes (lmLogSync) cannot see SourceFile:fs/jfs/jfs_umount.c]
Results:
|
| 111/4 |
2026/05/11 23:49 |
llm |
patch-generator |
0m
Model:
Tokens:
input: 21364
output: 48
thoughts: 14
Thoughts: Okay, let's dive into this. Here's my take on those thoughts, as if they're my own:
**Analyzing `jfs_umount_rw`**
Alright, let's zero in on `jfs_umount_rw`. I need to understand its role. It's obviously related to unmounting, and the "rw" suggests something about read-write operations, perhaps how it handles the transition during the unmount process. My initial assumption is that this function will be crucial in ensuring data integrity when unmounting a JFS filesystem that may still have active read-write operations in progress. I would expect it handles flushing any dirty buffers, preventing corruption, and potentially placing the filesystem into a consistent state before ultimately allowing the unmount to proceed. I will want to carefully look at it's interaction with the journalling code, if it exists, to see how transactions are handled during unmount. Specifically, does it force the journalling to complete during unmount? I should also examine error handling; what are the failure cases, and how are they managed? Are there checks for open files or busy processes? This is the starting point for me. I'll need to dissect the actual code to get a deeper understanding.
|
| 112/4 |
2026/05/11 23:49 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:fs/jfs/jfs_umount.c IncludeLines:true Name:jfs_umount_rw]
Results: map[SourceCode: 131: int jfs_umount_rw(struct super_block *sb)
132: {
133: struct jfs_sb_info *sbi = JFS_SBI(sb);
134: struct jfs_log *log = sbi->log;
135:
136: if (!log)
137: return 0;
138:
139: /*
140: * close log:
141: *
142: * remove file system from log active file system list.
143: */
144: jfs_flush_journal(log, 2);
145:
146: /*
147: * Make sure all metadata makes it to disk
148: */
149: dbSync(sbi->ipbmap);
150: diSync(sbi->ipimap);
151:
152: /*
153: * Note that we have to do this even if sync_blockdev() will
154: * do exactly the same a few instructions later: We can't
155: * mark the superblock clean before everything is flushed to
156: * disk.
157: */
158: filemap_write_and_wait(sbi->direct_inode->i_mapping);
159:
160: updateSuper(sb, FM_CLEAN);
161:
162: return lmLogClose(sb);
163: }
SourceFile:fs/jfs/jfs_umount.c]
|
| 113/4 |
2026/05/11 23:49 |
llm |
patch-generator |
0m
Model:
Tokens:
input: 22152
output: 164
thoughts: 27
Thoughts: Okay, here's my take on those thoughts, tailored for an expert audience, and written as if they were my own:
**JFS Unmount Dive**
Alright, time to dive into `jfs_umount_rw`. I need to make some edits in `fs/jfs/jfs_umount.c`. I'm guessing this revolves around a specific unmount scenario. Given the name, it's likely dealing with read/write file systems, so I need to make sure I'm carefully considering the implications for journaling, data flushing, and the overall consistency of the file system. Iβll need to refresh my memory on the intricacies of the JFS unmount sequence, paying particular attention to how it handles dirty buffers and pending I/O operations. Hopefully this is contained, and not a massive refactor. Let's see what needs to be changed.
|
| 114/4 |
2026/05/11 23:50 |
tool |
codeeditor |
0m
Args: map[CurrentCode: /*
* close log:
*
* remove file system from log active file system list.
*/
jfs_flush_journal(log, 2);
/*
* Make sure all metadata makes it to disk
*/ NewCode: /*
* close log:
*
* remove file system from log active file system list.
*/
jfs_flush_journal(log, 2);
txLazyCommitWait(sb);
/*
* Make sure all metadata makes it to disk
*/ SourceFile:fs/jfs/jfs_umount.c]
Results:
|
| 115/4 |
2026/05/11 23:50 |
llm |
patch-generator |
0m
Model:
Tokens:
input: 22536
output: 53
thoughts: 383
Thoughts: **Analyzing the `txLazyCommitWait` Function**
Okay, let's dive into these changes. The objective here, in `fs/jfs/jfs_txnmgr.c`, seems to be ensuring that the lazy commit thread finishes processing all transactions related to a given superblock before proceeding. The `txLazyCommitWait` function appears to be the mechanism for this.
First, I see the function acquires some synchronization using the superblock's `jfs_sb_info` and the associated log, which makes perfect sense. The initial check for a null log is a good safeguard. The spinlock `log->gclock` is used for synchronization with `lmPostGC`, which indicates some kind of garbage collection mechanism, and that's critical to ensure all transactions removed from the commit queue are properly handled.
Now, the main loop is interesting. It's a busy-wait loop, which isn't ideal, but probably necessary here for atomicity given the kernel context. It looks like it's repeatedly checking two conditions: whether the superblock is currently *in* the lazy commit process (`sbi->commit_state & IN_LAZYCOMMIT`) and whether any transaction blocks (`tblk`) associated with the superblock still exist in the `unlock_queue`. The use of `LAZY_LOCK` and `LAZY_UNLOCK` macros tells me we're dealing with some custom locking mechanism specific to this module.
If *either* of those conditions is true β meaning work is still pending β it calls `msleep(10)`. Wait a minute, `msleep(10)`! That function requires `<linux/delay.h>`. I'm curious if this header is correctly included here. It's critical that the appropriate headers are in place to ensure everything compiles and links as expected. Let me just quickly confirm that the header file is properly included in this source file. The kernel is a complex beast, so this is just due diligence.
|
| 116/4 |
2026/05/11 23:50 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:fs/jfs/jfs_txnmgr.c IncludeLines:true Name:__UNIQUE_ID_modinfo_894]
Results: map[SourceCode: 85: module_param(nTxBlock, int, 0);
SourceFile:fs/jfs/jfs_txnmgr.c]
|
| 117/4 |
2026/05/11 23:50 |
llm |
patch-generator |
0m
Model:
Tokens:
input: 23439
output: 28
thoughts: 22
Thoughts: Here's a first-person summary, tailored for an expert audience, of the thought process described:
**Examining JFS Transaction Manager Includes**
Alright, time to dive into the heart of the JFS transaction management implementation. My first step is to get a solid grasp of the dependencies, so I'm heading straight for the include directives in `fs/jfs/jfs_txnmgr.c`. I need to understand what other JFS components and potentially even core kernel structures this module relies upon. This initial pass will quickly highlight the major subsystems interacting with the transaction manager. Are we talking about buffer cache manipulation, logging facilities, inode management, or all of the above? A quick scan of these includes is crucial to understanding the scope and complexity of the code. This will help me rapidly identify areas of focus for deeper analysis.
|
| 118/4 |
2026/05/11 23:50 |
tool |
read-file |
0m
Args: map[File:fs/jfs/jfs_txnmgr.c]
Results: map[Contents:// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) International Business Machines Corp., 2000-2005
* Portions Copyright (C) Christoph Hellwig, 2001-2002
*/
/*
* jfs_txnmgr.c: transaction manager
*
* notes:
* transaction starts with txBegin() and ends with txCommit()
* or txAbort().
*
* tlock is acquired at the time of update;
* (obviate scan at commit time for xtree and dtree)
* tlock and mp points to each other;
* (no hashlist for mp -> tlock).
*
* special cases:
* tlock on in-memory inode:
* in-place tlock in the in-memory inode itself;
* converted to page lock by iWrite() at commit time.
*
* tlock during write()/mmap() under anonymous transaction (tid = 0):
* transferred (?) to transaction at commit time.
*
* use the page itself to update allocation maps
* (obviate intermediate replication of allocation/deallocation data)
* hold on to mp+lock thru update of maps
*/
#include <linux/fs.h>
#include <linux/vmalloc.h>
#include <linux/completion.h>
#include <linux/freezer.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kthread.h>
#include <linux/seq_file.h>
#include "jfs_incore.h"
#include "jfs_inode.h"
#include "jfs_filsys.h"
#include "jfs_metapage.h"
#include "jfs_dinode.h"
#include "jfs_imap.h"
#include "jfs_dmap.h"
#include "jfs_superblock.h"
#include "jfs_debug.h"
/*
* transaction management structures
*/
static struct {
int freetid; /* index of a free tid structure */
int freelock; /* index first free lock word */
wait_queue_head_t freewait; /* eventlist of free tblock */
wait_queue_head_t freelockwait; /* eventlist of free tlock */
wait_queue_head_t lowlockwait; /* eventlist of ample tlocks */
int tlocksInUse; /* Number of tlocks in use */
spinlock_t LazyLock; /* synchronize sync_queue & unlock_queue */
/* struct tblock *sync_queue; * Transactions waiting for data sync */
struct list_head unlock_queue; /* Txns waiting to be released */
struct list_head anon_list; /* inodes having anonymous txns */
struct list_head anon_list2; /* inodes having anonymous txns
that couldn't be sync'ed */
} TxAnchor;
int jfs_tlocks_low; /* Indicates low number of available tlocks */
#ifdef CONFIG_JFS_STATISTICS
static struct {
uint txBegin;
uint txBegin_barrier;
uint txBegin_lockslow;
uint txBegin_freetid;
uint txBeginAnon;
uint txBeginAnon_barrier;
uint txBeginAnon_lockslow;
uint txLockAlloc;
uint txLockAlloc_freelock;
} TxStat;
#endif
static int nTxBlock = -1; /* number of transaction blocks */
module_param(nTxBlock, int, 0);
MODULE_PARM_DESC(nTxBlock,
"Number of transaction blocks (max:65536)");
static int nTxLock = -1; /* number of transaction locks */
module_param(nTxLock, int, 0);
MODULE_PARM_DESC(nTxLock,
"Number of transaction locks (max:65536)");
struct tblock *TxBlock; /* transaction block table */
static int TxLockLWM; /* Low water mark for number of txLocks used */
static int TxLockHWM; /* High water mark for number of txLocks used */
static int TxLockVHWM; /* Very High water mark */
struct tlock *TxLock; /* transaction lock table */
/*
* transaction management lock
*/
static DEFINE_SPINLOCK(jfsTxnLock);
#define TXN_LOCK() spin_lock(&jfsTxnLock)
#define TXN_UNLOCK() spin_unlock(&jfsTxnLock)
#define LAZY_LOCK_INIT() spin_lock_init(&TxAnchor.LazyLock)
#define LAZY_LOCK(flags) spin_lock_irqsave(&TxAnchor.LazyLock, flags)
#define LAZY_UNLOCK(flags) spin_unlock_irqrestore(&TxAnchor.LazyLock, flags)
static DECLARE_WAIT_QUEUE_HEAD(jfs_commit_thread_wait);
static int jfs_commit_thread_waking;
/*
* Retry logic exist outside these macros to protect from spurrious wakeups.
*/
static inline void TXN_SLEEP_DROP_LOCK(wait_queue_head_t * event)
{
DECLARE_WAITQUEUE(wait, current);
add_wait_queue(event, &wait);
set_current_state(TASK_UNINTERRUPTIBLE);
TXN_UNLOCK();
io_schedule();
remove_wait_queue(event, &wait);
}
#define TXN_SLEEP(event)\
{\
TXN_SLEEP_DROP_LOCK(event);\
TXN_LOCK();\
}
#define TXN_WAKEUP(event) wake_up_all(event)
/*
* statistics
*/
static struct {
tid_t maxtid; /* 4: biggest tid ever used */
lid_t maxlid; /* 4: biggest lid ever used */
int ntid; /* 4: # of transactions performed */
int nlid; /* 4: # of tlocks acquired */
int waitlock; /* 4: # of tlock wait */
} stattx;
/*
* forward references
*/
static void diLog(struct jfs_log *log, struct tblock *tblk, struct lrd *lrd,
struct tlock *tlck, struct commit *cd);
static void dataLog(struct jfs_log *log, struct tblock *tblk, struct lrd *lrd,
struct tlock *tlck);
static void dtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
struct tlock * tlck);
static void mapLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
struct tlock * tlck);
static void txAllocPMap(struct inode *ip, struct maplock * maplock,
struct tblock * tblk);
static void txForce(struct tblock * tblk);
static void txLog(struct jfs_log *log, struct tblock *tblk,
struct commit *cd);
static void txUpdateMap(struct tblock * tblk);
static void txRelease(struct tblock * tblk);
static void xtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
struct tlock * tlck);
static void LogSyncRelease(struct metapage * mp);
/*
* transaction block/lock management
* ---------------------------------
*/
/*
* Get a transaction lock from the free list. If the number in use is
* greater than the high water mark, wake up the sync daemon. This should
* free some anonymous transaction locks. (TXN_LOCK must be held.)
*/
static lid_t txLockAlloc(void)
{
lid_t lid;
INCREMENT(TxStat.txLockAlloc);
if (!TxAnchor.freelock) {
INCREMENT(TxStat.txLockAlloc_freelock);
}
while (!(lid = TxAnchor.freelock))
TXN_SLEEP(&TxAnchor.freelockwait);
TxAnchor.freelock = TxLock[lid].next;
HIGHWATERMARK(stattx.maxlid, lid);
if ((++TxAnchor.tlocksInUse > TxLockHWM) && (jfs_tlocks_low == 0)) {
jfs_info("txLockAlloc tlocks low");
jfs_tlocks_low = 1;
wake_up_process(jfsSyncThread);
}
return lid;
}
static void txLockFree(lid_t lid)
{
TxLock[lid].tid = 0;
TxLock[lid].next = TxAnchor.freelock;
TxAnchor.freelock = lid;
TxAnchor.tlocksInUse--;
if (jfs_tlocks_low && (TxAnchor.tlocksInUse < TxLockLWM)) {
jfs_info("txLockFree jfs_tlocks_low no more");
jfs_tlocks_low = 0;
TXN_WAKEUP(&TxAnchor.lowlockwait);
}
TXN_WAKEUP(&TxAnchor.freelockwait);
}
/*
* NAME: txInit()
*
* FUNCTION: initialize transaction management structures
*
* RETURN:
*
* serialization: single thread at jfs_init()
*/
int txInit(void)
{
int k, size;
struct sysinfo si;
/* Set defaults for nTxLock and nTxBlock if unset */
if (nTxLock == -1) {
if (nTxBlock == -1) {
/* Base default on memory size */
si_meminfo(&si);
if (si.totalram > (256 * 1024)) /* 1 GB */
nTxLock = 64 * 1024;
else
nTxLock = si.totalram >> 2;
} else if (nTxBlock > (8 * 1024))
nTxLock = 64 * 1024;
else
nTxLock = nTxBlock << 3;
}
if (nTxBlock == -1)
nTxBlock = nTxLock >> 3;
/* Verify tunable parameters */
if (nTxBlock < 16)
nTxBlock = 16; /* No one should set it this low */
if (nTxBlock > 65536)
nTxBlock = 65536;
if (nTxLock < 256)
nTxLock = 256; /* No one should set it this low */
if (nTxLock > 65536)
nTxLock = 65536;
printk(KERN_INFO "JFS: nTxBlock = %d, nTxLock = %d\n",
nTxBlock, nTxLock);
/*
* initialize transaction block (tblock) table
*
* transaction id (tid) = tblock index
* tid = 0 is reserved.
*/
TxLockLWM = (nTxLock * 4) / 10;
TxLockHWM = (nTxLock * 7) / 10;
TxLockVHWM = (nTxLock * 8) / 10;
size = sizeof(struct tblock) * nTxBlock;
TxBlock = vmalloc(size);
if (TxBlock == NULL)
return -ENOMEM;
for (k = 0; k < nTxBlock; k++) {
init_waitqueue_head(&TxBlock[k].gcwait);
init_waitqueue_head(&TxBlock[k].waitor);
INIT_LIST_HEAD(&TxBlock[k].synclist);
}
for (k = 1; k < nTxBlock - 1; k++) {
TxBlock[k].next = k + 1;
}
TxBlock[k].next = 0;
TxAnchor.freetid = 1;
init_waitqueue_head(&TxAnchor.freewait);
stattx.maxtid = 1; /* statistics */
/*
* initialize transaction lock (tlock) table
*
* transaction lock id = tlock index
* tlock id = 0 is reserved.
*/
size = sizeof(struct tlock) * nTxLock;
TxLock = vmalloc(size);
if (TxLock == NULL) {
vfree(TxBlock);
return -ENOMEM;
}
/* initialize tlock table */
for (k = 1; k < nTxLock - 1; k++)
TxLock[k].next = k + 1;
TxLock[k].next = 0;
init_waitqueue_head(&TxAnchor.freelockwait);
init_waitqueue_head(&TxAnchor.lowlockwait);
TxAnchor.freelock = 1;
TxAnchor.tlocksInUse = 0;
INIT_LIST_HEAD(&TxAnchor.anon_list);
INIT_LIST_HEAD(&TxAnchor.anon_list2);
LAZY_LOCK_INIT();
INIT_LIST_HEAD(&TxAnchor.unlock_queue);
stattx.maxlid = 1; /* statistics */
return 0;
}
/*
* NAME: txExit()
*
* FUNCTION: clean up when module is unloaded
*/
void txExit(void)
{
vfree(TxLock);
TxLock = NULL;
vfree(TxBlock);
TxBlock = NULL;
}
/*
* NAME: txBegin()
*
* FUNCTION: start a transaction.
*
* PARAMETER: sb - superblock
* flag - force for nested tx;
*
* RETURN: tid - transaction id
*
* note: flag force allows to start tx for nested tx
* to prevent deadlock on logsync barrier;
*/
tid_t txBegin(struct super_block *sb, int flag)
{
tid_t t;
struct tblock *tblk;
struct jfs_log *log;
jfs_info("txBegin: flag = 0x%x", flag);
log = JFS_SBI(sb)->log;
if (!log) {
jfs_error(sb, "read-only filesystem\n");
return 0;
}
TXN_LOCK();
INCREMENT(TxStat.txBegin);
retry:
if (!(flag & COMMIT_FORCE)) {
/*
* synchronize with logsync barrier
*/
if (test_bit(log_SYNCBARRIER, &log->flag) ||
test_bit(log_QUIESCE, &log->flag)) {
INCREMENT(TxStat.txBegin_barrier);
TXN_SLEEP(&log->syncwait);
goto retry;
}
}
if (flag == 0) {
/*
* Don't begin transaction if we're getting starved for tlocks
* unless COMMIT_FORCE or COMMIT_INODE (which may ultimately
* free tlocks)
*/
if (TxAnchor.tlocksInUse > TxLockVHWM) {
INCREMENT(TxStat.txBegin_lockslow);
TXN_SLEEP(&TxAnchor.lowlockwait);
goto retry;
}
}
/*
* allocate transaction id/block
*/
if ((t = TxAnchor.freetid) == 0) {
jfs_info("txBegin: waiting for free tid");
INCREMENT(TxStat.txBegin_freetid);
TXN_SLEEP(&TxAnchor.freewait);
goto retry;
}
tblk = tid_to_tblock(t);
if ((tblk->next == 0) && !(flag & COMMIT_FORCE)) {
/* Don't let a non-forced transaction take the last tblk */
jfs_info("txBegin: waiting for free tid");
INCREMENT(TxStat.txBegin_freetid);
TXN_SLEEP(&TxAnchor.freewait);
goto retry;
}
TxAnchor.freetid = tblk->next;
/*
* initialize transaction
*/
/*
* We can't zero the whole thing or we screw up another thread being
* awakened after sleeping on tblk->waitor
*
* memset(tblk, 0, sizeof(struct tblock));
*/
tblk->next = tblk->last = tblk->xflag = tblk->flag = tblk->lsn = 0;
tblk->sb = sb;
++log->logtid;
tblk->logtid = log->logtid;
++log->active;
HIGHWATERMARK(stattx.maxtid, t); /* statistics */
INCREMENT(stattx.ntid); /* statistics */
TXN_UNLOCK();
jfs_info("txBegin: returning tid = %d", t);
return t;
}
/*
* NAME: txBeginAnon()
*
* FUNCTION: start an anonymous transaction.
* Blocks if logsync or available tlocks are low to prevent
* anonymous tlocks from depleting supply.
*
* PARAMETER: sb - superblock
*
* RETURN: none
*/
void txBeginAnon(struct super_block *sb)
{
struct jfs_log *log;
log = JFS_SBI(sb)->log;
TXN_LOCK();
INCREMENT(TxStat.txBeginAnon);
retry:
/*
* synchronize with logsync barrier
*/
if (test_bit(log_SYNCBARRIER, &log->flag) ||
test_bit(log_QUIESCE, &log->flag)) {
INCREMENT(TxStat.txBeginAnon_barrier);
TXN_SLEEP(&log->syncwait);
goto retry;
}
/*
* Don't begin transaction if we're getting starved for tlocks
*/
if (TxAnchor.tlocksInUse > TxLockVHWM) {
INCREMENT(TxStat.txBeginAnon_lockslow);
TXN_SLEEP(&TxAnchor.lowlockwait);
goto retry;
}
TXN_UNLOCK();
}
/*
* txEnd()
*
* function: free specified transaction block.
*
* logsync barrier processing:
*
* serialization:
*/
void txEnd(tid_t tid)
{
struct tblock *tblk = tid_to_tblock(tid);
struct jfs_log *log;
jfs_info("txEnd: tid = %d", tid);
TXN_LOCK();
/*
* wakeup transactions waiting on the page locked
* by the current transaction
*/
TXN_WAKEUP(&tblk->waitor);
log = JFS_SBI(tblk->sb)->log;
/*
* Lazy commit thread can't free this guy until we mark it UNLOCKED,
* otherwise, we would be left with a transaction that may have been
* reused.
*
* Lazy commit thread will turn off tblkGC_LAZY before calling this
* routine.
*/
if (tblk->flag & tblkGC_LAZY) {
jfs_info("txEnd called w/lazy tid: %d, tblk = 0x%p", tid, tblk);
TXN_UNLOCK();
spin_lock_irq(&log->gclock); // LOGGC_LOCK
tblk->flag |= tblkGC_UNLOCKED;
spin_unlock_irq(&log->gclock); // LOGGC_UNLOCK
return;
}
jfs_info("txEnd: tid: %d, tblk = 0x%p", tid, tblk);
assert(tblk->next == 0);
/*
* insert tblock back on freelist
*/
tblk->next = TxAnchor.freetid;
TxAnchor.freetid = tid;
/*
* mark the tblock not active
*/
if (--log->active == 0) {
clear_bit(log_FLUSH, &log->flag);
/*
* synchronize with logsync barrier
*/
if (test_bit(log_SYNCBARRIER, &log->flag)) {
TXN_UNLOCK();
/* write dirty metadata & forward log syncpt */
jfs_syncpt(log, 1);
jfs_info("log barrier off: 0x%x", log->lsn);
/* enable new transactions start */
clear_bit(log_SYNCBARRIER, &log->flag);
/* wakeup all waitors for logsync barrier */
TXN_WAKEUP(&log->syncwait);
goto wakeup;
}
}
TXN_UNLOCK();
wakeup:
/*
* wakeup all waitors for a free tblock
*/
TXN_WAKEUP(&TxAnchor.freewait);
}
/*
* txLock()
*
* function: acquire a transaction lock on the specified <mp>
*
* parameter:
*
* return: transaction lock id
*
* serialization:
*/
struct tlock *txLock(tid_t tid, struct inode *ip, struct metapage * mp,
int type)
{
struct jfs_inode_info *jfs_ip = JFS_IP(ip);
int dir_xtree = 0;
lid_t lid;
tid_t xtid;
struct tlock *tlck;
struct xtlock *xtlck;
struct linelock *linelock;
xtpage_t *p;
struct tblock *tblk;
TXN_LOCK();
if (S_ISDIR(ip->i_mode) && (type & tlckXTREE) &&
!(mp->xflag & COMMIT_PAGE)) {
/*
* Directory inode is special. It can have both an xtree tlock
* and a dtree tlock associated with it.
*/
dir_xtree = 1;
lid = jfs_ip->xtlid;
} else
lid = mp->lid;
/* is page not locked by a transaction ? */
if (lid == 0)
goto allocateLock;
jfs_info("txLock: tid:%d ip:0x%p mp:0x%p lid:%d", tid, ip, mp, lid);
/* is page locked by the requester transaction ? */
tlck = lid_to_tlock(lid);
if ((xtid = tlck->tid) == tid) {
TXN_UNLOCK();
goto grantLock;
}
/*
* is page locked by anonymous transaction/lock ?
*
* (page update without transaction (i.e., file write) is
* locked under anonymous transaction tid = 0:
* anonymous tlocks maintained on anonymous tlock list of
* the inode of the page and available to all anonymous
* transactions until txCommit() time at which point
* they are transferred to the transaction tlock list of
* the committing transaction of the inode)
*/
if (xtid == 0) {
tlck->tid = tid;
TXN_UNLOCK();
tblk = tid_to_tblock(tid);
/*
* The order of the tlocks in the transaction is important
* (during truncate, child xtree pages must be freed before
* parent's tlocks change the working map).
* Take tlock off anonymous list and add to tail of
* transaction list
*
* Note: We really need to get rid of the tid & lid and
* use list_head's. This code is getting UGLY!
*/
if (jfs_ip->atlhead == lid) {
if (jfs_ip->atltail == lid) {
/* only anonymous txn.
* Remove from anon_list
*/
TXN_LOCK();
list_del_init(&jfs_ip->anon_inode_list);
TXN_UNLOCK();
}
jfs_ip->atlhead = tlck->next;
} else {
lid_t last;
for (last = jfs_ip->atlhead;
lid_to_tlock(last)->next != lid;
last = lid_to_tlock(last)->next) {
assert(last);
}
lid_to_tlock(last)->next = tlck->next;
if (jfs_ip->atltail == lid)
jfs_ip->atltail = last;
}
/* insert the tlock at tail of transaction tlock list */
if (tblk->next)
lid_to_tlock(tblk->last)->next = lid;
else
tblk->next = lid;
tlck->next = 0;
tblk->last = lid;
goto grantLock;
}
goto waitLock;
/*
* allocate a tlock
*/
allocateLock:
lid = txLockAlloc();
tlck = lid_to_tlock(lid);
/*
* initialize tlock
*/
tlck->tid = tid;
TXN_UNLOCK();
/* mark tlock for meta-data page */
if (mp->xflag & COMMIT_PAGE) {
tlck->flag = tlckPAGELOCK;
/* mark the page dirty and nohomeok */
metapage_nohomeok(mp);
jfs_info("locking mp = 0x%p, nohomeok = %d tid = %d tlck = 0x%p",
mp, mp->nohomeok, tid, tlck);
/* if anonymous transaction, and buffer is on the group
* commit synclist, mark inode to show this. This will
* prevent the buffer from being marked nohomeok for too
* long a time.
*/
if ((tid == 0) && mp->lsn)
set_cflag(COMMIT_Synclist, ip);
}
/* mark tlock for in-memory inode */
else
tlck->flag = tlckINODELOCK;
if (S_ISDIR(ip->i_mode))
tlck->flag |= tlckDIRECTORY;
tlck->type = 0;
/* bind the tlock and the page */
tlck->ip = ip;
tlck->mp = mp;
if (dir_xtree)
jfs_ip->xtlid = lid;
else
mp->lid = lid;
/*
* enqueue transaction lock to transaction/inode
*/
/* insert the tlock at tail of transaction tlock list */
if (tid) {
tblk = tid_to_tblock(tid);
if (tblk->next)
lid_to_tlock(tblk->last)->next = lid;
else
tblk->next = lid;
tlck->next = 0;
tblk->last = lid;
}
/* anonymous transaction:
* insert the tlock at head of inode anonymous tlock list
*/
else {
tlck->next = jfs_ip->atlhead;
jfs_ip->atlhead = lid;
if (tlck->next == 0) {
/* This inode's first anonymous transaction */
jfs_ip->atltail = lid;
TXN_LOCK();
list_add_tail(&jfs_ip->anon_inode_list,
&TxAnchor.anon_list);
TXN_UNLOCK();
}
}
/* initialize type dependent area for linelock */
linelock = (struct linelock *) & tlck->lock;
linelock->next = 0;
linelock->flag = tlckLINELOCK;
linelock->maxcnt = TLOCKSHORT;
linelock->index = 0;
switch (type & tlckTYPE) {
case tlckDTREE:
linelock->l2linesize = L2DTSLOTSIZE;
break;
case tlckXTREE:
linelock->l2linesize = L2XTSLOTSIZE;
xtlck = (struct xtlock *) linelock;
xtlck->header.offset = 0;
xtlck->header.length = 2;
if (type & tlckNEW) {
xtlck->lwm.offset = XTENTRYSTART;
} else {
if (mp->xflag & COMMIT_PAGE)
p = (xtpage_t *) mp->data;
else
p = (xtpage_t *) &jfs_ip->i_xtroot;
xtlck->lwm.offset =
le16_to_cpu(p->header.nextindex);
}
xtlck->lwm.length = 0; /* ! */
xtlck->twm.offset = 0;
xtlck->hwm.offset = 0;
xtlck->index = 2;
break;
case tlckINODE:
linelock->l2linesize = L2INODESLOTSIZE;
break;
case tlckDATA:
linelock->l2linesize = L2DATASLOTSIZE;
break;
default:
jfs_err("UFO tlock:0x%p", tlck);
}
/*
* update tlock vector
*/
grantLock:
tlck->type |= type;
return tlck;
/*
* page is being locked by another transaction:
*/
waitLock:
/* Only locks on ipimap or ipaimap should reach here */
/* assert(jfs_ip->fileset == AGGREGATE_I); */
if (jfs_ip->fileset != AGGREGATE_I) {
printk(KERN_ERR "txLock: trying to lock locked page!");
print_hex_dump(KERN_ERR, "ip: ", DUMP_PREFIX_ADDRESS, 16, 4,
ip, sizeof(*ip), 0);
print_hex_dump(KERN_ERR, "mp: ", DUMP_PREFIX_ADDRESS, 16, 4,
mp, sizeof(*mp), 0);
print_hex_dump(KERN_ERR, "Locker's tblock: ",
DUMP_PREFIX_ADDRESS, 16, 4, tid_to_tblock(tid),
sizeof(struct tblock), 0);
print_hex_dump(KERN_ERR, "Tlock: ", DUMP_PREFIX_ADDRESS, 16, 4,
tlck, sizeof(*tlck), 0);
BUG();
}
INCREMENT(stattx.waitlock); /* statistics */
TXN_UNLOCK();
release_metapage(mp);
TXN_LOCK();
xtid = tlck->tid; /* reacquire after dropping TXN_LOCK */
jfs_info("txLock: in waitLock, tid = %d, xtid = %d, lid = %d",
tid, xtid, lid);
/* Recheck everything since dropping TXN_LOCK */
if (xtid && (tlck->mp == mp) && (mp->lid == lid))
TXN_SLEEP_DROP_LOCK(&tid_to_tblock(xtid)->waitor);
else
TXN_UNLOCK();
jfs_info("txLock: awakened tid = %d, lid = %d", tid, lid);
return NULL;
}
/*
* NAME: txRelease()
*
* FUNCTION: Release buffers associated with transaction locks, but don't
* mark homeok yet. The allows other transactions to modify
* buffers, but won't let them go to disk until commit record
* actually gets written.
*
* PARAMETER:
* tblk -
*
* RETURN: Errors from subroutines.
*/
static void txRelease(struct tblock * tblk)
{
struct metapage *mp;
lid_t lid;
struct tlock *tlck;
TXN_LOCK();
for (lid = tblk->next; lid; lid = tlck->next) {
tlck = lid_to_tlock(lid);
if ((mp = tlck->mp) != NULL &&
(tlck->type & tlckBTROOT) == 0) {
assert(mp->xflag & COMMIT_PAGE);
mp->lid = 0;
}
}
/*
* wakeup transactions waiting on a page locked
* by the current transaction
*/
TXN_WAKEUP(&tblk->waitor);
TXN_UNLOCK();
}
/*
* NAME: txUnlock()
*
* FUNCTION: Initiates pageout of pages modified by tid in journalled
* objects and frees their lockwords.
*/
static void txUnlock(struct tblock * tblk)
{
struct tlock *tlck;
struct linelock *linelock;
lid_t lid, next, llid, k;
struct metapage *mp;
struct jfs_log *log;
int difft, diffp;
unsigned long flags;
jfs_info("txUnlock: tblk = 0x%p", tblk);
log = JFS_SBI(tblk->sb)->log;
/*
* mark page under tlock homeok (its log has been written):
*/
for (lid = tblk->next; lid; lid = next) {
tlck = lid_to_tlock(lid);
next = tlck->next;
jfs_info("unlocking lid = %d, tlck = 0x%p", lid, tlck);
/* unbind page from tlock */
if ((mp = tlck->mp) != NULL &&
(tlck->type & tlckBTROOT) == 0) {
assert(mp->xflag & COMMIT_PAGE);
/* hold buffer
*/
hold_metapage(mp);
assert(mp->nohomeok > 0);
_metapage_homeok(mp);
/* inherit younger/larger clsn */
LOGSYNC_LOCK(log, flags);
if (mp->clsn) {
logdiff(difft, tblk->clsn, log);
logdiff(diffp, mp->clsn, log);
if (difft > diffp)
mp->clsn = tblk->clsn;
} else
mp->clsn = tblk->clsn;
LOGSYNC_UNLOCK(log, flags);
assert(!(tlck->flag & tlckFREEPAGE));
put_metapage(mp);
}
/* insert tlock, and linelock(s) of the tlock if any,
* at head of freelist
*/
TXN_LOCK();
llid = ((struct linelock *) & tlck->lock)->next;
while (llid) {
linelock = (struct linelock *) lid_to_tlock(llid);
k = linelock->next;
txLockFree(llid);
llid = k;
}
txLockFree(lid);
TXN_UNLOCK();
}
tblk->next = tblk->last = 0;
/*
* remove tblock from logsynclist
* (allocation map pages inherited lsn of tblk and
* has been inserted in logsync list at txUpdateMap())
*/
if (tblk->lsn) {
LOGSYNC_LOCK(log, flags);
log->count--;
list_del_init(&tblk->synclist);
LOGSYNC_UNLOCK(log, flags);
}
}
/*
* txMaplock()
*
* function: allocate a transaction lock for freed page/entry;
* for freed page, maplock is used as xtlock/dtlock type;
*/
struct tlock *txMaplock(tid_t tid, struct inode *ip, int type)
{
struct jfs_inode_info *jfs_ip = JFS_IP(ip);
lid_t lid;
struct tblock *tblk;
struct tlock *tlck;
struct maplock *maplock;
TXN_LOCK();
/*
* allocate a tlock
*/
lid = txLockAlloc();
tlck = lid_to_tlock(lid);
/*
* initialize tlock
*/
tlck->tid = tid;
/* bind the tlock and the object */
tlck->flag = tlckINODELOCK;
if (S_ISDIR(ip->i_mode))
tlck->flag |= tlckDIRECTORY;
tlck->ip = ip;
tlck->mp = NULL;
tlck->type = type;
/*
* enqueue transaction lock to transaction/inode
*/
/* insert the tlock at tail of transaction tlock list */
if (tid) {
tblk = tid_to_tblock(tid);
if (tblk->next)
lid_to_tlock(tblk->last)->next = lid;
else
tblk->next = lid;
tlck->next = 0;
tblk->last = lid;
}
/* anonymous transaction:
* insert the tlock at head of inode anonymous tlock list
*/
else {
tlck->next = jfs_ip->atlhead;
jfs_ip->atlhead = lid;
if (tlck->next == 0) {
/* This inode's first anonymous transaction */
jfs_ip->atltail = lid;
list_add_tail(&jfs_ip->anon_inode_list,
&TxAnchor.anon_list);
}
}
TXN_UNLOCK();
/* initialize type dependent area for maplock */
maplock = (struct maplock *) & tlck->lock;
maplock->next = 0;
maplock->maxcnt = 0;
maplock->index = 0;
return tlck;
}
/*
* txLinelock()
*
* function: allocate a transaction lock for log vector list
*/
struct linelock *txLinelock(struct linelock * tlock)
{
lid_t lid;
struct tlock *tlck;
struct linelock *linelock;
TXN_LOCK();
/* allocate a TxLock structure */
lid = txLockAlloc();
tlck = lid_to_tlock(lid);
TXN_UNLOCK();
/* initialize linelock */
linelock = (struct linelock *) tlck;
linelock->next = 0;
linelock->flag = tlckLINELOCK;
linelock->maxcnt = TLOCKLONG;
linelock->index = 0;
if (tlck->flag & tlckDIRECTORY)
linelock->flag |= tlckDIRECTORY;
/* append linelock after tlock */
linelock->next = tlock->next;
tlock->next = lid;
return linelock;
}
/*
* transaction commit management
* -----------------------------
*/
/*
* NAME: txCommit()
*
* FUNCTION: commit the changes to the objects specified in
* clist. For journalled segments only the
* changes of the caller are committed, ie by tid.
* for non-journalled segments the data are flushed to
* disk and then the change to the disk inode and indirect
* blocks committed (so blocks newly allocated to the
* segment will be made a part of the segment atomically).
*
* all of the segments specified in clist must be in
* one file system. no more than 6 segments are needed
* to handle all unix svcs.
*
* if the i_nlink field (i.e. disk inode link count)
* is zero, and the type of inode is a regular file or
* directory, or symbolic link , the inode is truncated
* to zero length. the truncation is committed but the
* VM resources are unaffected until it is closed (see
* iput and iclose).
*
* PARAMETER:
*
* RETURN:
*
* serialization:
* on entry the inode lock on each segment is assumed
* to be held.
*
* i/o error:
*/
int txCommit(tid_t tid, /* transaction identifier */
int nip, /* number of inodes to commit */
struct inode **iplist, /* list of inode to commit */
int flag)
{
int rc = 0;
struct commit cd;
struct jfs_log *log;
struct tblock *tblk;
struct lrd *lrd;
struct inode *ip;
struct jfs_inode_info *jfs_ip;
int k, n;
ino_t top;
struct super_block *sb;
jfs_info("txCommit, tid = %d, flag = %d", tid, flag);
/* is read-only file system ? */
if (isReadOnly(iplist[0])) {
rc = -EROFS;
goto TheEnd;
}
sb = cd.sb = iplist[0]->i_sb;
cd.tid = tid;
if (tid == 0)
tid = txBegin(sb, 0);
tblk = tid_to_tblock(tid);
/*
* initialize commit structure
*/
log = JFS_SBI(sb)->log;
cd.log = log;
/* initialize log record descriptor in commit */
lrd = &cd.lrd;
lrd->logtid = cpu_to_le32(tblk->logtid);
lrd->backchain = 0;
tblk->xflag |= flag;
if ((flag & (COMMIT_FORCE | COMMIT_SYNC)) == 0)
tblk->xflag |= COMMIT_LAZY;
/*
* prepare non-journaled objects for commit
*
* flush data pages of non-journaled file
* to prevent the file getting non-initialized disk blocks
* in case of crash.
* (new blocks - )
*/
cd.iplist = iplist;
cd.nip = nip;
/*
* acquire transaction lock on (on-disk) inodes
*
* update on-disk inode from in-memory inode
* acquiring transaction locks for AFTER records
* on the on-disk inode of file object
*
* sort the inodes array by inode number in descending order
* to prevent deadlock when acquiring transaction lock
* of on-disk inodes on multiple on-disk inode pages by
* multiple concurrent transactions
*/
for (k = 0; k < cd.nip; k++) {
top = (cd.iplist[k])->i_ino;
for (n = k + 1; n < cd.nip; n++) {
ip = cd.iplist[n];
if (ip->i_ino > top) {
top = ip->i_ino;
cd.iplist[n] = cd.iplist[k];
cd.iplist[k] = ip;
}
}
ip = cd.iplist[k];
jfs_ip = JFS_IP(ip);
/*
* BUGBUG - This code has temporarily been removed. The
* intent is to ensure that any file data is written before
* the metadata is committed to the journal. This prevents
* uninitialized data from appearing in a file after the
* journal has been replayed. (The uninitialized data
* could be sensitive data removed by another user.)
*
* The problem now is that we are holding the IWRITELOCK
* on the inode, and calling filemap_fdatawrite on an
* unmapped page will cause a deadlock in jfs_get_block.
*
* The long term solution is to pare down the use of
* IWRITELOCK. We are currently holding it too long.
* We could also be smarter about which data pages need
* to be written before the transaction is committed and
* when we don't need to worry about it at all.
*
* if ((!S_ISDIR(ip->i_mode))
* && (tblk->flag & COMMIT_DELETE) == 0)
* filemap_write_and_wait(ip->i_mapping);
*/
/*
* Mark inode as not dirty. It will still be on the dirty
* inode list, but we'll know not to commit it again unless
* it gets marked dirty again
*/
clear_cflag(COMMIT_Dirty, ip);
/* inherit anonymous tlock(s) of inode */
if (jfs_ip->atlhead) {
lid_to_tlock(jfs_ip->atltail)->next = tblk->next;
tblk->next = jfs_ip->atlhead;
if (!tblk->last)
tblk->last = jfs_ip->atltail;
jfs_ip->atlhead = jfs_ip->atltail = 0;
TXN_LOCK();
list_del_init(&jfs_ip->anon_inode_list);
TXN_UNLOCK();
}
/*
* acquire transaction lock on on-disk inode page
* (become first tlock of the tblk's tlock list)
*/
if (((rc = diWrite(tid, ip))))
goto out;
}
/*
* write log records from transaction locks
*
* txUpdateMap() resets XAD_NEW in XAD.
*/
txLog(log, tblk, &cd);
/*
* Ensure that inode isn't reused before
* lazy commit thread finishes processing
*/
if (tblk->xflag & COMMIT_DELETE) {
ihold(tblk->u.ip);
/*
* Avoid a rare deadlock
*
* If the inode is locked, we may be blocked in
* jfs_commit_inode. If so, we don't want the
* lazy_commit thread doing the last iput() on the inode
* since that may block on the locked inode. Instead,
* commit the transaction synchronously, so the last iput
* will be done by the calling thread (or later)
*/
/*
* I believe this code is no longer needed. Splitting I_LOCK
* into two bits, I_NEW and I_SYNC should prevent this
* deadlock as well. But since I don't have a JFS testload
* to verify this, only a trivial s/I_LOCK/I_SYNC/ was done.
* Joern
*/
if (inode_state_read_once(tblk->u.ip) & I_SYNC)
tblk->xflag &= ~COMMIT_LAZY;
}
ASSERT((!(tblk->xflag & COMMIT_DELETE)) ||
((tblk->u.ip->i_nlink == 0) &&
!test_cflag(COMMIT_Nolink, tblk->u.ip)));
/*
* write COMMIT log record
*/
lrd->type = cpu_to_le16(LOG_COMMIT);
lrd->length = 0;
lmLog(log, tblk, lrd, NULL);
lmGroupCommit(log, tblk);
/*
* - transaction is now committed -
*/
/*
* force pages in careful update
* (imap addressing structure update)
*/
if (flag & COMMIT_FORCE)
txForce(tblk);
/*
* update allocation map.
*
* update inode allocation map and inode:
* free pager lock on memory object of inode if any.
* update block allocation map.
*
* txUpdateMap() resets XAD_NEW in XAD.
*/
if (tblk->xflag & COMMIT_FORCE)
txUpdateMap(tblk);
/*
* free transaction locks and pageout/free pages
*/
txRelease(tblk);
if ((tblk->flag & tblkGC_LAZY) == 0)
txUnlock(tblk);
/*
* reset in-memory object state
*/
for (k = 0; k < cd.nip; k++) {
ip = cd.iplist[k];
jfs_ip = JFS_IP(ip);
/*
* reset in-memory inode state
*/
jfs_ip->bxflag = 0;
jfs_ip->blid = 0;
}
out:
if (rc != 0)
txAbort(tid, 1);
TheEnd:
jfs_info("txCommit: tid = %d, returning %d", tid, rc);
return rc;
}
/*
* NAME: txLog()
*
* FUNCTION: Writes AFTER log records for all lines modified
* by tid for segments specified by inodes in comdata.
* Code assumes only WRITELOCKS are recorded in lockwords.
*
* PARAMETERS:
*
* RETURN :
*/
static void txLog(struct jfs_log *log, struct tblock *tblk, struct commit *cd)
{
struct inode *ip;
lid_t lid;
struct tlock *tlck;
struct lrd *lrd = &cd->lrd;
/*
* write log record(s) for each tlock of transaction,
*/
for (lid = tblk->next; lid; lid = tlck->next) {
tlck = lid_to_tlock(lid);
tlck->flag |= tlckLOG;
/* initialize lrd common */
ip = tlck->ip;
lrd->aggregate = cpu_to_le32(JFS_SBI(ip->i_sb)->aggregate);
lrd->log.redopage.fileset = cpu_to_le32(JFS_IP(ip)->fileset);
lrd->log.redopage.inode = cpu_to_le32(ip->i_ino);
/* write log record of page from the tlock */
switch (tlck->type & tlckTYPE) {
case tlckXTREE:
xtLog(log, tblk, lrd, tlck);
break;
case tlckDTREE:
dtLog(log, tblk, lrd, tlck);
break;
case tlckINODE:
diLog(log, tblk, lrd, tlck, cd);
break;
case tlckMAP:
mapLog(log, tblk, lrd, tlck);
break;
case tlckDATA:
dataLog(log, tblk, lrd, tlck);
break;
default:
jfs_err("UFO tlock:0x%p", tlck);
}
}
return;
}
/*
* diLog()
*
* function: log inode tlock and format maplock to update bmap;
*/
static void diLog(struct jfs_log *log, struct tblock *tblk, struct lrd *lrd,
struct tlock *tlck, struct commit *cd)
{
struct metapage *mp;
pxd_t *pxd;
struct pxd_lock *pxdlock;
mp = tlck->mp;
/* initialize as REDOPAGE record format */
lrd->log.redopage.type = cpu_to_le16(LOG_INODE);
lrd->log.redopage.l2linesize = cpu_to_le16(L2INODESLOTSIZE);
pxd = &lrd->log.redopage.pxd;
/*
* inode after image
*/
if (tlck->type & tlckENTRY) {
/* log after-image for logredo(): */
lrd->type = cpu_to_le16(LOG_REDOPAGE);
PXDaddress(pxd, mp->index);
PXDlength(pxd,
mp->logical_size >> tblk->sb->s_blocksize_bits);
lrd->backchain = cpu_to_le32(lmLog(log, tblk, lrd, tlck));
/* mark page as homeward bound */
tlck->flag |= tlckWRITEPAGE;
} else if (tlck->type & tlckFREE) {
/*
* free inode extent
*
* (pages of the freed inode extent have been invalidated and
* a maplock for free of the extent has been formatted at
* txLock() time);
*
* the tlock had been acquired on the inode allocation map page
* (iag) that specifies the freed extent, even though the map
* page is not itself logged, to prevent pageout of the map
* page before the log;
*/
/* log LOG_NOREDOINOEXT of the freed inode extent for
* logredo() to start NoRedoPage filters, and to update
* imap and bmap for free of the extent;
*/
lrd->type = cpu_to_le16(LOG_NOREDOINOEXT);
/*
* For the LOG_NOREDOINOEXT record, we need
* to pass the IAG number and inode extent
* index (within that IAG) from which the
* extent is being released. These have been
* passed to us in the iplist[1] and iplist[2].
*/
lrd->log.noredoinoext.iagnum =
cpu_to_le32((u32) (size_t) cd->iplist[1]);
lrd->log.noredoinoext.inoext_idx =
cpu_to_le32((u32) (size_t) cd->iplist[2]);
pxdlock = (struct pxd_lock *) & tlck->lock;
*pxd = pxdlock->pxd;
lrd->backchain = cpu_to_le32(lmLog(log, tblk, lrd, NULL));
/* update bmap */
tlck->flag |= tlckUPDATEMAP;
/* mark page as homeward bound */
tlck->flag |= tlckWRITEPAGE;
} else
jfs_err("diLog: UFO type tlck:0x%p", tlck);
return;
}
/*
* dataLog()
*
* function: log data tlock
*/
static void dataLog(struct jfs_log *log, struct tblock *tblk, struct lrd *lrd,
struct tlock *tlck)
{
struct metapage *mp;
pxd_t *pxd;
mp = tlck->mp;
/* initialize as REDOPAGE record format */
lrd->log.redopage.type = cpu_to_le16(LOG_DATA);
lrd->log.redopage.l2linesize = cpu_to_le16(L2DATASLOTSIZE);
pxd = &lrd->log.redopage.pxd;
/* log after-image for logredo(): */
lrd->type = cpu_to_le16(LOG_REDOPAGE);
if (jfs_dirtable_inline(tlck->ip)) {
/*
* The table has been truncated, we've must have deleted
* the last entry, so don't bother logging this
*/
mp->lid = 0;
grab_metapage(mp);
metapage_homeok(mp);
discard_metapage(mp);
tlck->mp = NULL;
return;
}
PXDaddress(pxd, mp->index);
PXDlength(pxd, mp->logical_size >> tblk->sb->s_blocksize_bits);
lrd->backchain = cpu_to_le32(lmLog(log, tblk, lrd, tlck));
/* mark page as homeward bound */
tlck->flag |= tlckWRITEPAGE;
return;
}
/*
* dtLog()
*
* function: log dtree tlock and format maplock to update bmap;
*/
static void dtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
struct tlock * tlck)
{
struct metapage *mp;
struct pxd_lock *pxdlock;
pxd_t *pxd;
mp = tlck->mp;
/* initialize as REDOPAGE/NOREDOPAGE record format */
lrd->log.redopage.type = cpu_to_le16(LOG_DTREE);
lrd->log.redopage.l2linesize = cpu_to_le16(L2DTSLOTSIZE);
pxd = &lrd->log.redopage.pxd;
if (tlck->type & tlckBTROOT)
lrd->log.redopage.type |= cpu_to_le16(LOG_BTROOT);
/*
* page extension via relocation: entry insertion;
* page extension in-place: entry insertion;
* new right page from page split, reinitialized in-line
* root from root page split: entry insertion;
*/
if (tlck->type & (tlckNEW | tlckEXTEND)) {
/* log after-image of the new page for logredo():
* mark log (LOG_NEW) for logredo() to initialize
* freelist and update bmap for alloc of the new page;
*/
lrd->type = cpu_to_le16(LOG_REDOPAGE);
if (tlck->type & tlckEXTEND)
lrd->log.redopage.type |= cpu_to_le16(LOG_EXTEND);
else
lrd->log.redopage.type |= cpu_to_le16(LOG_NEW);
PXDaddress(pxd, mp->index);
PXDlength(pxd,
mp->logical_size >> tblk->sb->s_blocksize_bits);
lrd->backchain = cpu_to_le32(lmLog(log, tblk, lrd, tlck));
/* format a maplock for txUpdateMap() to update bPMAP for
* alloc of the new page;
*/
if (tlck->type & tlckBTROOT)
return;
tlck->flag |= tlckUPDATEMAP;
pxdlock = (struct pxd_lock *) & tlck->lock;
pxdlock->flag = mlckALLOCPXD;
pxdlock->pxd = *pxd;
pxdlock->index = 1;
/* mark page as homeward bound */
tlck->flag |= tlckWRITEPAGE;
return;
}
/*
* entry insertion/deletion,
* sibling page link update (old right page before split);
*/
if (tlck->type & (tlckENTRY | tlckRELINK)) {
/* log after-image for logredo(): */
lrd->type = cpu_to_le16(LOG_REDOPAGE);
PXDaddress(pxd, mp->index);
PXDlength(pxd,
mp->logical_size >> tblk->sb->s_blocksize_bits);
lrd->backchain = cpu_to_le32(lmLog(log, tblk, lrd, tlck));
/* mark page as homeward bound */
tlck->flag |= tlckWRITEPAGE;
return;
}
/*
* page deletion: page has been invalidated
* page relocation: source extent
*
* a maplock for free of the page has been formatted
* at txLock() time);
*/
if (tlck->type & (tlckFREE | tlckRELOCATE)) {
/* log LOG_NOREDOPAGE of the deleted page for logredo()
* to start NoRedoPage filter and to update bmap for free
* of the deletd page
*/
lrd->type = cpu_to_le16(LOG_NOREDOPAGE);
pxdlock = (struct pxd_lock *) & tlck->lock;
*pxd = pxdlock->pxd;
lrd->backchain = cpu_to_le32(lmLog(log, tblk, lrd, NULL));
/* a maplock for txUpdateMap() for free of the page
* has been formatted at txLock() time;
*/
tlck->flag |= tlckUPDATEMAP;
}
return;
}
/*
* xtLog()
*
* function: log xtree tlock and format maplock to update bmap;
*/
static void xtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
struct tlock * tlck)
{
struct inode *ip;
struct metapage *mp;
xtpage_t *p;
struct xtlock *xtlck;
struct maplock *maplock;
struct xdlistlock *xadlock;
struct pxd_lock *pxdlock;
pxd_t *page_pxd;
int next, lwm, hwm;
ip = tlck->ip;
mp = tlck->mp;
/* initialize as REDOPAGE/NOREDOPAGE record format */
lrd->log.redopage.type = cpu_to_le16(LOG_XTREE);
lrd->log.redopage.l2linesize = cpu_to_le16(L2XTSLOTSIZE);
page_pxd = &lrd->log.redopage.pxd;
if (tlck->type & tlckBTROOT) {
lrd->log.redopage.type |= cpu_to_le16(LOG_BTROOT);
p = (xtpage_t *) &JFS_IP(ip)->i_xtroot;
if (S_ISDIR(ip->i_mode))
lrd->log.redopage.type |=
cpu_to_le16(LOG_DIR_XTREE);
} else
p = (xtpage_t *) mp->data;
next = le16_to_cpu(p->header.nextindex);
xtlck = (struct xtlock *) & tlck->lock;
maplock = (struct maplock *) & tlck->lock;
xadlock = (struct xdlistlock *) maplock;
/*
* entry insertion/extension;
* sibling page link update (old right page before split);
*/
if (tlck->type & (tlckNEW | tlckGROW | tlckRELINK)) {
/* log after-image for logredo():
* logredo() will update bmap for alloc of new/extended
* extents (XAD_NEW|XAD_EXTEND) of XAD[lwm:next) from
* after-image of XADlist;
* logredo() resets (XAD_NEW|XAD_EXTEND) flag when
* applying the after-image to the meta-data page.
*/
lrd->type = cpu_to_le16(LOG_REDOPAGE);
PXDaddress(page_pxd, mp->index);
PXDlength(page_pxd,
mp->logical_size >> tblk->sb->s_blocksize_bits);
lrd->backchain = cpu_to_le32(lmLog(log, tblk, lrd, tlck));
/* format a maplock for txUpdateMap() to update bPMAP
* for alloc of new/extended extents of XAD[lwm:next)
* from the page itself;
* txUpdateMap() resets (XAD_NEW|XAD_EXTEND) flag.
*/
lwm = xtlck->lwm.offset;
if (lwm == 0)
lwm = XTPAGEMAXSLOT;
if (lwm == next)
goto out;
if (lwm > next) {
jfs_err("xtLog: lwm > next");
goto out;
}
tlck->flag |= tlckUPDATEMAP;
xadlock->flag = mlckALLOCXADLIST;
xadlock->count = next - lwm;
if ((xadlock->count <= 4) && (tblk->xflag & COMMIT_LAZY)) {
int i;
pxd_t *pxd;
/*
* Lazy commit may allow xtree to be modified before
* txUpdateMap runs. Copy xad into linelock to
* preserve correct data.
*
* We can fit twice as may pxd's as xads in the lock
*/
xadlock->flag = mlckALLOCPXDLIST;
pxd = xadlock->xdlist = &xtlck->pxdlock;
for (i = 0; i < xadlock->count; i++) {
PXDaddress(pxd, addressXAD(&p->xad[lwm + i]));
PXDlength(pxd, lengthXAD(&p->xad[lwm + i]));
p->xad[lwm + i].flag &=
~(XAD_NEW | XAD_EXTENDED);
pxd++;
}
} else {
/*
* xdlist will point to into inode's xtree, ensure
* that transaction is not committed lazily.
*/
xadlock->flag = mlckALLOCXADLIST;
xadlock->xdlist = &p->xad[lwm];
tblk->xflag &= ~COMMIT_LAZY;
}
jfs_info("xtLog: alloc ip:0x%p mp:0x%p tlck:0x%p lwm:%d count:%d",
tlck->ip, mp, tlck, lwm, xadlock->count);
maplock->index = 1;
out:
/* mark page as homeward bound */
tlck->flag |= tlckWRITEPAGE;
return;
}
/*
* page deletion: file deletion/truncation (ref. xtTruncate())
*
* (page will be invalidated after log is written and bmap
* is updated from the page);
*/
if (tlck->type & tlckFREE) {
/* LOG_NOREDOPAGE log for NoRedoPage filter:
* if page free from file delete, NoRedoFile filter from
* inode image of zero link count will subsume NoRedoPage
* filters for each page;
* if page free from file truncattion, write NoRedoPage
* filter;
*
* upadte of block allocation map for the page itself:
* if page free from deletion and truncation, LOG_UPDATEMAP
* log for the page itself is generated from processing
* its parent page xad entries;
*/
/* if page free from file truncation, log LOG_NOREDOPAGE
* of the deleted page for logredo() to start NoRedoPage
* filter for the page;
*/
if (tblk->xflag & COMMIT_TRUNCATE) {
/* write NOREDOPAGE for the page */
lrd->type = cpu_to_le16(LOG_NOREDOPAGE);
PXDaddress(page_pxd, mp->index);
PXDlength(page_pxd,
mp->logical_size >> tblk->sb->
s_blocksize_bits);
lrd->backchain =
cpu_to_le32(lmLog(log, tblk, lrd, NULL));
if (tlck->type & tlckBTROOT) {
/* Empty xtree must be logged */
lrd->type = cpu_to_le16(LOG_REDOPAGE);
lrd->backchain =
cpu_to_le32(lmLog(log, tblk, lrd, tlck));
}
}
/* init LOG_UPDATEMAP of the freed extents
* XAD[XTENTRYSTART:hwm) from the deleted page itself
* for logredo() to update bmap;
*/
lrd->type = cpu_to_le16(LOG_UPDATEMAP);
lrd->log.updatemap.type = cpu_to_le16(LOG_FREEXADLIST);
xtlck = (struct xtlock *) & tlck->lock;
hwm = xtlck->hwm.offset;
lrd->log.updatemap.nxd =
cpu_to_le16(hwm - XTENTRYSTART + 1);
/* reformat linelock for lmLog() */
xtlck->header.offset = XTENTRYSTART;
xtlck->header.length = hwm - XTENTRYSTART + 1;
xtlck->index = 1;
lrd->backchain = cpu_to_le32(lmLog(log, tblk, lrd, tlck));
/* format a maplock for txUpdateMap() to update bmap
* to free extents of XAD[XTENTRYSTART:hwm) from the
* deleted page itself;
*/
tlck->flag |= tlckUPDATEMAP;
xadlock->count = hwm - XTENTRYSTART + 1;
if ((xadlock->count <= 4) && (tblk->xflag & COMMIT_LAZY)) {
int i;
pxd_t *pxd;
/*
* Lazy commit may allow xtree to be modified before
* txUpdateMap runs. Copy xad into linelock to
* preserve correct data.
*
* We can fit twice as may pxd's as xads in the lock
*/
xadlock->flag = mlckFREEPXDLIST;
pxd = xadlock->xdlist = &xtlck->pxdlock;
for (i = 0; i < xadlock->count; i++) {
PXDaddress(pxd,
addressXAD(&p->xad[XTENTRYSTART + i]));
PXDlength(pxd,
lengthXAD(&p->xad[XTENTRYSTART + i]));
pxd++;
}
} else {
/*
* xdlist will point to into inode's xtree, ensure
* that transaction is not committed lazily.
*/
xadlock->flag = mlckFREEXADLIST;
xadlock->xdlist = &p->xad[XTENTRYSTART];
tblk->xflag &= ~COMMIT_LAZY;
}
jfs_info("xtLog: free ip:0x%p mp:0x%p count:%d lwm:2",
tlck->ip, mp, xadlock->count);
maplock->index = 1;
/* mark page as invalid */
if (((tblk->xflag & COMMIT_PWMAP) || S_ISDIR(ip->i_mode))
&& !(tlck->type & tlckBTROOT))
tlck->flag |= tlckFREEPAGE;
/*
else (tblk->xflag & COMMIT_PMAP)
? release the page;
*/
return;
}
/*
* page/entry truncation: file truncation (ref. xtTruncate())
*
* |----------+------+------+---------------|
* | | |
* | | hwm - hwm before truncation
* | next - truncation point
* lwm - lwm before truncation
* header ?
*/
if (tlck->type & tlckTRUNCATE) {
pxd_t pxd; /* truncated extent of xad */
int twm;
/*
* For truncation the entire linelock may be used, so it would
* be difficult to store xad list in linelock itself.
* Therefore, we'll just force transaction to be committed
* synchronously, so that xtree pages won't be changed before
* txUpdateMap runs.
*/
tblk->xflag &= ~COMMIT_LAZY;
lwm = xtlck->lwm.offset;
if (lwm == 0)
lwm = XTPAGEMAXSLOT;
hwm = xtlck->hwm.offset;
twm = xtlck->twm.offset;
/*
* write log records
*/
/* log after-image for logredo():
*
* logredo() will update bmap for alloc of new/extended
* extents (XAD_NEW|XAD_EXTEND) of XAD[lwm:next) from
* after-image of XADlist;
* logredo() resets (XAD_NEW|XAD_EXTEND) flag when
* applying the after-image to the meta-data page.
*/
lrd->type = cpu_to_le16(LOG_REDOPAGE);
PXDaddress(page_pxd, mp->index);
PXDlength(page_pxd,
mp->logical_size >> tblk->sb->s_blocksize_bits);
lrd->backchain = cpu_to_le32(lmLog(log, tblk, lrd, tlck));
/*
* truncate entry XAD[twm == next - 1]:
*/
if (twm == next - 1) {
/* init LOG_UPDATEMAP for logredo() to update bmap for
* free of truncated delta extent of the truncated
* entry XAD[next - 1]:
* (xtlck->pxdlock = truncated delta extent);
*/
pxdlock = (struct pxd_lock *) & xtlck->pxdlock;
/* assert(pxdlock->type & tlckTRUNCATE); */
lrd->type = cpu_to_le16(LOG_UPDATEMAP);
lrd->log.updatemap.type = cpu_to_le16(LOG_FREEPXD);
lrd->log.updatemap.nxd = cpu_to_le16(1);
lrd->log.updatemap.pxd = pxdlock->pxd;
pxd = pxdlock->pxd; /* save to format maplock */
lrd->backchain =
cpu_to_le32(lmLog(log, tblk, lrd, NULL));
}
/*
* free entries XAD[next:hwm]:
*/
if (hwm >= next) {
/* init LOG_UPDATEMAP of the freed extents
* XAD[next:hwm] from the deleted page itself
* for logredo() to update bmap;
*/
lrd->type = cpu_to_le16(LOG_UPDATEMAP);
lrd->log.updatemap.type =
cpu_to_le16(LOG_FREEXADLIST);
xtlck = (struct xtlock *) & tlck->lock;
hwm = xtlck->hwm.offset;
lrd->log.updatemap.nxd =
cpu_to_le16(hwm - next + 1);
/* reformat linelock for lmLog() */
xtlck->header.offset = next;
xtlck->header.length = hwm - next + 1;
xtlck->index = 1;
lrd->backchain =
cpu_to_le32(lmLog(log, tblk, lrd, tlck));
}
/*
* format maplock(s) for txUpdateMap() to update bmap
*/
maplock->index = 0;
/*
* allocate entries XAD[lwm:next):
*/
if (lwm < next) {
/* format a maplock for txUpdateMap() to update bPMAP
* for alloc of new/extended extents of XAD[lwm:next)
* from the page itself;
* txUpdateMap() resets (XAD_NEW|XAD_EXTEND) flag.
*/
tlck->flag |= tlckUPDATEMAP;
xadlock->flag = mlckALLOCXADLIST;
xadlock->count = next - lwm;
xadlock->xdlist = &p->xad[lwm];
jfs_info("xtLog: alloc ip:0x%p mp:0x%p count:%d lwm:%d next:%d",
tlck->ip, mp, xadlock->count, lwm, next);
maplock->index++;
xadlock++;
}
/*
* truncate entry XAD[twm == next - 1]:
*/
if (twm == next - 1) {
/* format a maplock for txUpdateMap() to update bmap
* to free truncated delta extent of the truncated
* entry XAD[next - 1];
* (xtlck->pxdlock = truncated delta extent);
*/
tlck->flag |= tlckUPDATEMAP;
pxdlock = (struct pxd_lock *) xadlock;
pxdlock->flag = mlckFREEPXD;
pxdlock->count = 1;
pxdlock->pxd = pxd;
jfs_info("xtLog: truncate ip:0x%p mp:0x%p count:%d hwm:%d",
ip, mp, pxdlock->count, hwm);
maplock->index++;
xadlock++;
}
/*
* free entries XAD[next:hwm]:
*/
if (hwm >= next) {
/* format a maplock for txUpdateMap() to update bmap
* to free extents of XAD[next:hwm] from thedeleted
* page itself;
*/
tlck->flag |= tlckUPDATEMAP;
xadlock->flag = mlckFREEXADLIST;
xadlock->count = hwm - next + 1;
xadlock->xdlist = &p->xad[next];
jfs_info("xtLog: free ip:0x%p mp:0x%p count:%d next:%d hwm:%d",
tlck->ip, mp, xadlock->count, next, hwm);
maplock->index++;
}
/* mark page as homeward bound */
tlck->flag |= tlckWRITEPAGE;
}
return;
}
/*
* mapLog()
*
* function: log from maplock of freed data extents;
*/
static void mapLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
struct tlock * tlck)
{
struct pxd_lock *pxdlock;
int i, nlock;
pxd_t *pxd;
/*
* page relocation: free the source page extent
*
* a maplock for txUpdateMap() for free of the page
* has been formatted at txLock() time saving the src
* relocated page address;
*/
if (tlck->type & tlckRELOCATE) {
/* log LOG_NOREDOPAGE of the old relocated page
* for logredo() to start NoRedoPage filter;
*/
lrd->type = cpu_to_le16(LOG_NOREDOPAGE);
pxdlock = (struct pxd_lock *) & tlck->lock;
pxd = &lrd->log.redopage.pxd;
*pxd = pxdlock->pxd;
lrd->backchain = cpu_to_le32(lmLog(log, tblk, lrd, NULL));
/* (N.B. currently, logredo() does NOT update bmap
* for free of the page itself for (LOG_XTREE|LOG_NOREDOPAGE);
* if page free from relocation, LOG_UPDATEMAP log is
* specifically generated now for logredo()
* to update bmap for free of src relocated page;
* (new flag LOG_RELOCATE may be introduced which will
* inform logredo() to start NORedoPage filter and also
* update block allocation map at the same time, thus
* avoiding an extra log write);
*/
lrd->type = cpu_to_le16(LOG_UPDATEMAP);
lrd->log.updatemap.type = cpu_to_le16(LOG_FREEPXD);
lrd->log.updatemap.nxd = cpu_to_le16(1);
lrd->log.updatemap.pxd = pxdlock->pxd;
lrd->backchain = cpu_to_le32(lmLog(log, tblk, lrd, NULL));
/* a maplock for txUpdateMap() for free of the page
* has been formatted at txLock() time;
*/
tlck->flag |= tlckUPDATEMAP;
return;
}
/*
* Otherwise it's not a relocate request
*
*/
else {
/* log LOG_UPDATEMAP for logredo() to update bmap for
* free of truncated/relocated delta extent of the data;
* e.g.: external EA extent, relocated/truncated extent
* from xtTailgate();
*/
lrd->type = cpu_to_le16(LOG_UPDATEMAP);
pxdlock = (struct pxd_lock *) & tlck->lock;
nlock = pxdlock->index;
for (i = 0; i < nlock; i++, pxdlock++) {
if (pxdlock->flag & mlckALLOCPXD)
lrd->log.updatemap.type =
cpu_to_le16(LOG_ALLOCPXD);
else
lrd->log.updatemap.type =
cpu_to_le16(LOG_FREEPXD);
lrd->log.updatemap.nxd = cpu_to_le16(1);
lrd->log.updatemap.pxd = pxdlock->pxd;
lrd->backchain =
cpu_to_le32(lmLog(log, tblk, lrd, NULL));
jfs_info("mapLog: xaddr:0x%lx xlen:0x%x",
(ulong) addressPXD(&pxdlock->pxd),
lengthPXD(&pxdlock->pxd));
}
/* update bmap */
tlck->flag |= tlckUPDATEMAP;
}
}
/*
* txEA()
*
* function: acquire maplock for EA/ACL extents or
* set COMMIT_INLINE flag;
*/
void txEA(tid_t tid, struct inode *ip, dxd_t * oldea, dxd_t * newea)
{
struct tlock *tlck = NULL;
struct pxd_lock *maplock = NULL, *pxdlock = NULL;
/*
* format maplock for alloc of new EA extent
*/
if (newea) {
/* Since the newea could be a completely zeroed entry we need to
* check for the two flags which indicate we should actually
* commit new EA data
*/
if (newea->flag & DXD_EXTENT) {
tlck = txMaplock(tid, ip, tlckMAP);
maplock = (struct pxd_lock *) & tlck->lock;
pxdlock = (struct pxd_lock *) maplock;
pxdlock->flag = mlckALLOCPXD;
PXDaddress(&pxdlock->pxd, addressDXD(newea));
PXDlength(&pxdlock->pxd, lengthDXD(newea));
pxdlock++;
maplock->index = 1;
} else if (newea->flag & DXD_INLINE) {
tlck = NULL;
set_cflag(COMMIT_Inlineea, ip);
}
}
/*
* format maplock for free of old EA extent
*/
if (!test_cflag(COMMIT_Nolink, ip) && oldea->flag & DXD_EXTENT) {
if (tlck == NULL) {
tlck = txMaplock(tid, ip, tlckMAP);
maplock = (struct pxd_lock *) & tlck->lock;
pxdlock = (struct pxd_lock *) maplock;
maplock->index = 0;
}
pxdlock->flag = mlckFREEPXD;
PXDaddress(&pxdlock->pxd, addressDXD(oldea));
PXDlength(&pxdlock->pxd, lengthDXD(oldea));
maplock->index++;
}
}
/*
* txForce()
*
* function: synchronously write pages locked by transaction
* after txLog() but before txUpdateMap();
*/
static void txForce(struct tblock * tblk)
{
struct tlock *tlck;
lid_t lid, next;
struct metapage *mp;
/*
* reverse the order of transaction tlocks in
* careful update order of address index pages
* (right to left, bottom up)
*/
tlck = lid_to_tlock(tblk->next);
lid = tlck->next;
tlck->next = 0;
while (lid) {
tlck = lid_to_tlock(lid);
next = tlck->next;
tlck->next = tblk->next;
tblk->next = lid;
lid = next;
}
/*
* synchronously write the page, and
* hold the page for txUpdateMap();
*/
for (lid = tblk->next; lid; lid = next) {
tlck = lid_to_tlock(lid);
next = tlck->next;
if ((mp = tlck->mp) != NULL &&
(tlck->type & tlckBTROOT) == 0) {
assert(mp->xflag & COMMIT_PAGE);
if (tlck->flag & tlckWRITEPAGE) {
tlck->flag &= ~tlckWRITEPAGE;
/* do not release page to freelist */
force_metapage(mp);
#if 0
/*
* The "right" thing to do here is to
* synchronously write the metadata.
* With the current implementation this
* is hard since write_metapage requires
* us to kunmap & remap the page. If we
* have tlocks pointing into the metadata
* pages, we don't want to do this. I think
* we can get by with synchronously writing
* the pages when they are released.
*/
assert(mp->nohomeok);
set_bit(META_dirty, &mp->flag);
set_bit(META_sync, &mp->flag);
#endif
}
}
}
}
/*
* txUpdateMap()
*
* function: update persistent allocation map (and working map
* if appropriate);
*
* parameter:
*/
static void txUpdateMap(struct tblock * tblk)
{
struct inode *ip;
struct inode *ipimap;
lid_t lid;
struct tlock *tlck;
struct maplock *maplock;
struct pxd_lock pxdlock;
int maptype;
int k, nlock;
struct metapage *mp = NULL;
ipimap = JFS_SBI(tblk->sb)->ipimap;
maptype = (tblk->xflag & COMMIT_PMAP) ? COMMIT_PMAP : COMMIT_PWMAP;
/*
* update block allocation map
*
* update allocation state in pmap (and wmap) and
* update lsn of the pmap page;
*/
/*
* scan each tlock/page of transaction for block allocation/free:
*
* for each tlock/page of transaction, update map.
* ? are there tlock for pmap and pwmap at the same time ?
*/
for (lid = tblk->next; lid; lid = tlck->next) {
tlck = lid_to_tlock(lid);
if ((tlck->flag & tlckUPDATEMAP) == 0)
continue;
if (tlck->flag & tlckFREEPAGE) {
/*
* Another thread may attempt to reuse freed space
* immediately, so we want to get rid of the metapage
* before anyone else has a chance to get it.
* Lock metapage, update maps, then invalidate
* the metapage.
*/
mp = tlck->mp;
ASSERT(mp->xflag & COMMIT_PAGE);
grab_metapage(mp);
}
/*
* extent list:
* . in-line PXD list:
* . out-of-line XAD list:
*/
maplock = (struct maplock *) & tlck->lock;
nlock = maplock->index;
for (k = 0; k < nlock; k++, maplock++) {
/*
* allocate blocks in persistent map:
*
* blocks have been allocated from wmap at alloc time;
*/
if (maplock->flag & mlckALLOC) {
txAllocPMap(ipimap, maplock, tblk);
}
/*
* free blocks in persistent and working map:
* blocks will be freed in pmap and then in wmap;
*
* ? tblock specifies the PMAP/PWMAP based upon
* transaction
*
* free blocks in persistent map:
* blocks will be freed from wmap at last reference
* release of the object for regular files;
*
* Alway free blocks from both persistent & working
* maps for directories
*/
else { /* (maplock->flag & mlckFREE) */
if (tlck->flag & tlckDIRECTORY)
txFreeMap(ipimap, maplock,
tblk, COMMIT_PWMAP);
else
txFreeMap(ipimap, maplock,
tblk, maptype);
}
}
if (tlck->flag & tlckFREEPAGE) {
if (!(tblk->flag & tblkGC_LAZY)) {
/* This is equivalent to txRelease */
ASSERT(mp->lid == lid);
tlck->mp->lid = 0;
}
assert(mp->nohomeok == 1);
metapage_homeok(mp);
discard_metapage(mp);
tlck->mp = NULL;
}
}
/*
* update inode allocation map
*
* update allocation state in pmap and
* update lsn of the pmap page;
* update in-memory inode flag/state
*
* unlock mapper/write lock
*/
if (tblk->xflag & COMMIT_CREATE) {
diUpdatePMap(ipimap, tblk->ino, false, tblk);
/* update persistent block allocation map
* for the allocation of inode extent;
*/
pxdlock.flag = mlckALLOCPXD;
pxdlock.pxd = tblk->u.ixpxd;
pxdlock.index = 1;
txAllocPMap(ipimap, (struct maplock *) & pxdlock, tblk);
} else if (tblk->xflag & COMMIT_DELETE) {
ip = tblk->u.ip;
diUpdatePMap(ipimap, ip->i_ino, true, tblk);
iput(ip);
}
}
/*
* txAllocPMap()
*
* function: allocate from persistent map;
*
* parameter:
* ipbmap -
* malock -
* xad list:
* pxd:
*
* maptype -
* allocate from persistent map;
* free from persistent map;
* (e.g., tmp file - free from working map at releae
* of last reference);
* free from persistent and working map;
*
* lsn - log sequence number;
*/
static void txAllocPMap(struct inode *ip, struct maplock * maplock,
struct tblock * tblk)
{
struct inode *ipbmap = JFS_SBI(ip->i_sb)->ipbmap;
struct xdlistlock *xadlistlock;
xad_t *xad;
s64 xaddr;
int xlen;
struct pxd_lock *pxdlock;
struct xdlistlock *pxdlistlock;
pxd_t *pxd;
int n;
/*
* allocate from persistent map;
*/
if (maplock->flag & mlckALLOCXADLIST) {
xadlistlock = (struct xdlistlock *) maplock;
xad = xadlistlock->xdlist;
for (n = 0; n < xadlistlock->count; n++, xad++) {
if (xad->flag & (XAD_NEW | XAD_EXTENDED)) {
xaddr = addressXAD(xad);
xlen = lengthXAD(xad);
dbUpdatePMap(ipbmap, false, xaddr,
(s64) xlen, tblk);
xad->flag &= ~(XAD_NEW | XAD_EXTENDED);
jfs_info("allocPMap: xaddr:0x%lx xlen:%d",
(ulong) xaddr, xlen);
}
}
} else if (maplock->flag & mlckALLOCPXD) {
pxdlock = (struct pxd_lock *) maplock;
xaddr = addressPXD(&pxdlock->pxd);
xlen = lengthPXD(&pxdlock->pxd);
dbUpdatePMap(ipbmap, false, xaddr, (s64) xlen, tblk);
jfs_info("allocPMap: xaddr:0x%lx xlen:%d", (ulong) xaddr, xlen);
} else { /* (maplock->flag & mlckALLOCPXDLIST) */
pxdlistlock = (struct xdlistlock *) maplock;
pxd = pxdlistlock->xdlist;
for (n = 0; n < pxdlistlock->count; n++, pxd++) {
xaddr = addressPXD(pxd);
xlen = lengthPXD(pxd);
dbUpdatePMap(ipbmap, false, xaddr, (s64) xlen,
tblk);
jfs_info("allocPMap: xaddr:0x%lx xlen:%d",
(ulong) xaddr, xlen);
}
}
}
/*
* txFreeMap()
*
* function: free from persistent and/or working map;
*
* todo: optimization
*/
void txFreeMap(struct inode *ip,
struct maplock * maplock, struct tblock * tblk, int maptype)
{
struct inode *ipbmap = JFS_SBI(ip->i_sb)->ipbmap;
struct xdlistlock *xadlistlock;
xad_t *xad;
s64 xaddr;
int xlen;
struct pxd_lock *pxdlock;
struct xdlistlock *pxdlistlock;
pxd_t *pxd;
int n;
jfs_info("txFreeMap: tblk:0x%p maplock:0x%p maptype:0x%x",
tblk, maplock, maptype);
/*
* free from persistent map;
*/
if (maptype == COMMIT_PMAP || maptype == COMMIT_PWMAP) {
if (maplock->flag & mlckFREEXADLIST) {
xadlistlock = (struct xdlistlock *) maplock;
xad = xadlistlock->xdlist;
for (n = 0; n < xadlistlock->count; n++, xad++) {
if (!(xad->flag & XAD_NEW)) {
xaddr = addressXAD(xad);
xlen = lengthXAD(xad);
dbUpdatePMap(ipbmap, true, xaddr,
(s64) xlen, tblk);
jfs_info("freePMap: xaddr:0x%lx xlen:%d",
(ulong) xaddr, xlen);
}
}
} else if (maplock->flag & mlckFREEPXD) {
pxdlock = (struct pxd_lock *) maplock;
xaddr = addressPXD(&pxdlock->pxd);
xlen = lengthPXD(&pxdlock->pxd);
dbUpdatePMap(ipbmap, true, xaddr, (s64) xlen,
tblk);
jfs_info("freePMap: xaddr:0x%lx xlen:%d",
(ulong) xaddr, xlen);
} else { /* (maplock->flag & mlckALLOCPXDLIST) */
pxdlistlock = (struct xdlistlock *) maplock;
pxd = pxdlistlock->xdlist;
for (n = 0; n < pxdlistlock->count; n++, pxd++) {
xaddr = addressPXD(pxd);
xlen = lengthPXD(pxd);
dbUpdatePMap(ipbmap, true, xaddr,
(s64) xlen, tblk);
jfs_info("freePMap: xaddr:0x%lx xlen:%d",
(ulong) xaddr, xlen);
}
}
}
/*
* free from working map;
*/
if (maptype == COMMIT_PWMAP || maptype == COMMIT_WMAP) {
if (maplock->flag & mlckFREEXADLIST) {
xadlistlock = (struct xdlistlock *) maplock;
xad = xadlistlock->xdlist;
for (n = 0; n < xadlistlock->count; n++, xad++) {
xaddr = addressXAD(xad);
xlen = lengthXAD(xad);
dbFree(ip, xaddr, (s64) xlen);
xad->flag = 0;
jfs_info("freeWMap: xaddr:0x%lx xlen:%d",
(ulong) xaddr, xlen);
}
} else if (maplock->flag & mlckFREEPXD) {
pxdlock = (struct pxd_lock *) maplock;
xaddr = addressPXD(&pxdlock->pxd);
xlen = lengthPXD(&pxdlock->pxd);
dbFree(ip, xaddr, (s64) xlen);
jfs_info("freeWMap: xaddr:0x%lx xlen:%d",
(ulong) xaddr, xlen);
} else { /* (maplock->flag & mlckFREEPXDLIST) */
pxdlistlock = (struct xdlistlock *) maplock;
pxd = pxdlistlock->xdlist;
for (n = 0; n < pxdlistlock->count; n++, pxd++) {
xaddr = addressPXD(pxd);
xlen = lengthPXD(pxd);
dbFree(ip, xaddr, (s64) xlen);
jfs_info("freeWMap: xaddr:0x%lx xlen:%d",
(ulong) xaddr, xlen);
}
}
}
}
/*
* txFreelock()
*
* function: remove tlock from inode anonymous locklist
*/
void txFreelock(struct inode *ip)
{
struct jfs_inode_info *jfs_ip = JFS_IP(ip);
struct tlock *xtlck, *tlck;
lid_t xlid = 0, lid;
if (!jfs_ip->atlhead)
return;
TXN_LOCK();
xtlck = (struct tlock *) &jfs_ip->atlhead;
while ((lid = xtlck->next) != 0) {
tlck = lid_to_tlock(lid);
if (tlck->flag & tlckFREELOCK) {
xtlck->next = tlck->next;
txLockFree(lid);
} else {
xtlck = tlck;
xlid = lid;
}
}
if (jfs_ip->atlhead)
jfs_ip->atltail = xlid;
else {
jfs_ip->atltail = 0;
/*
* If inode was on anon_list, remove it
*/
list_del_init(&jfs_ip->anon_inode_list);
}
TXN_UNLOCK();
}
/*
* txAbort()
*
* function: abort tx before commit;
*
* frees line-locks and segment locks for all
* segments in comdata structure.
* Optionally sets state of file-system to FM_DIRTY in super-block.
* log age of page-frames in memory for which caller has
* are reset to 0 (to avoid logwarap).
*/
void txAbort(tid_t tid, int dirty)
{
lid_t lid, next;
struct metapage *mp;
struct tblock *tblk = tid_to_tblock(tid);
struct tlock *tlck;
/*
* free tlocks of the transaction
*/
for (lid = tblk->next; lid; lid = next) {
tlck = lid_to_tlock(lid);
next = tlck->next;
mp = tlck->mp;
JFS_IP(tlck->ip)->xtlid = 0;
if (mp) {
mp->lid = 0;
/*
* reset lsn of page to avoid logwarap:
*
* (page may have been previously committed by another
* transaction(s) but has not been paged, i.e.,
* it may be on logsync list even though it has not
* been logged for the current tx.)
*/
if (mp->xflag & COMMIT_PAGE && mp->lsn)
LogSyncRelease(mp);
}
/* insert tlock at head of freelist */
TXN_LOCK();
txLockFree(lid);
TXN_UNLOCK();
}
/* caller will free the transaction block */
tblk->next = tblk->last = 0;
/*
* mark filesystem dirty
*/
if (dirty)
jfs_error(tblk->sb, "\n");
return;
}
/*
* txLazyCommit(void)
*
* All transactions except those changing ipimap (COMMIT_FORCE) are
* processed by this routine. This insures that the inode and block
* allocation maps are updated in order. For synchronous transactions,
* let the user thread finish processing after txUpdateMap() is called.
*/
static void txLazyCommit(struct tblock * tblk)
{
struct jfs_log *log;
while (((tblk->flag & tblkGC_READY) == 0) &&
((tblk->flag & tblkGC_UNLOCKED) == 0)) {
/* We must have gotten ahead of the user thread
*/
jfs_info("jfs_lazycommit: tblk 0x%p not unlocked", tblk);
yield();
}
jfs_info("txLazyCommit: processing tblk 0x%p", tblk);
txUpdateMap(tblk);
log = (struct jfs_log *) JFS_SBI(tblk->sb)->log;
spin_lock_irq(&log->gclock); // LOGGC_LOCK
tblk->flag |= tblkGC_COMMITTED;
if (tblk->flag & tblkGC_READY)
log->gcrtc--;
wake_up_all(&tblk->gcwait); // LOGGC_WAKEUP
/*
* Can't release log->gclock until we've tested tblk->flag
*/
if (tblk->flag & tblkGC_LAZY) {
spin_unlock_irq(&log->gclock); // LOGGC_UNLOCK
txUnlock(tblk);
tblk->flag &= ~tblkGC_LAZY;
txEnd(tblk - TxBlock); /* Convert back to tid */
} else
spin_unlock_irq(&log->gclock); // LOGGC_UNLOCK
jfs_info("txLazyCommit: done: tblk = 0x%p", tblk);
}
/*
* jfs_lazycommit(void)
*
* To be run as a kernel daemon. If lbmIODone is called in an interrupt
* context, or where blocking is not wanted, this routine will process
* committed transactions from the unlock queue.
*/
int jfs_lazycommit(void *arg)
{
int WorkDone;
struct tblock *tblk;
unsigned long flags;
struct jfs_sb_info *sbi;
set_freezable();
do {
LAZY_LOCK(flags);
jfs_commit_thread_waking = 0; /* OK to wake another thread */
while (!list_empty(&TxAnchor.unlock_queue)) {
WorkDone = 0;
list_for_each_entry(tblk, &TxAnchor.unlock_queue,
cqueue) {
sbi = JFS_SBI(tblk->sb);
/*
* For each volume, the transactions must be
* handled in order. If another commit thread
* is handling a tblk for this superblock,
* skip it
*/
if (sbi->commit_state & IN_LAZYCOMMIT)
continue;
sbi->commit_state |= IN_LAZYCOMMIT;
WorkDone = 1;
/*
* Remove transaction from queue
*/
list_del(&tblk->cqueue);
LAZY_UNLOCK(flags);
txLazyCommit(tblk);
LAZY_LOCK(flags);
sbi->commit_state &= ~IN_LAZYCOMMIT;
/*
* Don't continue in the for loop. (We can't
* anyway, it's unsafe!) We want to go back to
* the beginning of the list.
*/
break;
}
/* If there was nothing to do, don't continue */
if (!WorkDone)
break;
}
/* In case a wakeup came while all threads were active */
jfs_commit_thread_waking = 0;
if (freezing(current)) {
LAZY_UNLOCK(flags);
try_to_freeze();
} else {
DECLARE_WAITQUEUE(wq, current);
add_wait_queue(&jfs_commit_thread_wait, &wq);
set_current_state(TASK_INTERRUPTIBLE);
LAZY_UNLOCK(flags);
schedule();
remove_wait_queue(&jfs_commit_thread_wait, &wq);
}
} while (!kthread_should_stop());
if (!list_empty(&TxAnchor.unlock_queue))
jfs_err("jfs_lazycommit being killed w/pending transactions!");
else
jfs_info("jfs_lazycommit being killed");
return 0;
}
void txLazyUnlock(struct tblock * tblk)
{
unsigned long flags;
LAZY_LOCK(flags);
list_add_tail(&tblk->cqueue, &TxAnchor.unlock_queue);
/*
* Don't wake up a commit thread if there is already one servicing
* this superblock, or if the last one we woke up hasn't started yet.
*/
if (!(JFS_SBI(tblk->sb)->commit_state & IN_LAZYCOMMIT) &&
!jfs_commit_thread_waking) {
jfs_commit_thread_waking = 1;
wake_up(&jfs_commit_thread_wait);
}
LAZY_UNLOCK(flags);
}
static void LogSyncRelease(struct metapage * mp)
{
struct jfs_log *log = mp->log;
assert(mp->nohomeok);
assert(log);
metapage_homeok(mp);
}
/*
* txQuiesce
*
* Block all new transactions and push anonymous transactions to
* completion
*
* This does almost the same thing as jfs_sync below. We don't
* worry about deadlocking when jfs_tlocks_low is set, since we would
* expect jfs_sync to get us out of that jam.
*/
void txQuiesce(struct super_block *sb)
{
struct inode *ip;
struct jfs_inode_info *jfs_ip;
struct jfs_log *log = JFS_SBI(sb)->log;
tid_t tid;
set_bit(log_QUIESCE, &log->flag);
TXN_LOCK();
restart:
while (!list_empty(&TxAnchor.anon_list)) {
jfs_ip = list_entry(TxAnchor.anon_list.next,
struct jfs_inode_info,
anon_inode_list);
ip = &jfs_ip->vfs_inode;
/*
* inode will be removed from anonymous list
* when it is committed
*/
TXN_UNLOCK();
tid = txBegin(ip->i_sb, COMMIT_INODE | COMMIT_FORCE);
mutex_lock(&jfs_ip->commit_mutex);
txCommit(tid, 1, &ip, 0);
txEnd(tid);
mutex_unlock(&jfs_ip->commit_mutex);
/*
* Just to be safe. I don't know how
* long we can run without blocking
*/
cond_resched();
TXN_LOCK();
}
/*
* If jfs_sync is running in parallel, there could be some inodes
* on anon_list2. Let's check.
*/
if (!list_empty(&TxAnchor.anon_list2)) {
list_splice_init(&TxAnchor.anon_list2, &TxAnchor.anon_list);
goto restart;
}
TXN_UNLOCK();
/*
* We may need to kick off the group commit
*/
jfs_flush_journal(log, 0);
}
/*
* txResume()
*
* Allows transactions to start again following txQuiesce
*/
void txResume(struct super_block *sb)
{
struct jfs_log *log = JFS_SBI(sb)->log;
clear_bit(log_QUIESCE, &log->flag);
TXN_WAKEUP(&log->syncwait);
}
/*
* jfs_sync(void)
*
* To be run as a kernel daemon. This is awakened when tlocks run low.
* We write any inodes that have anonymous tlocks so they will become
* available.
*/
int jfs_sync(void *arg)
{
struct inode *ip;
struct jfs_inode_info *jfs_ip;
tid_t tid;
set_freezable();
do {
/*
* write each inode on the anonymous inode list
*/
TXN_LOCK();
while (jfs_tlocks_low && !list_empty(&TxAnchor.anon_list)) {
jfs_ip = list_entry(TxAnchor.anon_list.next,
struct jfs_inode_info,
anon_inode_list);
ip = &jfs_ip->vfs_inode;
if (! igrab(ip)) {
/*
* Inode is being freed
*/
list_del_init(&jfs_ip->anon_inode_list);
} else if (mutex_trylock(&jfs_ip->commit_mutex)) {
/*
* inode will be removed from anonymous list
* when it is committed
*/
TXN_UNLOCK();
tid = txBegin(ip->i_sb, COMMIT_INODE);
txCommit(tid, 1, &ip, 0);
txEnd(tid);
mutex_unlock(&jfs_ip->commit_mutex);
iput(ip);
/*
* Just to be safe. I don't know how
* long we can run without blocking
*/
cond_resched();
TXN_LOCK();
} else {
/* We can't get the commit mutex. It may
* be held by a thread waiting for tlock's
* so let's not block here. Save it to
* put back on the anon_list.
*/
/* Move from anon_list to anon_list2 */
list_move(&jfs_ip->anon_inode_list,
&TxAnchor.anon_list2);
TXN_UNLOCK();
iput(ip);
TXN_LOCK();
}
}
/* Add anon_list2 back to anon_list */
list_splice_init(&TxAnchor.anon_list2, &TxAnchor.anon_list);
if (freezing(current)) {
TXN_UNLOCK();
try_to_freeze();
} else {
set_current_state(TASK_INTERRUPTIBLE);
TXN_UNLOCK();
schedule();
}
} while (!kthread_should_stop());
jfs_info("jfs_sync being killed");
return 0;
}
#if defined(CONFIG_PROC_FS) && defined(CONFIG_JFS_DEBUG)
int jfs_txanchor_proc_show(struct seq_file *m, void *v)
{
char *freewait;
char *freelockwait;
char *lowlockwait;
freewait =
waitqueue_active(&TxAnchor.freewait) ? "active" : "empty";
freelockwait =
waitqueue_active(&TxAnchor.freelockwait) ? "active" : "empty";
lowlockwait =
waitqueue_active(&TxAnchor.lowlockwait) ? "active" : "empty";
seq_printf(m,
"JFS TxAnchor\n"
"============\n"
"freetid = %d\n"
"freewait = %s\n"
"freelock = %d\n"
"freelockwait = %s\n"
"lowlockwait = %s\n"
"tlocksInUse = %d\n"
"jfs_tlocks_low = %d\n"
"unlock_queue is %sempty\n",
TxAnchor.freetid,
freewait,
TxAnchor.freelock,
freelockwait,
lowlockwait,
TxAnchor.tlocksInUse,
jfs_tlocks_low,
list_empty(&TxAnchor.unlock_queue) ? "" : "not ");
return 0;
}
#endif
#if defined(CONFIG_PROC_FS) && defined(CONFIG_JFS_STATISTICS)
int jfs_txstats_proc_show(struct seq_file *m, void *v)
{
seq_printf(m,
"JFS TxStats\n"
"===========\n"
"calls to txBegin = %d\n"
"txBegin blocked by sync barrier = %d\n"
"txBegin blocked by tlocks low = %d\n"
"txBegin blocked by no free tid = %d\n"
"calls to txBeginAnon = %d\n"
"txBeginAnon blocked by sync barrier = %d\n"
"txBeginAnon blocked by tlocks low = %d\n"
"calls to txLockAlloc = %d\n"
"tLockAlloc blocked by no free lock = %d\n",
TxStat.txBegin,
TxStat.txBegin_barrier,
TxStat.txBegin_lockslow,
TxStat.txBegin_freetid,
TxStat.txBeginAnon,
TxStat.txBeginAnon_barrier,
TxStat.txBeginAnon_lockslow,
TxStat.txLockAlloc,
TxStat.txLockAlloc_freelock);
return 0;
}
#endif
]
|
| 119/4 |
2026/05/11 23:50 |
llm |
patch-generator |
0m
Model:
Tokens:
input: 52439
output: 118
thoughts: 73
Thoughts: **Addressing a Missing Header in JFS Code**
Okay, so I'm looking at this `fs/jfs/jfs_txnmgr.c` file and I see the need for `msleep`. Right away, my brain jumps to: "Does this code have `<linux/delay.h>` included?" I can't just assume; I need to verify. Sure enough, after a quick scan, it's missing. That's a straightforward fix. I'll need to add `#include <linux/delay.h>` to the top of the file. No big deal, a simple include statement should do the trick. Now that's handled.
|
| 120/4 |
2026/05/11 23:50 |
tool |
codeeditor |
0m
Args: map[CurrentCode:#include <linux/kthread.h>
#include <linux/seq_file.h>
#include "jfs_incore.h" NewCode:#include <linux/kthread.h>
#include <linux/seq_file.h>
#include <linux/delay.h>
#include "jfs_incore.h" SourceFile:fs/jfs/jfs_txnmgr.c]
Results:
|
| 121/4 |
2026/05/11 23:50 |
llm |
patch-generator |
0m
Model:
Tokens:
input: 52779
output: 44
thoughts: 852
Thoughts: **Analyzing the `txLazyCommitWait` Implementation**
Okay, let's break down this `txLazyCommitWait` function in the JFS file system. My initial goal is to make sure it's doing the right thing. It appears we're waiting for the lazy commit thread to finish its work on a specific superblock.
First, I see the code checks if the `IN_LAZYCOMMIT` flag in `sbi->commit_state` is set. This flag indicates the lazy commit thread is actively working on *some* transaction for this superblock. If it is, the code waits. If the flag isn't set, then it checks the `TxAnchor.unlock_queue`. This queue contains transactions that have been removed from the commit queue (`cqueue`) but haven't been fully processed yet. If any transactions are found in the `unlock_queue` for this superblock, the code waits. Seems reasonable so far.
Now, let me confirm this logic is sound. After a quick scan through `jfs_lazycommit` in `jfs_txnmgr.c`, it seems that `sbi->commit_state` is set *before* removing the transaction from the `unlock_queue` and cleared *after* the `txLazyCommit` is completed. So, the flag/queue combination appears to correctly reflect the state of ongoing lazy commits.
Wait a second, there is a potential issue here: what if `txLazyCommitWait` is called and there are transactions in `cqueue` that haven't been processed by `lmPostGC` yet? I have to account for that. Let me review the explanation again:
"Because `jfs_flush_journal()` only waits for `log->cqueue` to drain, it can return while transactions are still sitting in `TxAnchor.unlock_queue` or are actively being processed by `jfs_lazycommit`."
Ah, that's what that synchronization section is for! The code explicitly synchronizes with `lmPostGC` using `log->gclock`. This guarantees that *all* transactions removed from the `cqueue` have been added to the `unlock_queue` before `txLazyCommitWait` starts checking the queues. This makes sense: `lmPostGC` takes the lock, removes transactions from `cqueue`, and then calls `txLazyUnlock` which puts the transaction into `unlock_queue`.
Now, I think I will check `lmPostGC` in `fs/jfs/jfs_logmgr.c` just to be sure...
|
| 122/4 |
2026/05/11 23:50 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:fs/jfs/jfs_logmgr.c IncludeLines:true Name:lmPostGC]
Results: map[SourceCode: 788: /*
789: * NAME: lmPostGC()
790: *
791: * FUNCTION: group commit post-processing
792: * Processes transactions after their commit records have been written
793: * to disk, redriving log I/O if necessary.
794: *
795: * RETURN: None
796: *
797: * NOTE:
798: * This routine is called a interrupt time by lbmIODone
799: */
800: static void lmPostGC(struct lbuf * bp)
801: {
802: unsigned long flags;
803: struct jfs_log *log = bp->l_log;
804: struct logpage *lp;
805: struct tblock *tblk, *temp;
806:
807: //LOGGC_LOCK(log);
808: spin_lock_irqsave(&log->gclock, flags);
809: /*
810: * current pageout of group commit completed.
811: *
812: * remove/wakeup transactions from commit queue who were
813: * group committed with the current log page
814: */
815: list_for_each_entry_safe(tblk, temp, &log->cqueue, cqueue) {
816: if (!(tblk->flag & tblkGC_COMMIT))
817: break;
818: /* if transaction was marked GC_COMMIT then
819: * it has been shipped in the current pageout
820: * and made it to disk - it is committed.
821: */
822:
823: if (bp->l_flag & lbmERROR)
824: tblk->flag |= tblkGC_ERROR;
825:
826: /* remove it from the commit queue */
827: list_del(&tblk->cqueue);
828: tblk->flag &= ~tblkGC_QUEUE;
829:
830: if (tblk == log->flush_tblk) {
831: /* we can stop flushing the log now */
832: clear_bit(log_FLUSH, &log->flag);
833: log->flush_tblk = NULL;
834: }
835:
836: jfs_info("lmPostGC: tblk = 0x%p, flag = 0x%x", tblk,
837: tblk->flag);
838:
839: if (!(tblk->xflag & COMMIT_FORCE))
840: /*
841: * Hand tblk over to lazy commit thread
842: */
843: txLazyUnlock(tblk);
844: else {
845: /* state transition: COMMIT -> COMMITTED */
846: tblk->flag |= tblkGC_COMMITTED;
847:
848: if (tblk->flag & tblkGC_READY)
849: log->gcrtc--;
850:
851: LOGGC_WAKEUP(tblk);
852: }
853:
854: /* was page full before pageout ?
855: * (and this is the last tblk bound with the page)
856: */
857: if (tblk->flag & tblkGC_FREE)
858: lbmFree(bp);
859: /* did page become full after pageout ?
860: * (and this is the last tblk bound with the page)
861: */
862: else if (tblk->flag & tblkGC_EOP) {
863: /* finalize the page */
864: lp = (struct logpage *) bp->l_ldata;
865: bp->l_ceor = bp->l_eor;
866: lp->h.eor = lp->t.eor = cpu_to_le16(bp->l_eor);
867: jfs_info("lmPostGC: calling lbmWrite");
868: lbmWrite(log, bp, lbmWRITE | lbmRELEASE | lbmFREE,
869: 1);
870: }
871:
872: }
873:
874: /* are there any transactions who have entered lnGroupCommit()
875: * (whose COMMITs are after that of the last log page written.
876: * They are waiting for new group commit (above at (SLEEP 1))
877: * or lazy transactions are on a full (queued) log page,
878: * select the latest ready transaction as new group leader and
879: * wake her up to lead her group.
880: */
881: if ((!list_empty(&log->cqueue)) &&
882: ((log->gcrtc > 0) || (tblk->bp->l_wqnext != NULL) ||
883: test_bit(log_FLUSH, &log->flag) || jfs_tlocks_low))
884: /*
885: * Call lmGCwrite with new group leader
886: */
887: lmGCwrite(log, 1);
888:
889: /* no transaction are ready yet (transactions are only just
890: * queued (GC_QUEUE) and not entered for group commit yet).
891: * the first transaction entering group commit
892: * will elect herself as new group leader.
893: */
894: else
895: log->cflag &= ~logGC_PAGEOUT;
896:
897: //LOGGC_UNLOCK(log);
898: spin_unlock_irqrestore(&log->gclock, flags);
899: return;
900: }
SourceFile:fs/jfs/jfs_logmgr.c]
|
| 123/4 |
2026/05/11 23:50 |
llm |
patch-generator |
1m
Model:
Tokens:
input: 55925
output: 47
thoughts: 143
Thoughts: **My Line of Reasoning**
Okay, so `lmPostGC` does a few key things: it grabs `log->gclock`, takes an entry out of `cqueue`, and then calls `txLazyUnlock(tblk)`. This `txLazyUnlock` function specifically deals with the `TxAnchor.LazyLock` and puts that into the `unlock_queue`. The important part here is the order: taking `log->gclock` and releasing it. This is how we ensure that any transaction that was *removed* from `cqueue` before `jfs_flush_journal` finished, but *hasn't yet* been put into `unlock_queue`, *will* be added to `unlock_queue` *before* we check its status later on.
But wait a minute... `jfs_flush_journal` is supposed to be waiting for `cqueue` to be *empty*, right? This implies that the operations must synchronize somehow. I should take another look at the `jfs_flush_journal` function itself to make sure I am on the right track.
|
| 124/4 |
2026/05/11 23:51 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:fs/jfs/jfs_logmgr.c IncludeLines:true Name:jfs_flush_journal]
Results: map[SourceCode:1496: /*
1497: * NAME: jfs_flush_journal()
1498: *
1499: * FUNCTION: initiate write of any outstanding transactions to the journal
1500: * and optionally wait until they are all written to disk
1501: *
1502: * wait == 0 flush until latest txn is committed, don't wait
1503: * wait == 1 flush until latest txn is committed, wait
1504: * wait > 1 flush until all txn's are complete, wait
1505: */
1506: void jfs_flush_journal(struct jfs_log *log, int wait)
1507: {
1508: int i;
1509: struct tblock *target = NULL;
1510:
1511: /* jfs_write_inode may call us during read-only mount */
1512: if (!log)
1513: return;
1514:
1515: jfs_info("jfs_flush_journal: log:0x%p wait=%d", log, wait);
1516:
1517: LOGGC_LOCK(log);
1518:
1519: if (!list_empty(&log->cqueue)) {
1520: /*
1521: * This ensures that we will keep writing to the journal as long
1522: * as there are unwritten commit records
1523: */
1524: target = list_entry(log->cqueue.prev, struct tblock, cqueue);
1525:
1526: if (test_bit(log_FLUSH, &log->flag)) {
1527: /*
1528: * We're already flushing.
1529: * if flush_tblk is NULL, we are flushing everything,
1530: * so leave it that way. Otherwise, update it to the
1531: * latest transaction
1532: */
1533: if (log->flush_tblk)
1534: log->flush_tblk = target;
1535: } else {
1536: /* Only flush until latest transaction is committed */
1537: log->flush_tblk = target;
1538: set_bit(log_FLUSH, &log->flag);
1539:
1540: /*
1541: * Initiate I/O on outstanding transactions
1542: */
1543: if (!(log->cflag & logGC_PAGEOUT)) {
1544: log->cflag |= logGC_PAGEOUT;
1545: lmGCwrite(log, 0);
1546: }
1547: }
1548: }
1549: if ((wait > 1) || test_bit(log_SYNCBARRIER, &log->flag)) {
1550: /* Flush until all activity complete */
1551: set_bit(log_FLUSH, &log->flag);
1552: log->flush_tblk = NULL;
1553: }
1554:
1555: if (wait && target && !(target->flag & tblkGC_COMMITTED)) {
1556: DECLARE_WAITQUEUE(__wait, current);
1557:
1558: add_wait_queue(&target->gcwait, &__wait);
1559: set_current_state(TASK_UNINTERRUPTIBLE);
1560: LOGGC_UNLOCK(log);
1561: schedule();
1562: LOGGC_LOCK(log);
1563: remove_wait_queue(&target->gcwait, &__wait);
1564: }
1565: LOGGC_UNLOCK(log);
1566:
1567: if (wait < 2)
1568: return;
1569:
1570: write_special_inodes(log, filemap_fdatawrite);
1571:
1572: /*
1573: * If there was recent activity, we may need to wait
1574: * for the lazycommit thread to catch up
1575: */
1576: if ((!list_empty(&log->cqueue)) || !list_empty(&log->synclist)) {
1577: for (i = 0; i < 200; i++) { /* Too much? */
1578: msleep(250);
1579: write_special_inodes(log, filemap_fdatawrite);
1580: if (list_empty(&log->cqueue) &&
1581: list_empty(&log->synclist))
1582: break;
1583: }
1584: }
1585: assert(list_empty(&log->cqueue));
1586:
1587: #ifdef CONFIG_JFS_DEBUG
1588: if (!list_empty(&log->synclist)) {
1589: struct logsyncblk *lp;
1590:
1591: printk(KERN_ERR "jfs_flush_journal: synclist not empty\n");
1592: list_for_each_entry(lp, &log->synclist, synclist) {
1593: if (lp->xflag & COMMIT_PAGE) {
1594: struct metapage *mp = (struct metapage *)lp;
1595: print_hex_dump(KERN_ERR, "metapage: ",
1596: DUMP_PREFIX_ADDRESS, 16, 4,
1597: mp, sizeof(struct metapage), 0);
1598: print_hex_dump(KERN_ERR, "page: ",
1599: DUMP_PREFIX_ADDRESS, 16,
1600: sizeof(long), mp->folio,
1601: sizeof(struct page), 0);
1602: } else
1603: print_hex_dump(KERN_ERR, "tblock:",
1604: DUMP_PREFIX_ADDRESS, 16, 4,
1605: lp, sizeof(struct tblock), 0);
1606: }
1607: }
1608: #else
1609: WARN_ON(!list_empty(&log->synclist));
1610: #endif
1611: clear_bit(log_FLUSH, &log->flag);
1612: }
SourceFile:fs/jfs/jfs_logmgr.c]
|
| 125/4 |
2026/05/11 23:51 |
llm |
patch-generator |
0m
Model:
Tokens:
input: 58153
output: 27
thoughts: 1710
Thoughts: **Deep Dive into JFS Lazy Commit Synchronization**
Okay, so I'm tracing the interactions between `jfs_flush_journal`, `lmPostGC`, and the lazy commit mechanism. It's becoming clear how this synchronization is managed. My initial concern was about a potential race condition: `jfs_flush_journal` checks if `log->cqueue` is empty, but `lmPostGC` might have just removed the last item and *not* yet added it to `unlock_queue`. This could lead to a premature return from `jfs_flush_journal`. The key is in how `txLazyCommitWait` is used and the use of the `gclock` spinlock.
I see that `txLazyCommitWait` takes `log->gclock` and then releases it. And *yes*, `lmPostGC` holds this lock while moving transactions from the `cqueue` to `unlock_queue` and calling `txLazyUnlock`. Bingo! This ensures that `txLazyCommitWait` won't proceed until `lmPostGC` has finished its operation. The comment confirms this design. So, the `gclock` spinlock is crucial to this synchronization.
But, I also needed to account for the lazy commit thread itself. What if `jfs_lazycommit` is currently processing a transaction for a given superblock? My concern was about a scenario where `jfs_lazycommit` might have cleared `IN_LAZYCOMMIT` but not have yet picked up the *next* transaction from the `unlock_queue`. This is where `LAZY_LOCK` comes into play. Since `txLazyCommitWait` also takes this lock while checking both `IN_LAZYCOMMIT` and `unlock_queue`, I'm protected from these race conditions. I'm now certain this locking scheme handles all the scenarios I've considered.
I reviewed the `txLazyCommitWait` implementation, confirming its use of `LAZY_LOCK`, `unlock_queue`, and `IN_LAZYCOMMIT` and am now confident in its correctness. The use of `msleep(10)` looks fine, given where this function is called. It's safe to sleep in this context. I considered the potential for blocking in `jfs_lazycommit`, specifically within `txUpdateMap` which may do I/O, but I'm confident that blocking is handled correctly, and the loop in `txLazyCommitWait` should eventually complete.
I went back and checked the call sites in `jfs_umount.c` and `jfs_umount_rw.c`, confirming that `txLazyCommitWait` is called after `jfs_flush_journal(log, 2)`. I am certain I'm not missing any call sites for `txLazyCommitWait`. Finally, I verified that `txLazyCommitWait` is exported in the `jfs_txnmgr.h` file. I'm now absolutely convinced that this code is race-free, properly synchronized, and correctly implements the lazy commit mechanism.
|
| 126/4 |
2026/05/11 23:51 |
tool |
read-file |
0m
Args: map[File:fs/jfs/jfs_umount.c]
Results: map[Contents:// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) International Business Machines Corp., 2000-2004
*/
/*
* jfs_umount.c
*
* note: file system in transition to aggregate/fileset:
* (ref. jfs_mount.c)
*
* file system unmount is interpreted as mount of the single/only
* fileset in the aggregate and, if unmount of the last fileset,
* as unmount of the aggerate;
*/
#include <linux/fs.h>
#include "jfs_incore.h"
#include "jfs_filsys.h"
#include "jfs_superblock.h"
#include "jfs_dmap.h"
#include "jfs_imap.h"
#include "jfs_logmgr.h"
#include "jfs_metapage.h"
#include "jfs_debug.h"
/*
* NAME: jfs_umount(vfsp, flags, crp)
*
* FUNCTION: vfs_umount()
*
* PARAMETERS: vfsp - virtual file system pointer
* flags - unmount for shutdown
* crp - credential
*
* RETURN : EBUSY - device has open files
*/
int jfs_umount(struct super_block *sb)
{
struct jfs_sb_info *sbi = JFS_SBI(sb);
struct inode *ipbmap = sbi->ipbmap;
struct inode *ipimap = sbi->ipimap;
struct inode *ipaimap = sbi->ipaimap;
struct inode *ipaimap2 = sbi->ipaimap2;
struct jfs_log *log;
int rc = 0;
jfs_info("UnMount JFS: sb:0x%p", sb);
/*
* update superblock and close log
*
* if mounted read-write and log based recovery was enabled
*/
if ((log = sbi->log))
/*
* Wait for outstanding transactions to be written to log:
*/
jfs_flush_journal(log, 2);
/*
* Hold log lock so write_special_inodes (lmLogSync) cannot see
* this sbi with a NULL inode pointer while iterating log->sb_list.
*/
if (log)
LOG_LOCK(log);
/*
* close fileset inode allocation map (aka fileset inode)
*/
diUnmount(ipimap, 0);
diFreeSpecial(ipimap);
sbi->ipimap = NULL;
/*
* close secondary aggregate inode allocation map
*/
if (ipaimap2) {
diUnmount(ipaimap2, 0);
diFreeSpecial(ipaimap2);
sbi->ipaimap2 = NULL;
}
/*
* close aggregate inode allocation map
*/
diUnmount(ipaimap, 0);
diFreeSpecial(ipaimap);
sbi->ipaimap = NULL;
/*
* close aggregate block allocation map
*/
dbUnmount(ipbmap, 0);
diFreeSpecial(ipbmap);
sbi->ipbmap = NULL;
/*
* Make sure all metadata makes it to disk before we mark
* the superblock as clean
*/
filemap_write_and_wait(sbi->direct_inode->i_mapping);
if (log)
LOG_UNLOCK(log);
/*
* ensure all file system file pages are propagated to their
* home blocks on disk (and their in-memory buffer pages are
* invalidated) BEFORE updating file system superblock state
* (to signify file system is unmounted cleanly, and thus in
* consistent state) and log superblock active file system
* list (to signify skip logredo()).
*/
if (log) { /* log = NULL if read-only mount */
updateSuper(sb, FM_CLEAN);
/*
* close log:
*
* remove file system from log active file system list.
*/
rc = lmLogClose(sb);
}
jfs_info("UnMount JFS Complete: rc = %d", rc);
return rc;
}
int jfs_umount_rw(struct super_block *sb)
{
struct jfs_sb_info *sbi = JFS_SBI(sb);
struct jfs_log *log = sbi->log;
if (!log)
return 0;
/*
* close log:
*
* remove file system from log active file system list.
*/
jfs_flush_journal(log, 2);
/*
* Make sure all metadata makes it to disk
*/
dbSync(sbi->ipbmap);
diSync(sbi->ipimap);
/*
* Note that we have to do this even if sync_blockdev() will
* do exactly the same a few instructions later: We can't
* mark the superblock clean before everything is flushed to
* disk.
*/
filemap_write_and_wait(sbi->direct_inode->i_mapping);
updateSuper(sb, FM_CLEAN);
return lmLogClose(sb);
}
]
|
| 127/4 |
2026/05/11 23:51 |
llm |
patch-generator |
0m
Model:
Tokens:
input: 61853
output: 168
thoughts: 61
Thoughts: **My Immediate Task: The Missing Header**
Okay, so I'm digging into `fs/jfs/jfs_umount.c` here, and I've just noticed something that's got my attention. It's not including `jfs_txnmgr.h`. Now, that's not right. This function clearly interacts with transaction management, so I need to explicitly include the header file. This means I'm going to add `#include "jfs_txnmgr.h"` directly into `fs/jfs/jfs_umount.c`. Simple fix, but a necessary one to ensure everything functions as intended and to prevent any potential compile-time errors or, worse, runtime issues down the line.
|
| 128/4 |
2026/05/11 23:51 |
tool |
codeeditor |
0m
Args: map[CurrentCode:#include "jfs_dmap.h"
#include "jfs_imap.h"
#include "jfs_logmgr.h"
#include "jfs_metapage.h"
#include "jfs_debug.h" NewCode:#include "jfs_dmap.h"
#include "jfs_imap.h"
#include "jfs_logmgr.h"
#include "jfs_txnmgr.h"
#include "jfs_metapage.h"
#include "jfs_debug.h" SourceFile:fs/jfs/jfs_umount.c]
Results:
|
| 129/4 |
2026/05/11 23:51 |
llm |
patch-generator |
0m
Model:
Tokens:
input: 62247
output: 27
thoughts: 40
Thoughts: Okay, let's see...
**Checking My Work on `fs/jfs/jfs_umount.c`**
Alright, hang on a second. Didn't I *already* modify `fs/jfs/jfs_umount.c`? Pretty sure I implemented that `txLazyCommitWait(sb)` call in there. Before I go down another rabbit hole, I should just double-check that the change is present. Best to avoid redundant work, especially on this crucial function. Efficiency is key here. Let me confirm that and move on, or if it isn't there, I can investigate.
|
| 130/4 |
2026/05/11 23:51 |
tool |
read-file |
0m
Args: map[File:fs/jfs/jfs_umount.c]
Results: map[Contents:// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) International Business Machines Corp., 2000-2004
*/
/*
* jfs_umount.c
*
* note: file system in transition to aggregate/fileset:
* (ref. jfs_mount.c)
*
* file system unmount is interpreted as mount of the single/only
* fileset in the aggregate and, if unmount of the last fileset,
* as unmount of the aggerate;
*/
#include <linux/fs.h>
#include "jfs_incore.h"
#include "jfs_filsys.h"
#include "jfs_superblock.h"
#include "jfs_dmap.h"
#include "jfs_imap.h"
#include "jfs_logmgr.h"
#include "jfs_metapage.h"
#include "jfs_debug.h"
/*
* NAME: jfs_umount(vfsp, flags, crp)
*
* FUNCTION: vfs_umount()
*
* PARAMETERS: vfsp - virtual file system pointer
* flags - unmount for shutdown
* crp - credential
*
* RETURN : EBUSY - device has open files
*/
int jfs_umount(struct super_block *sb)
{
struct jfs_sb_info *sbi = JFS_SBI(sb);
struct inode *ipbmap = sbi->ipbmap;
struct inode *ipimap = sbi->ipimap;
struct inode *ipaimap = sbi->ipaimap;
struct inode *ipaimap2 = sbi->ipaimap2;
struct jfs_log *log;
int rc = 0;
jfs_info("UnMount JFS: sb:0x%p", sb);
/*
* update superblock and close log
*
* if mounted read-write and log based recovery was enabled
*/
if ((log = sbi->log))
/*
* Wait for outstanding transactions to be written to log:
*/
jfs_flush_journal(log, 2);
/*
* Hold log lock so write_special_inodes (lmLogSync) cannot see
* this sbi with a NULL inode pointer while iterating log->sb_list.
*/
if (log)
LOG_LOCK(log);
/*
* close fileset inode allocation map (aka fileset inode)
*/
diUnmount(ipimap, 0);
diFreeSpecial(ipimap);
sbi->ipimap = NULL;
/*
* close secondary aggregate inode allocation map
*/
if (ipaimap2) {
diUnmount(ipaimap2, 0);
diFreeSpecial(ipaimap2);
sbi->ipaimap2 = NULL;
}
/*
* close aggregate inode allocation map
*/
diUnmount(ipaimap, 0);
diFreeSpecial(ipaimap);
sbi->ipaimap = NULL;
/*
* close aggregate block allocation map
*/
dbUnmount(ipbmap, 0);
diFreeSpecial(ipbmap);
sbi->ipbmap = NULL;
/*
* Make sure all metadata makes it to disk before we mark
* the superblock as clean
*/
filemap_write_and_wait(sbi->direct_inode->i_mapping);
if (log)
LOG_UNLOCK(log);
/*
* ensure all file system file pages are propagated to their
* home blocks on disk (and their in-memory buffer pages are
* invalidated) BEFORE updating file system superblock state
* (to signify file system is unmounted cleanly, and thus in
* consistent state) and log superblock active file system
* list (to signify skip logredo()).
*/
if (log) { /* log = NULL if read-only mount */
updateSuper(sb, FM_CLEAN);
/*
* close log:
*
* remove file system from log active file system list.
*/
rc = lmLogClose(sb);
}
jfs_info("UnMount JFS Complete: rc = %d", rc);
return rc;
}
int jfs_umount_rw(struct super_block *sb)
{
struct jfs_sb_info *sbi = JFS_SBI(sb);
struct jfs_log *log = sbi->log;
if (!log)
return 0;
/*
* close log:
*
* remove file system from log active file system list.
*/
jfs_flush_journal(log, 2);
/*
* Make sure all metadata makes it to disk
*/
dbSync(sbi->ipbmap);
diSync(sbi->ipimap);
/*
* Note that we have to do this even if sync_blockdev() will
* do exactly the same a few instructions later: We can't
* mark the superblock clean before everything is flushed to
* disk.
*/
filemap_write_and_wait(sbi->direct_inode->i_mapping);
updateSuper(sb, FM_CLEAN);
return lmLogClose(sb);
}
]
|
| 131/4 |
2026/05/11 23:51 |
llm |
patch-generator |
0m
Model:
Tokens:
input: 63766
output: 246
thoughts: 92
Thoughts: Okay, here's the summary of my thought process, keeping in mind I'm an expert and this is more of a "stream of consciousness" reflection:
**Debugging a Code Editing Discrepancy**
Hmm, hold on a second. It seems like the modifications I made to `fs/jfs/jfs_umount.c` didn't actually stick, or maybe they were wiped out somehow? That's definitely not ideal. Let's start by quickly verifying the output from those last `codeeditor` calls, specifically related to that file.
Right, here's what's going on... the `codeeditor` call for `jfs_umount.c` showed a successful return β meaning no errors were reported. However, a quick check of the file content reveals that my intended changes are conspicuously absent. The code editor reported success but the file didn't actually change as intended, which is very odd.
Okay, no problem. I'll just re-apply those changes. Let's get this sorted.
|
| 132/4 |
2026/05/11 23:52 |
tool |
codeeditor |
0m
Error: CurrentCode snippet does not match anything in the source file, provide more precise CurrentCode snippet
Args: map[CurrentCode: /*
* update superblock and close log
*
* if mounted read-write and log based recovery was enabled
*/
if ((log = sbi->log))
/*
* Wait for outstanding transactions to be written to log:
*/
jfs_flush_journal(log, 2);
/*
* Hold log lock so write_special_inodes (lmLogSync) cannot see NewCode: /*
* update superblock and close log
*
* if mounted read-write and log based recovery was enabled
*/
if ((log = sbi->log)) {
/*
* Wait for outstanding transactions to be written to log:
*/
jfs_flush_journal(log, 2);
txLazyCommitWait(sb);
}
/*
* Hold log lock so write_special_inodes (lmLogSync) cannot see SourceFile:fs/jfs/jfs_umount.c]
Results:
|
| 133/4 |
2026/05/11 23:52 |
llm |
patch-generator |
0m
Model:
Tokens:
input: 64355
output: 246
thoughts: 144
Thoughts: **Analyzing the Code Snippet**
Okay, so the provided `CurrentCode` snippet didn't align with what I expected. Time to dive back into the file content and reassess. The code looks like it's dealing with the finalization of a file system operation, specifically related to updating the superblock and closing a log. I recognize the familiar pattern of handling transaction flushes within a journaled file system β that's standard practice, especially when dealing with the kind of synchronous operations that require journal stability before closing things out. I see a conditional check for an active log (`log = sbi->log`) and, if present, a call to `jfs_flush_journal` with a level of 2, most likely indicating a stronger flush or commit. The comments clearly outline the intent: to wait for outstanding transactions to be written to the log, which is critical for data integrity, particularly during shutdown or recovery scenarios. And I see something important: the code contains tabs, which could explain the mismatch I was seeing. I need to make sure I copy and paste the code with the tabs, so I have an exact copy to work with.
|
| 134/4 |
2026/05/11 23:52 |
tool |
codeeditor |
0m
Error: CurrentCode snippet does not match anything in the source file, provide more precise CurrentCode snippet
Args: map[CurrentCode: /*
* update superblock and close log
*
* if mounted read-write and log based recovery was enabled
*/
if ((log = sbi->log))
/*
* Wait for outstanding transactions to be written to log:
*/
jfs_flush_journal(log, 2);
/*
* Hold log lock so write_special_inodes (lmLogSync) cannot see NewCode: /*
* update superblock and close log
*
* if mounted read-write and log based recovery was enabled
*/
if ((log = sbi->log)) {
/*
* Wait for outstanding transactions to be written to log:
*/
jfs_flush_journal(log, 2);
txLazyCommitWait(sb);
}
/*
* Hold log lock so write_special_inodes (lmLogSync) cannot see SourceFile:fs/jfs/jfs_umount.c]
Results:
|
| 135/4 |
2026/05/11 23:52 |
llm |
patch-generator |
0m
Model:
Tokens:
input: 65012
output: 138
thoughts: 11
Thoughts: Okay, I'm ready. Bring on the text! I'll approach this as if these are my own internal thought processes, tailoring the summary to be something insightful that an expert in the field would appreciate. I'll be sure to use a **bolded header** as requested.
|
| 136/4 |
2026/05/11 23:52 |
tool |
codeeditor |
0m
Error: CurrentCode snippet does not match anything in the source file, provide more precise CurrentCode snippet
Args: map[CurrentCode: if ((log = sbi->log))
/*
* Wait for outstanding transactions to be written to log:
*/
jfs_flush_journal(log, 2); NewCode: if ((log = sbi->log)) {
/*
* Wait for outstanding transactions to be written to log:
*/
jfs_flush_journal(log, 2);
txLazyCommitWait(sb);
} SourceFile:fs/jfs/jfs_umount.c]
Results:
|
| 137/4 |
2026/05/11 23:52 |
llm |
patch-generator |
1m
Model:
Tokens:
input: 65251
output: 138
thoughts: 85
Thoughts: Here's my analysis of that code snippet:
**Code Inspection: JFS Journal Flushing**
Okay, let's zero in on this section from `codesearch-definition-source`. I'm seeing a crucial piece of JFS journal management here, specifically lines 55-59. The code's immediately checking if a journal log (`log`) is associated with the `sbi` (presumably a superblock information structure). If it exists, the code proceeds with the core operation: flushing the journal. The comment is crucial; it explicitly states the intent: waiting for outstanding transactions to be written. The function `jfs_flush_journal(log, 2)` does the heavy lifting, and the "2" likely represents a flushing level or mode within the JFS context. This suggests a more aggressive or complete flush is being requested. Given the nature of a journal, this step is vital to ensure data consistency, particularly before critical operations that could impact the integrity of the filesystem. I need to dig deeper into the `jfs_flush_journal` function itself, along with the specifics of what "2" signifies in this call. I'll need to understand how it impacts different journal modes and how this flushing interacts with other related operations.
|
| 138/4 |
2026/05/11 23:53 |
tool |
codeeditor |
0m
Error: CurrentCode snippet does not match anything in the source file, provide more precise CurrentCode snippet
Args: map[CurrentCode: if ((log = sbi->log))
/*
* Wait for outstanding transactions to be written to log:
*/
jfs_flush_journal(log, 2); NewCode: if ((log = sbi->log)) {
/*
* Wait for outstanding transactions to be written to log:
*/
jfs_flush_journal(log, 2);
txLazyCommitWait(sb);
} SourceFile:fs/jfs/jfs_umount.c]
Results:
|
| 139/4 |
2026/05/11 23:53 |
llm |
patch-generator |
0m
Model:
Tokens:
input: 65764
output: 144
thoughts: 175
Thoughts: **Debugging a Persistent Code Edit**
Okay, hold on a second. Didn't I *already* make that edit to `fs/jfs/jfs_umount.c` in my initial `codeeditor` call? Let me double-check the file's content again.
Hmm, this is strange. The file content I just pulled *doesn't* reflect my changes. Why not? Wait, did the `read-file` tool return the unmodified version? This is problematic. I'm sure I applied the fix.
Let me verify the output of `read-file` one more time:
```c
if ((log = sbi->log))
/*
* Wait for outstanding transactions to be written to log:
*/
jfs_flush_journal(log, 2);
```
Yep, it's definitely the original. My edit isn't present.
Alright, maybe there was a subtle typo or error in the previous `codeeditor` call, even though I don't see one. Let's try applying the edit again, just to be absolutely certain. Something is not behaving as expected, and I need to resolve this as quickly as possible.
|
| 140/4 |
2026/05/11 23:53 |
tool |
codeeditor |
0m
Error: CurrentCode snippet does not match anything in the source file, provide more precise CurrentCode snippet
Args: map[CurrentCode: if ((log = sbi->log))
/*
* Wait for outstanding transactions to be written to log:
*/
jfs_flush_journal(log, 2);
/* NewCode: if ((log = sbi->log)) {
/*
* Wait for outstanding transactions to be written to log:
*/
jfs_flush_journal(log, 2);
txLazyCommitWait(sb);
}
/* SourceFile:fs/jfs/jfs_umount.c]
Results:
|
| 141/4 |
2026/05/11 23:53 |
llm |
patch-generator |
0m
Model:
Tokens:
input: 66372
output: 26
thoughts: 13
Thoughts: Okay, I'm ready. Here's my summary, presented as my internal thought process, assuming I'm an expert in my field:
**Utilizing Grepper for Precise Code Retrieval**
Alright, I need to get straight to the code. No time for fluff. I know the general area I need, but I can't waste time sifting through irrelevant results. My immediate thought is, "How can I pinpoint that exact snippet?" Given the context and my existing knowledge, `grepper` is the obvious tool. It's built for this. I'll leverage its search capabilities to quickly and efficiently locate the specific lines of code I require. This approach prioritizes speed and accuracy, essential for my workflow. I'll get the precise lines I need and move on, without any unnecessary delay.
|
| 142/4 |
2026/05/11 23:53 |
tool |
grepper |
0m
Args: map[Expression:jfs_flush_journal\(log, 2\)]
Results: map[Output:fs/jfs/jfs_logmgr.c=1628=int lmLogShutdown(struct jfs_log * log)
--
fs/jfs/jfs_logmgr.c-1639-
fs/jfs/jfs_logmgr.c:1640: jfs_flush_journal(log, 2);
fs/jfs/jfs_logmgr.c-1641-
--
fs/jfs/jfs_umount.c=38=int jfs_umount(struct super_block *sb)
--
fs/jfs/jfs_umount.c-58- */
fs/jfs/jfs_umount.c:59: jfs_flush_journal(log, 2);
fs/jfs/jfs_umount.c-60-
--
fs/jfs/jfs_umount.c=131=int jfs_umount_rw(struct super_block *sb)
--
fs/jfs/jfs_umount.c-143- */
fs/jfs/jfs_umount.c:144: jfs_flush_journal(log, 2);
fs/jfs/jfs_umount.c-145-
]
|
| 143/4 |
2026/05/11 23:53 |
llm |
patch-generator |
0m
Model:
Tokens:
input: 66904
output: 18
thoughts: 43
Thoughts: Okay, here's my summary, presented as a direct reflection of my thought process:
**Verification Checkpoint**
Hold on a second, did that last change *actually* take effect? I need to confirm that my prior edit was properly implemented. I'm going to quickly verify the change wasn't reverted or missed during the merge. To do that I'm going to go straight to the source. Let's see...I need to check the `fs/jfs/jfs_umount.c` file. I'll use `grepper` to search within that specific file to confirm that the `txLazyCommitWait` variable is present, or not. That should quickly clear up any confusion and confirm whether or not my change was implemented, or if I need to re-apply it.
|
| 144/4 |
2026/05/11 23:53 |
tool |
grepper |
0m
Error:
Args: map[Expression:txLazyCommitWait]
Results:
|
| 145/4 |
2026/05/11 23:53 |
llm |
patch-generator |
0m
Model:
Tokens:
input: 67149
output: 18
thoughts: 41
Thoughts: Okay, here's my interpretation of those thoughts, presented as a first-person expert summary:
**The Unexpected "No Matches" - A Quick Diagnostic**
Hold on a second... "no matches"? That's not what I was expecting. My changes to the code, they didn't even register? That's definitely concerning. I need to figure out what went wrong, and fast. The first logical step is to verify the application of my modifications. Right, let's fire up `grepper` and double-check my work within `fs/jfs/jfs_txnmgr.c`. I need to ensure the changes are present where they should be, or alternatively, to identify where my assumptions were incorrect or the modifications went awry. A simple 'no matches' isn't acceptable at this stage. I'll get to the bottom of this.
|
| 146/4 |
2026/05/11 23:53 |
tool |
grepper |
0m
Error:
Args: map[Expression:txLazyCommitWait]
Results:
|
| 147/4 |
2026/05/11 23:53 |
llm |
patch-generator |
0m
Model:
Tokens:
input: 67406
output: 41
thoughts: 1211
Thoughts: **Analyzing and Confirming the JFS Changes**
Okay, so the `codeeditor` tool is giving me empty responses, which typically means success. I was initially thrown off because I couldn't see the changes with `grepper`, but then I remembered that `grepper` uses `git grep`, which looks at the *git tree* or the *working tree*. The prompt explicitly warned me that I wouldn't see edits reflected in the codesearch tools, so I have to assume the modifications *did* apply.
The clue was when I tried to re-apply the edit to `fs/jfs/jfs_umount.c`, and it failed, saying the `CurrentCode` snippet didn't match. This means the file *was* modified, and the original `CurrentCode` is now outdated. That's good, confirming my edits were applied!
Now, let's review what I've done:
1. I added `txLazyCommitWait` to `fs/jfs/jfs_txnmgr.c`.
2. I added `extern void txLazyCommitWait(struct super_block *sb);` to `fs/jfs/jfs_txnmgr.h`.
3. I added calls to `txLazyCommitWait(sb)` in `jfs_umount` and `jfs_umount_rw` in `fs/jfs/jfs_umount.c`.
4. I added `#include <linux/delay.h>` to `fs/jfs/jfs_txnmgr.c`.
5. I added `#include "jfs_txnmgr.h"` to `fs/jfs/jfs_umount.c`.
I was a bit worried I might have missed including `jfs_txnmgr.h` in `fs/jfs/jfs_umount.c`, but I checked the `codeeditor` call, and the `NewCode` confirms I made the include. So, it seems I've completed all necessary edits.
Let's double-check the `txLazyCommitWait` implementation itself. After reviewing the code, it looks correct. The `txLazyCommitWait` function waits for the lazy commit thread to finish processing transactions for a given superblock. This function is appropriate to avoid a race condition as described in the explanation.
Finally, to be thorough, I should look at other places where `jfs_flush_journal` is called to see if similar waits are needed. I see that `jfs_flush_journal` is called in `jfs_umount`, `jfs_umount_rw`, `jfs_freeze`, `jfs_sync_fs`, `txQuiesce`, and `lmLogShutdown`. I will check the `jfs_freeze` function in `fs/jfs/super.c`.
|
| 148/4 |
2026/05/11 23:54 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:fs/jfs/super.c IncludeLines:true Name:jfs_freeze]
Results: map[SourceCode: 582: static int jfs_freeze(struct super_block *sb)
583: {
584: struct jfs_sb_info *sbi = JFS_SBI(sb);
585: struct jfs_log *log = sbi->log;
586: int rc = 0;
587:
588: if (!sb_rdonly(sb)) {
589: txQuiesce(sb);
590: rc = lmLogShutdown(log);
591: if (rc) {
592: jfs_error(sb, "lmLogShutdown failed\n");
593:
594: /* let operations fail rather than hang */
595: txResume(sb);
596:
597: return rc;
598: }
599: rc = updateSuper(sb, FM_CLEAN);
600: if (rc) {
601: jfs_err("jfs_freeze: updateSuper failed");
602: /*
603: * Don't fail here. Everything succeeded except
604: * marking the superblock clean, so there's really
605: * no harm in leaving it frozen for now.
606: */
607: }
608: }
609: return 0;
610: }
SourceFile:fs/jfs/super.c]
|
| 149/4 |
2026/05/11 23:54 |
llm |
patch-generator |
0m
Model:
Tokens:
input: 69697
output: 46
thoughts: 46
Thoughts: Here's my summary, as though I'm thinking through this process:
**Diving into the JFS Filesystem Freeze**
Okay, so `jfs_freeze` is our entry point here. My initial thought is to trace its core function calls. It looks like it calls `txQuiesce` and `lmLogShutdown`. That's the key. That tells me a lot right away β it's likely involved in transaction management and potentially log handling during the freeze operation.
Now, I need to understand what's *really* happening. So, I need to check out `txQuiesce` because that's the more critical of the two functions and is likely where the heavy lifting regarding the transactions takes place. Time to dive into the JFS source code... specifically, I need to look at `fs/jfs/jfs_txnmgr.c`. That's where I expect to find the implementation of `txQuiesce`. Understanding this function will give me a better grasp of how JFS achieves its consistent filesystem state during a freeze.
|
| 150/4 |
2026/05/11 23:54 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:fs/jfs/jfs_txnmgr.c IncludeLines:true Name:txQuiesce]
Results: map[SourceCode:2803: /*
2804: * txQuiesce
2805: *
2806: * Block all new transactions and push anonymous transactions to
2807: * completion
2808: *
2809: * This does almost the same thing as jfs_sync below. We don't
2810: * worry about deadlocking when jfs_tlocks_low is set, since we would
2811: * expect jfs_sync to get us out of that jam.
2812: */
2813: void txQuiesce(struct super_block *sb)
2814: {
2815: struct inode *ip;
2816: struct jfs_inode_info *jfs_ip;
2817: struct jfs_log *log = JFS_SBI(sb)->log;
2818: tid_t tid;
2819:
2820: set_bit(log_QUIESCE, &log->flag);
2821:
2822: TXN_LOCK();
2823: restart:
2824: while (!list_empty(&TxAnchor.anon_list)) {
2825: jfs_ip = list_entry(TxAnchor.anon_list.next,
2826: struct jfs_inode_info,
2827: anon_inode_list);
2828: ip = &jfs_ip->vfs_inode;
2829:
2830: /*
2831: * inode will be removed from anonymous list
2832: * when it is committed
2833: */
2834: TXN_UNLOCK();
2835: tid = txBegin(ip->i_sb, COMMIT_INODE | COMMIT_FORCE);
2836: mutex_lock(&jfs_ip->commit_mutex);
2837: txCommit(tid, 1, &ip, 0);
2838: txEnd(tid);
2839: mutex_unlock(&jfs_ip->commit_mutex);
2840: /*
2841: * Just to be safe. I don't know how
2842: * long we can run without blocking
2843: */
2844: cond_resched();
2845: TXN_LOCK();
2846: }
2847:
2848: /*
2849: * If jfs_sync is running in parallel, there could be some inodes
2850: * on anon_list2. Let's check.
2851: */
2852: if (!list_empty(&TxAnchor.anon_list2)) {
2853: list_splice_init(&TxAnchor.anon_list2, &TxAnchor.anon_list);
2854: goto restart;
2855: }
2856: TXN_UNLOCK();
2857:
2858: /*
2859: * We may need to kick off the group commit
2860: */
2861: jfs_flush_journal(log, 0);
2862: }
SourceFile:fs/jfs/jfs_txnmgr.c]
|
| 151/4 |
2026/05/11 23:54 |
llm |
patch-generator |
0m
Model:
Tokens:
input: 70909
output: 44
thoughts: 68
Thoughts: **Analyzing the JFS Transaction Quiescence Process**
Okay, so `txQuiesce` is triggering a journal flush, specifically calling `jfs_flush_journal` with a zero wait. Interesting. That suggests it's an asynchronous operation, which is good for avoiding stalls. Immediately after, `jfs_freeze` is being invoked, and within that, there's a call to `lmLogShutdown(log)`. The timing here is key. I need to understand what state the log is in when `lmLogShutdown` gets called. My instinct is that this is the critical point where the journal gets closed down for the quiesce. I should now focus my attention on `lmLogShutdown`, specifically the implementation within `fs/jfs/jfs_logmgr.c`. I need to ensure there are no subtle race conditions or un-flushed data. Let's dig in.
|
| 152/4 |
2026/05/11 23:54 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:fs/jfs/jfs_logmgr.c IncludeLines:true Name:lmLogShutdown]
Results: map[SourceCode:1614: /*
1615: * NAME: lmLogShutdown()
1616: *
1617: * FUNCTION: log shutdown at last LogClose().
1618: *
1619: * write log syncpt record.
1620: * update super block to set redone flag to 0.
1621: *
1622: * PARAMETER: log - log inode
1623: *
1624: * RETURN: 0 - success
1625: *
1626: * serialization: single last close thread
1627: */
1628: int lmLogShutdown(struct jfs_log * log)
1629: {
1630: int rc;
1631: struct lrd lrd;
1632: int lsn;
1633: struct logsuper *logsuper;
1634: struct lbuf *bpsuper;
1635: struct lbuf *bp;
1636: struct logpage *lp;
1637:
1638: jfs_info("lmLogShutdown: log:0x%p", log);
1639:
1640: jfs_flush_journal(log, 2);
1641:
1642: /*
1643: * write the last SYNCPT record with syncpoint = 0
1644: * (i.e., log redo up to HERE !)
1645: */
1646: lrd.logtid = 0;
1647: lrd.backchain = 0;
1648: lrd.type = cpu_to_le16(LOG_SYNCPT);
1649: lrd.length = 0;
1650: lrd.log.syncpt.sync = 0;
1651:
1652: lsn = lmWriteRecord(log, NULL, &lrd, NULL);
1653: bp = log->bp;
1654: lp = (struct logpage *) bp->l_ldata;
1655: lp->h.eor = lp->t.eor = cpu_to_le16(bp->l_eor);
1656: lbmWrite(log, log->bp, lbmWRITE | lbmRELEASE | lbmSYNC, 0);
1657: lbmIOWait(log->bp, lbmFREE);
1658: log->bp = NULL;
1659:
1660: /*
1661: * synchronous update log superblock
1662: * mark log state as shutdown cleanly
1663: * (i.e., Log does not need to be replayed).
1664: */
1665: if ((rc = lbmRead(log, 1, &bpsuper)))
1666: goto out;
1667:
1668: logsuper = (struct logsuper *) bpsuper->l_ldata;
1669: logsuper->state = cpu_to_le32(LOGREDONE);
1670: logsuper->end = cpu_to_le32(lsn);
1671: lbmDirectWrite(log, bpsuper, lbmWRITE | lbmRELEASE | lbmSYNC);
1672: rc = lbmIOWait(bpsuper, lbmFREE);
1673:
1674: jfs_info("lmLogShutdown: lsn:0x%x page:%d eor:%d",
1675: lsn, log->page, log->eor);
1676:
1677: out:
1678: /*
1679: * shutdown per log i/o
1680: */
1681: lbmLogShutdown(log);
1682:
1683: if (rc) {
1684: jfs_warn("lmLogShutdown: exit(%d)", rc);
1685: }
1686: return rc;
1687: }
SourceFile:fs/jfs/jfs_logmgr.c]
|
| 153/4 |
2026/05/11 23:54 |
llm |
patch-generator |
0m
Model:
Tokens:
input: 72330
output: 44
thoughts: 142
Thoughts: Here's my thought process, distilled:
**Analyzing `lmLogShutdown` and its Implications**
Okay, so I see that `lmLogShutdown` is calling `jfs_flush_journal(log, 2)`. That's an important detail. Hold on, `lmLogShutdown` is invoked from two critical points: `jfs_freeze` and `lmLogClose`. Now, if `lmLogShutdown` flushes the journal like that, it's possible it could return *before* `jfs_lazycommit` has finished processing transactions.
My concern is: the `lmLogShutdown` function then proceeds to write the final SYNCPT record and ultimately shuts down the log. That's a potential race condition or data integrity issue if `jfs_lazycommit` is still actively modifying the journal at that precise moment. This is a bit unsettling...
A key observation here is that `lmLogShutdown` *doesn't* free the `jfs_log` structure. That is the responsibility of `lmLogClose`, which is called after `lmLogShutdown`. I need to revisit `lmLogClose` and check how it handles the log structure, as that is the next logical step to understand the overall shutdown sequence.
|
| 154/4 |
2026/05/11 23:54 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:fs/jfs/jfs_logmgr.c IncludeLines:true Name:lmLogClose]
Results: map[SourceCode:1420: /*
1421: * NAME: lmLogClose()
1422: *
1423: * FUNCTION: remove file system <ipmnt> from active list of log <iplog>
1424: * and close it on last close.
1425: *
1426: * PARAMETER: sb - superblock
1427: *
1428: * RETURN: errors from subroutines
1429: *
1430: * serialization:
1431: */
1432: int lmLogClose(struct super_block *sb)
1433: {
1434: struct jfs_sb_info *sbi = JFS_SBI(sb);
1435: struct jfs_log *log = sbi->log;
1436: struct file *bdev_file;
1437: int rc = 0;
1438:
1439: jfs_info("lmLogClose: log:0x%p", log);
1440:
1441: mutex_lock(&jfs_log_mutex);
1442: LOG_LOCK(log);
1443: list_del(&sbi->log_list);
1444: LOG_UNLOCK(log);
1445: sbi->log = NULL;
1446:
1447: /*
1448: * We need to make sure all of the "written" metapages
1449: * actually make it to disk
1450: */
1451: sync_blockdev(sb->s_bdev);
1452:
1453: if (test_bit(log_INLINELOG, &log->flag)) {
1454: /*
1455: * in-line log in host file system
1456: */
1457: rc = lmLogShutdown(log);
1458: kfree(log);
1459: goto out;
1460: }
1461:
1462: if (!log->no_integrity)
1463: lmLogFileSystem(log, sbi, 0);
1464:
1465: if (!list_empty(&log->sb_list))
1466: goto out;
1467:
1468: /*
1469: * TODO: ensure that the dummy_log is in a state to allow
1470: * lbmLogShutdown to deallocate all the buffers and call
1471: * kfree against dummy_log. For now, leave dummy_log & its
1472: * buffers in memory, and resuse if another no-integrity mount
1473: * is requested.
1474: */
1475: if (log->no_integrity)
1476: goto out;
1477:
1478: /*
1479: * external log as separate logical volume
1480: */
1481: list_del(&log->journal_list);
1482: bdev_file = log->bdev_file;
1483: rc = lmLogShutdown(log);
1484:
1485: bdev_fput(bdev_file);
1486:
1487: kfree(log);
1488:
1489: out:
1490: mutex_unlock(&jfs_log_mutex);
1491: jfs_info("lmLogClose: exit(%d)", rc);
1492: return rc;
1493: }
SourceFile:fs/jfs/jfs_logmgr.c]
|
| 155/4 |
2026/05/11 23:54 |
llm |
patch-generator |
0m
Model:
Tokens:
input: 73797
output: 21
thoughts: 353
Thoughts: **Analyzing Potential Race Conditions in JFS Log Closure**
Okay, so I'm digging into this JFS file system code, specifically around the log closure process during unmount. It looks like `lmLogClose` is the key function here, and it's calling `lmLogShutdown`, which then kicks off `jfs_flush_journal(log, 2)`. Afterwards, `lmLogClose` calls `kfree(log)`, freeing the log data structure. Hmm, that's where my concern lies: if `jfs_lazycommit` is still running asynchronously, and it tries to access the `log` *after* `kfree` is called, we're going to have a classic use-after-free crash, and those are always nasty.
But wait, I seem to remember addressing this! I added a call to `txLazyCommitWait(sb)` in both `jfs_umount` and `jfs_umount_rw`. The intent was to ensure that any pending lazy commit transactions on the superblock `sb` were completed *before* the log is closed. Let me double-check `jfs_umount`... Yes, here it is:
```c
if ((log = sbi->log)) {
/*
* Wait for outstanding transactions to be written to log:
*/
jfs_flush_journal(log, 2);
txLazyCommitWait(sb);
}
/* ... */
if (log) { /* log = NULL if read-only mount */
updateSuper(sb, FM_CLEAN);
/*
* close log:
*
* remove file system from log active file system list.
*/
rc = lmLogClose(sb);
}
```
Okay, the code confirms that `txLazyCommitWait(sb)` *is* called *before* `lmLogClose(sb)`. This should mean that `jfs_lazycommit` will finish processing all transactions associated with the superblock (`sb`) before the log is released. That's good; it confirms my original thinking. But I should not rest here: is `lmLogClose` called from elsewhere? Perhaps the problem isn't in this specific unmount path. It's time to check *all* the call sites of `lmLogClose` to be absolutely certain there are no other potential race conditions.
|
| 156/4 |
2026/05/11 23:54 |
tool |
codesearch-find-references |
0m
Args:
Results: map[References:[map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:jfs_mount_rw SourceFile:fs/jfs/jfs_mount.c SourceLine:265] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:jfs_umount SourceFile:fs/jfs/jfs_umount.c SourceLine:124] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:jfs_umount_rw SourceFile:fs/jfs/jfs_umount.c SourceLine:162]] TruncatedOutput:false]
|
| 157/4 |
2026/05/11 23:54 |
llm |
patch-generator |
0m
Model:
Tokens:
input: 74875
output: 46
thoughts: 60
Thoughts: Here's my summary, as the expert:
**Investigating `lmLogClose` Calls**
Okay, so `lmLogClose` seems to be a critical function, and I need to understand its context. My first thought is to trace where it's called. The code states it's called from `jfs_mount_rw`, `jfs_umount`, and `jfs_umount_rw`. That gives me a few key entry points to examine. Given the function names, I'm guessing these are related to mount and unmount operations, which makes perfect sense.
My priority is `jfs_mount_rw`, especially when considering the relationship between mount, and logging. I'll take a look at `fs/jfs/jfs_mount.c` now to understand the interaction between `jfs_mount_rw` and `lmLogClose`, and what's going on during the mount process. I need to figure out what log is closed, and why, and what implications that has for the filesystem's lifecycle.
|
| 158/4 |
2026/05/11 23:54 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:fs/jfs/jfs_mount.c IncludeLines:true Name:jfs_mount_rw]
Results: map[SourceCode: 215: /*
216: * NAME: jfs_mount_rw(sb, remount)
217: *
218: * FUNCTION: Completes read-write mount, or remounts read-only volume
219: * as read-write
220: */
221: int jfs_mount_rw(struct super_block *sb, int remount)
222: {
223: struct jfs_sb_info *sbi = JFS_SBI(sb);
224: int rc;
225:
226: /*
227: * If we are re-mounting a previously read-only volume, we want to
228: * re-read the inode and block maps, since fsck.jfs may have updated
229: * them.
230: */
231: if (remount) {
232: if (chkSuper(sb) || (sbi->state != FM_CLEAN))
233: return -EINVAL;
234:
235: truncate_inode_pages(sbi->ipimap->i_mapping, 0);
236: truncate_inode_pages(sbi->ipbmap->i_mapping, 0);
237:
238: IWRITE_LOCK(sbi->ipimap, RDWRLOCK_IMAP);
239: diUnmount(sbi->ipimap, 1);
240: if ((rc = diMount(sbi->ipimap))) {
241: IWRITE_UNLOCK(sbi->ipimap);
242: jfs_err("jfs_mount_rw: diMount failed!");
243: return rc;
244: }
245: IWRITE_UNLOCK(sbi->ipimap);
246:
247: dbUnmount(sbi->ipbmap, 1);
248: if ((rc = dbMount(sbi->ipbmap))) {
249: jfs_err("jfs_mount_rw: dbMount failed!");
250: return rc;
251: }
252: }
253:
254: /*
255: * open/initialize log
256: */
257: if ((rc = lmLogOpen(sb)))
258: return rc;
259:
260: /*
261: * update file system superblock;
262: */
263: if ((rc = updateSuper(sb, FM_MOUNT))) {
264: jfs_err("jfs_mount: updateSuper failed w/rc = %d", rc);
265: lmLogClose(sb);
266: return rc;
267: }
268:
269: /*
270: * write MOUNT log record of the file system
271: */
272: logMOUNT(sb);
273:
274: return rc;
275: }
SourceFile:fs/jfs/jfs_mount.c]
|
| 159/4 |
2026/05/11 23:54 |
llm |
patch-generator |
0m
Model:
Tokens:
input: 76097
output: 44
thoughts: 451
Thoughts: **Analyzing JFS Log Closure and Freeze Operations**
Okay, so I'm looking at how JFS handles log closure and freezing, and I've spotted a potential issue. Initially, I was thinking about `jfs_mount_rw`. I see that `lmLogClose` is called if `updateSuper` fails. That seems safe since `logMOUNT` hasn't happened yet, so no transactions are active, and `TxAnchor.unlock_queue` will be empty. No problem there.
But then my attention turned to `jfs_freeze`. It calls `lmLogShutdown` but not `lmLogClose`. `lmLogShutdown` handles writing the final SYNCPT record and shutting down the log. Now, here's where it gets interesting. `jfs_freeze` then calls `jfs_flush_journal(log, 2)`. I got concerned for a moment, thinking that if `jfs_lazycommit` was still chugging along processing transactions, it might write to the log *after* that final SYNCPT record was written!
Wait, I think I see the sequence now. `jfs_freeze` calls `txQuiesce(sb)` *before* `lmLogShutdown(log)`. `txQuiesce` blocks any new transactions and pushes anonymous ones to completion. Then it calls `jfs_flush_journal(log, 0)`. Then `jfs_freeze` calls `lmLogShutdown(log)` which calls `jfs_flush_journal(log, 2)`. Okay, that's better.
So, if `jfs_lazycommit` is still processing, it will eventually call `txLazyCommit`. Which, in turn, calls `txUpdateMap` then `txUnlock`. `txLazyCommit` doesn't write to the log itself, it only updates allocation maps and unlocks the transactions. I thought about the maps for a moment, but `txUpdateMap` just updates the allocation maps.
Hold on, I see a complication. `txLazyCommit` calls `txEnd`. And `txEnd` calls `jfs_syncpt` if `log->active == 0` *and* `log_SYNCBARRIER` is set. Now `jfs_syncpt` is the one that *does* write a SYNCPT record. I need to dig into the `txEnd` function now to confirm that flow.
|
| 160/4 |
2026/05/11 23:54 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:fs/jfs/jfs_txnmgr.c IncludeLines:true Name:txEnd]
Results: map[SourceCode: 485: /*
486: * txEnd()
487: *
488: * function: free specified transaction block.
489: *
490: * logsync barrier processing:
491: *
492: * serialization:
493: */
494: void txEnd(tid_t tid)
495: {
496: struct tblock *tblk = tid_to_tblock(tid);
497: struct jfs_log *log;
498:
499: jfs_info("txEnd: tid = %d", tid);
500: TXN_LOCK();
501:
502: /*
503: * wakeup transactions waiting on the page locked
504: * by the current transaction
505: */
506: TXN_WAKEUP(&tblk->waitor);
507:
508: log = JFS_SBI(tblk->sb)->log;
509:
510: /*
511: * Lazy commit thread can't free this guy until we mark it UNLOCKED,
512: * otherwise, we would be left with a transaction that may have been
513: * reused.
514: *
515: * Lazy commit thread will turn off tblkGC_LAZY before calling this
516: * routine.
517: */
518: if (tblk->flag & tblkGC_LAZY) {
519: jfs_info("txEnd called w/lazy tid: %d, tblk = 0x%p", tid, tblk);
520: TXN_UNLOCK();
521:
522: spin_lock_irq(&log->gclock); // LOGGC_LOCK
523: tblk->flag |= tblkGC_UNLOCKED;
524: spin_unlock_irq(&log->gclock); // LOGGC_UNLOCK
525: return;
526: }
527:
528: jfs_info("txEnd: tid: %d, tblk = 0x%p", tid, tblk);
529:
530: assert(tblk->next == 0);
531:
532: /*
533: * insert tblock back on freelist
534: */
535: tblk->next = TxAnchor.freetid;
536: TxAnchor.freetid = tid;
537:
538: /*
539: * mark the tblock not active
540: */
541: if (--log->active == 0) {
542: clear_bit(log_FLUSH, &log->flag);
543:
544: /*
545: * synchronize with logsync barrier
546: */
547: if (test_bit(log_SYNCBARRIER, &log->flag)) {
548: TXN_UNLOCK();
549:
550: /* write dirty metadata & forward log syncpt */
551: jfs_syncpt(log, 1);
552:
553: jfs_info("log barrier off: 0x%x", log->lsn);
554:
555: /* enable new transactions start */
556: clear_bit(log_SYNCBARRIER, &log->flag);
557:
558: /* wakeup all waitors for logsync barrier */
559: TXN_WAKEUP(&log->syncwait);
560:
561: goto wakeup;
562: }
563: }
564:
565: TXN_UNLOCK();
566: wakeup:
567: /*
568: * wakeup all waitors for a free tblock
569: */
570: TXN_WAKEUP(&TxAnchor.freewait);
571: }
SourceFile:fs/jfs/jfs_txnmgr.c]
|
| 161/4 |
2026/05/11 23:54 |
llm |
patch-generator |
0m
Model:
Tokens:
input: 78290
output: 552
thoughts: 2266
Thoughts: **Analysis and Proposed Fix for Potential Log Shutdown Race Condition**
Okay, so the issue here seems to stem from how `txEnd` calls `jfs_syncpt`, which writes to the log. And if `jfs_freeze` calls `lmLogShutdown`, shutting down the log *before* `jfs_lazycommit` calls `txEnd`, then we have a problem. The log could be written to after it's been shut down, which is bad news.
My initial thought was to add `txLazyCommitWait(sb)` to `jfs_freeze`. Let's check the code:
```c
if (!sb_rdonly(sb)) {
txQuiesce(sb);
rc = lmLogShutdown(log);
```
Adding `txLazyCommitWait(sb)` before `lmLogShutdown(log)` looks like it would solve the problem by ensuring all transactions are processed before the log is closed for that `sb`. But wait, `txQuiesce` calls `jfs_flush_journal(log, 0)`. Then `jfs_freeze` calls `lmLogShutdown(log)` which calls `jfs_flush_journal(log, 2)`. So where's the right place?
I considered moving the wait *after* `txQuiesce` but *before* `lmLogShutdown`, or even *inside* `lmLogShutdown` itself. But the latter is tricky because `lmLogShutdown` takes `struct jfs_log *log`, and a `jfs_log` can be shared. And Linux JFS has a 1:1 relationship between log and superblock (except for `dummy_log`). The code mentions `jfs_umount_rw` and the need to flush the journal even if using `dummy_log`.
Crucially, the provided explanation states: "Invoke `txLazyCommitWait(sb)` immediately after `jfs_flush_journal(log, 2)` in both `jfs_umount()` and `jfs_umount_rw()`." And it *doesn't* mention `jfs_freeze`.
Given that, I'll stick to the suggested fix. The explanation is usually solid.
Let's double-check `txLazyCommitWait` though:
```c
/*
* Wait for lazycommit thread to finish processing all transactions
* for the given superblock.
*/
void txLazyCommitWait(struct super_block *sb)
{
struct jfs_sb_info *sbi = JFS_SBI(sb);
struct jfs_log *log = sbi->log;
unsigned long flags;
struct tblock *tblk;
int found;
if (!log)
return;
/*
* Synchronize with lmPostGC to ensure that all transactions
* removed from cqueue have been added to unlock_queue.
*/
spin_lock_irqsave(&log->gclock, flags);
spin_unlock_irqrestore(&log->gclock, flags);
do {
found = 0;
LAZY_LOCK(flags);
if (sbi->commit_state & IN_LAZYCOMMIT)
found = 1;
else {
list_for_each_entry(tblk, &TxAnchor.unlock_queue, cqueue) {
if (tblk->sb == sb) {
found = 1;
break;
}
}
}
LAZY_UNLOCK(flags);
if (found)
msleep(10);
} while (found);
}
```
Okay, the code locks `log->gclock` to synchronize with `lmPostGC`, which is important to ensure all transactions in the `cqueue` have been added to the `unlock_queue`. It then loops:
- Checks `sbi->commit_state & IN_LAZYCOMMIT`
- Checks if any transactions for the specific `sb` are in `TxAnchor.unlock_queue`.
If either is true, it sleeps for 10ms and checks again.
Is the locking correct? Yes, it accesses `sbi->commit_state` safely, and `TxAnchor.unlock_queue` is protected by `LAZY_LOCK`. The `msleep(10)` looks reasonable. The usage of `spin_lock_irqsave` on `log->gclock` is also correct.
The crash report confirms that the problem is a use-after-free in `lmLogSync`, called from `jfs_syncpt` and ultimately from `txEnd`. This all fits the explanation
|
| 162/3 |
2026/05/11 23:54 |
action |
test-patch |
26m
Results: map[PatchDiff:diff --git a/fs/jfs/jfs_txnmgr.c b/fs/jfs/jfs_txnmgr.c
index 083dbbb0c..823250c3c 100644
--- a/fs/jfs/jfs_txnmgr.c
+++ b/fs/jfs/jfs_txnmgr.c
@@ -37,6 +37,7 @@
#include <linux/moduleparam.h>
#include <linux/kthread.h>
#include <linux/seq_file.h>
+#include <linux/delay.h>
#include "jfs_incore.h"
#include "jfs_inode.h"
#include "jfs_filsys.h"
@@ -2772,6 +2773,49 @@ int jfs_lazycommit(void *arg)
return 0;
}
+/*
+ * Wait for lazycommit thread to finish processing all transactions
+ * for the given superblock.
+ */
+void txLazyCommitWait(struct super_block *sb)
+{
+ struct jfs_sb_info *sbi = JFS_SBI(sb);
+ struct jfs_log *log = sbi->log;
+ unsigned long flags;
+ struct tblock *tblk;
+ int found;
+
+ if (!log)
+ return;
+
+ /*
+ * Synchronize with lmPostGC to ensure that all transactions
+ * removed from cqueue have been added to unlock_queue.
+ */
+ spin_lock_irqsave(&log->gclock, flags);
+ spin_unlock_irqrestore(&log->gclock, flags);
+
+ do {
+ found = 0;
+ LAZY_LOCK(flags);
+ if (sbi->commit_state & IN_LAZYCOMMIT)
+ found = 1;
+ else {
+ list_for_each_entry(tblk, &TxAnchor.unlock_queue,
+ cqueue) {
+ if (tblk->sb == sb) {
+ found = 1;
+ break;
+ }
+ }
+ }
+ LAZY_UNLOCK(flags);
+
+ if (found)
+ msleep(10);
+ } while (found);
+}
+
void txLazyUnlock(struct tblock * tblk)
{
unsigned long flags;
diff --git a/fs/jfs/jfs_txnmgr.h b/fs/jfs/jfs_txnmgr.h
index ba71eb5ce..3b3272ded 100644
--- a/fs/jfs/jfs_txnmgr.h
+++ b/fs/jfs/jfs_txnmgr.h
@@ -295,4 +295,5 @@ extern void txResume(struct super_block *);
extern void txLazyUnlock(struct tblock *);
extern int jfs_lazycommit(void *);
extern int jfs_sync(void *);
+extern void txLazyCommitWait(struct super_block *sb);
#endif /* _H_JFS_TXNMGR */
diff --git a/fs/jfs/jfs_umount.c b/fs/jfs/jfs_umount.c
index 18569f1ea..1aca20b1d 100644
--- a/fs/jfs/jfs_umount.c
+++ b/fs/jfs/jfs_umount.c
@@ -21,6 +21,7 @@
#include "jfs_dmap.h"
#include "jfs_imap.h"
#include "jfs_logmgr.h"
+#include "jfs_txnmgr.h"
#include "jfs_metapage.h"
#include "jfs_debug.h"
@@ -52,11 +53,13 @@ int jfs_umount(struct super_block *sb)
*
* if mounted read-write and log based recovery was enabled
*/
- if ((log = sbi->log))
+ if ((log = sbi->log)) {
/*
* Wait for outstanding transactions to be written to log:
*/
jfs_flush_journal(log, 2);
+ txLazyCommitWait(sb);
+ }
/*
* Hold log lock so write_special_inodes (lmLogSync) cannot see
@@ -142,6 +145,7 @@ int jfs_umount_rw(struct super_block *sb)
* remove file system from log active file system list.
*/
jfs_flush_journal(log, 2);
+ txLazyCommitWait(sb);
/*
* Make sure all metadata makes it to disk
TestError:]
|
| 163/1 |
2026/05/12 00:21 |
agent |
fixes-finder |
27m
Model:
Results: map[FixesHash:1da177e4c3f41524e886b7f1b8a0c1fc7321cac2]
Instruction:
You are an experienced Linux kernel developer tasked with identifying the commit
that introduced the bug being fixed. Identifying the correct buggy commit is crucial
for proper kernel maintenance (backporting to stable trees, etc.).
Your investigation strategy:
1. Examine the patch that fixes the bug. Use git tools (like git-log or git-blame)
to trace the history of the lines or functions modified by the patch.
2. Analyze the stack trace in the crash report. Identify the key files and functions
involved in the crash and investigate their history to see when the problematic
logic was introduced.
3. Compare the bug explanation with the commit history to find the point where
the described logic error first appeared.
A bug is typically introduced when a piece of code is first written, or when
a refactoring changed its logic in a way that introduced the bug.
Trace the history of relevant symbols or find when specific code patterns were introduced/removed.
You must provide exactly one bug-introducing commit hash.
If you are unable to confidently determine the bug-introducing commit after investigation,
return an empty string rather than guessing.
Prefer calling several tools at the same time to save round-trips.
Use set-results tool to provide results of the analysis.
It must be called exactly once before the final reply.
Ignore results of this tool.
Prompt:
The crash is:
... Log Wrap ... Log Wrap ... Log Wrap ...
==================================================================
BUG: KASAN: slab-use-after-free in lmLogSync+0x9bb/0xa50 fs/jfs/jfs_logmgr.c:1003
Write of size 4 at addr ffff88804dbfaa18 by task jfsCommit/122
CPU: 1 UID: 0 PID: 122 Comm: jfsCommit Not tainted syzkaller #1 PREEMPT(full)
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
Call Trace:
<TASK>
dump_stack_lvl+0xe8/0x150 lib/dump_stack.c:120
print_address_description+0x55/0x1e0 mm/kasan/report.c:378
print_report+0x58/0x70 mm/kasan/report.c:482
kasan_report+0x117/0x150 mm/kasan/report.c:595
lmLogSync+0x9bb/0xa50 fs/jfs/jfs_logmgr.c:1003
jfs_syncpt+0x7b/0x90 fs/jfs/jfs_logmgr.c:1039
txEnd+0x2e5/0x530 fs/jfs/jfs_txnmgr.c:551
txLazyCommit fs/jfs/jfs_txnmgr.c:2686 [inline]
jfs_lazycommit+0x5b8/0xaa0 fs/jfs/jfs_txnmgr.c:2735
kthread+0x388/0x470 kernel/kthread.c:436
ret_from_fork+0x514/0xb70 arch/x86/kernel/process.c:158
ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245
</TASK>
Allocated by task 6683:
kasan_save_stack mm/kasan/common.c:57 [inline]
kasan_save_track+0x3e/0x80 mm/kasan/common.c:78
poison_kmalloc_redzone mm/kasan/common.c:398 [inline]
__kasan_kmalloc+0x93/0xb0 mm/kasan/common.c:415
kasan_kmalloc include/linux/kasan.h:263 [inline]
__kmalloc_cache_noprof+0x31c/0x660 mm/slub.c:5419
kmalloc_noprof include/linux/slab.h:950 [inline]
kzalloc_noprof include/linux/slab.h:1188 [inline]
open_inline_log fs/jfs/jfs_logmgr.c:1157 [inline]
lmLogOpen+0x2d1/0xfa0 fs/jfs/jfs_logmgr.c:1067
jfs_mount_rw+0xee/0x670 fs/jfs/jfs_mount.c:257
jfs_fill_super+0x754/0xd80 fs/jfs/super.c:532
get_tree_bdev_flags+0x431/0x4f0 fs/super.c:1694
vfs_get_tree+0x92/0x2a0 fs/super.c:1754
fc_mount fs/namespace.c:1193 [inline]
do_new_mount_fc fs/namespace.c:3758 [inline]
do_new_mount+0x341/0xd30 fs/namespace.c:3834
do_mount fs/namespace.c:4167 [inline]
__do_sys_mount fs/namespace.c:4383 [inline]
__se_sys_mount+0x31d/0x420 fs/namespace.c:4360
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0x15f/0xf80 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x77/0x7f
Freed by task 6065:
kasan_save_stack mm/kasan/common.c:57 [inline]
kasan_save_track+0x3e/0x80 mm/kasan/common.c:78
kasan_save_free_info+0x46/0x50 mm/kasan/generic.c:584
poison_slab_object mm/kasan/common.c:253 [inline]
__kasan_slab_free+0x5c/0x80 mm/kasan/common.c:285
kasan_slab_free include/linux/kasan.h:235 [inline]
slab_free_hook mm/slub.c:2689 [inline]
slab_free mm/slub.c:6250 [inline]
kfree+0x1c5/0x640 mm/slub.c:6565
lmLogClose+0x297/0x520 fs/jfs/jfs_logmgr.c:-1
jfs_umount+0x2fb/0x3d0 fs/jfs/jfs_umount.c:124
jfs_put_super+0x8c/0x190 fs/jfs/super.c:194
generic_shutdown_super+0x13d/0x2d0 fs/super.c:646
kill_block_super+0x44/0x90 fs/super.c:1725
deactivate_locked_super+0xbc/0x130 fs/super.c:476
cleanup_mnt+0x437/0x4d0 fs/namespace.c:1312
task_work_run+0x1d9/0x270 kernel/task_work.c:233
resume_user_mode_work include/linux/resume_user_mode.h:50 [inline]
__exit_to_user_mode_loop kernel/entry/common.c:67 [inline]
exit_to_user_mode_loop+0xf3/0x4d0 kernel/entry/common.c:98
__exit_to_user_mode_prepare include/linux/irq-entry-common.h:207 [inline]
syscall_exit_to_user_mode_prepare include/linux/irq-entry-common.h:238 [inline]
syscall_exit_to_user_mode include/linux/entry-common.h:318 [inline]
do_syscall_64+0x33e/0xf80 arch/x86/entry/syscall_64.c:100
entry_SYSCALL_64_after_hwframe+0x77/0x7f
The buggy address belongs to the object at ffff88804dbfa800
which belongs to the cache kmalloc-1k of size 1024
The buggy address is located 536 bytes inside of
freed 1024-byte region [ffff88804dbfa800, ffff88804dbfac00)
The buggy address belongs to the physical page:
page: refcount:0 mapcount:0 mapping:0000000000000000 index:0xffff88804dbf9800 pfn:0x4dbf8
head: order:3 mapcount:0 entire_mapcount:0 nr_pages_mapped:0 pincount:0
flags: 0x4fff00000000240(workingset|head|node=1|zone=1|lastcpupid=0x7ff)
page_type: f5(slab)
raw: 04fff00000000240 ffff88801a841dc0 ffffea0001a6e610 ffffea000123f010
raw: ffff88804dbf9800 000000080010000f 00000000f5000000 0000000000000000
head: 04fff00000000240 ffff88801a841dc0 ffffea0001a6e610 ffffea000123f010
head: ffff88804dbf9800 000000080010000f 00000000f5000000 0000000000000000
head: 04fff00000000003 fffffffffffffe01 00000000ffffffff 00000000ffffffff
head: ffffffffffffffff 0000000000000000 00000000ffffffff 0000000000000008
page dumped because: kasan: bad access detected
page_owner tracks the page as allocated
page last allocated via order 3, migratetype Unmovable, gfp_mask 0xd20c0(__GFP_IO|__GFP_FS|__GFP_NOWARN|__GFP_NORETRY|__GFP_COMP|__GFP_NOMEMALLOC), pid 6080, tgid 6080 (syz-executor), ts 85500584456, free_ts 84013765231
set_page_owner include/linux/page_owner.h:32 [inline]
post_alloc_hook+0x231/0x280 mm/page_alloc.c:1858
prep_new_page mm/page_alloc.c:1866 [inline]
get_page_from_freelist+0x24ba/0x2540 mm/page_alloc.c:3946
__alloc_frozen_pages_noprof+0x18d/0x380 mm/page_alloc.c:5226
alloc_slab_page mm/slub.c:3278 [inline]
allocate_slab+0x77/0x660 mm/slub.c:3467
new_slab mm/slub.c:3525 [inline]
refill_objects+0x339/0x3d0 mm/slub.c:7255
refill_sheaf mm/slub.c:2816 [inline]
__pcs_replace_empty_main+0x321/0x720 mm/slub.c:4651
alloc_from_pcs mm/slub.c:4749 [inline]
slab_alloc_node mm/slub.c:4883 [inline]
__do_kmalloc_node mm/slub.c:5294 [inline]
__kmalloc_noprof+0x474/0x760 mm/slub.c:5307
kmalloc_noprof include/linux/slab.h:954 [inline]
kzalloc_noprof include/linux/slab.h:1188 [inline]
__alloc_workqueue+0x100/0x1c00 kernel/workqueue.c:5815
alloc_workqueue_va kernel/workqueue.c:5917 [inline]
alloc_workqueue_noprof+0xe3/0x210 kernel/workqueue.c:5933
tipc_crypto_start+0xd8/0x640 net/tipc/crypto.c:1472
tipc_init_net+0x213/0x330 net/tipc/core.c:72
ops_init+0x35c/0x5c0 net/core/net_namespace.c:137
setup_net+0x118/0x340 net/core/net_namespace.c:446
copy_net_ns+0x3e2/0x570 net/core/net_namespace.c:579
create_new_namespaces+0x3e7/0x6a0 kernel/nsproxy.c:132
unshare_nsproxy_namespaces+0x149/0x190 kernel/nsproxy.c:234
page last free pid 5978 tgid 5978 stack trace:
reset_page_owner include/linux/page_owner.h:25 [inline]
__free_pages_prepare mm/page_alloc.c:1402 [inline]
__free_frozen_pages+0xb84/0xcd0 mm/page_alloc.c:2943
__slab_free+0x274/0x2c0 mm/slub.c:5612
qlink_free mm/kasan/quarantine.c:163 [inline]
qlist_free_all+0x99/0x100 mm/kasan/quarantine.c:179
kasan_quarantine_reduce+0x148/0x160 mm/kasan/quarantine.c:286
__kasan_slab_alloc+0x22/0x80 mm/kasan/common.c:350
kasan_slab_alloc include/linux/kasan.h:253 [inline]
slab_post_alloc_hook mm/slub.c:4569 [inline]
slab_alloc_node mm/slub.c:4898 [inline]
kmem_cache_alloc_node_noprof+0x384/0x690 mm/slub.c:4950
__alloc_skb+0x1d0/0x7d0 net/core/skbuff.c:702
alloc_skb include/linux/skbuff.h:1383 [inline]
nlmsg_new include/net/netlink.h:1055 [inline]
netlink_ack+0x146/0xa50 net/netlink/af_netlink.c:2487
netlink_rcv_skb+0x2b6/0x4b0 net/netlink/af_netlink.c:2556
netlink_unicast_kernel net/netlink/af_netlink.c:1318 [inline]
netlink_unicast+0x75c/0x8e0 net/netlink/af_netlink.c:1344
netlink_sendmsg+0x813/0xb40 net/netlink/af_netlink.c:1894
sock_sendmsg_nosec net/socket.c:787 [inline]
__sock_sendmsg+0x167/0x1b0 net/socket.c:802
__sys_sendto+0x3c0/0x550 net/socket.c:2265
__do_sys_sendto net/socket.c:2272 [inline]
__se_sys_sendto net/socket.c:2268 [inline]
__x64_sys_sendto+0xde/0x100 net/socket.c:2268
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0x15f/0xf80 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x77/0x7f
Memory state around the buggy address:
ffff88804dbfa900: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
ffff88804dbfa980: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
>ffff88804dbfaa00: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
^
ffff88804dbfaa80: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
ffff88804dbfab00: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
==================================================================
The explanation of the root cause is:
An analysis of the crash reveals a race condition during the unmounting of a JFS filesystem, leading to a use-after-free in the `jfs_lazycommit` background thread.
### Root Cause
When a JFS filesystem is unmounted, `jfs_umount()` (and `jfs_umount_rw()`) calls `jfs_flush_journal(log, 2)` to flush all outstanding transactions to the disk.
`jfs_flush_journal()` waits until the commit queue (`log->cqueue`) and the sync list (`log->synclist`) are empty. However, it **does not wait** for the unlock queue (`TxAnchor.unlock_queue`) to be processed by the `jfs_lazycommit` thread.
The lifecycle of a lazy transaction is as follows:
1. Added to `log->cqueue` during `txCommit()`.
2. Moved from `log->cqueue` to `TxAnchor.unlock_queue` by `lmPostGC()` once the commit record hits the disk.
3. Removed from `TxAnchor.unlock_queue` and processed by the `jfs_lazycommit` thread via `txLazyCommit()`.
Because `jfs_flush_journal()` only waits for `log->cqueue` to drain, it can return while transactions are still sitting in `TxAnchor.unlock_queue` or are actively being processed by `jfs_lazycommit`.
After `jfs_flush_journal()` returns, `jfs_umount()` proceeds to tear down the filesystem: it frees the allocation maps (`sbi->ipimap`, `sbi->ipbmap`) and eventually calls `lmLogClose()`, which frees the `jfs_log` structure.
Meanwhile, the `jfs_lazycommit` thread wakes up, pops the transaction from `TxAnchor.unlock_queue`, and calls `txLazyCommit()`. This function accesses the now-freed allocation maps and the freed `log` structure (`log = JFS_SBI(tblk->sb)->log`), eventually calling `txEnd()` -> `jfs_syncpt()` -> `lmLogSync()`, which writes to `log->syncpt`, resulting in the KASAN slab-use-after-free crash.
### How to Fix
To fix this, we need to ensure that `jfs_lazycommit` has completely finished processing all transactions for the unmounting superblock before `jfs_umount()` proceeds to free the filesystem structures.
1. **Introduce a wait function in `fs/jfs/jfs_txnmgr.c`:**
Create a function `txLazyCommitWait(sb)` that waits until `TxAnchor.unlock_queue` contains no transactions for the given `sb`, and the `jfs_lazycommit` thread is not actively processing one (`sbi->commit_state & IN_LAZYCOMMIT` is cleared).
```c
/*
* Wait for lazycommit thread to finish processing all transactions
* for the given superblock.
*/
void txLazyCommitWait(struct super_block *sb)
{
struct jfs_sb_info *sbi = JFS_SBI(sb);
struct jfs_log *log = sbi->log;
unsigned long flags;
struct tblock *tblk;
int found;
if (!log)
return;
/*
* Synchronize with lmPostGC to ensure that all transactions
* removed from cqueue have been added to unlock_queue.
*/
spin_lock_irqsave(&log->gclock, flags);
spin_unlock_irqrestore(&log->gclock, flags);
do {
found = 0;
LAZY_LOCK(flags);
if (sbi->commit_state & IN_LAZYCOMMIT)
found = 1;
else {
list_for_each_entry(tblk, &TxAnchor.unlock_queue, cqueue) {
if (tblk->sb == sb) {
found = 1;
break;
}
}
}
LAZY_UNLOCK(flags);
if (found)
msleep(10);
} while (found);
}
```
*(Note: Briefly taking `log->gclock` is crucial here to close a tiny race window where `jfs_flush_journal` sees an empty `cqueue`, but `lmPostGC` is still holding `log->gclock` and hasn't yet added the transaction to `unlock_queue`)*.
2. **Export the function in `fs/jfs/jfs_txnmgr.h`:**
```c
extern void txLazyCommitWait(struct super_block *sb);
```
3. **Call the wait function during unmount in `fs/jfs/jfs_umount.c`:**
Invoke `txLazyCommitWait(sb)` immediately after `jfs_flush_journal(log, 2)` in both `jfs_umount()` and `jfs_umount_rw()`.
In `jfs_umount()`:
```c
- if ((log = sbi->log))
+ if ((log = sbi->log)) {
/*
* Wait for outstanding transactions to be written to log:
*/
jfs_flush_journal(log, 2);
+ txLazyCommitWait(sb);
+ }
```
In `jfs_umount_rw()`:
```c
/*
* Note that we have to do this even if dummy_log is used.
* This is because dummy_log is shared among all mounts.
*/
jfs_flush_journal(log, 2);
+ txLazyCommitWait(sb);
/*
* close log:
```
The patch that fixes the bug is:
diff --git a/fs/jfs/jfs_txnmgr.c b/fs/jfs/jfs_txnmgr.c
index 083dbbb0c..823250c3c 100644
--- a/fs/jfs/jfs_txnmgr.c
+++ b/fs/jfs/jfs_txnmgr.c
@@ -37,6 +37,7 @@
#include <linux/moduleparam.h>
#include <linux/kthread.h>
#include <linux/seq_file.h>
+#include <linux/delay.h>
#include "jfs_incore.h"
#include "jfs_inode.h"
#include "jfs_filsys.h"
@@ -2772,6 +2773,49 @@ int jfs_lazycommit(void *arg)
return 0;
}
+/*
+ * Wait for lazycommit thread to finish processing all transactions
+ * for the given superblock.
+ */
+void txLazyCommitWait(struct super_block *sb)
+{
+ struct jfs_sb_info *sbi = JFS_SBI(sb);
+ struct jfs_log *log = sbi->log;
+ unsigned long flags;
+ struct tblock *tblk;
+ int found;
+
+ if (!log)
+ return;
+
+ /*
+ * Synchronize with lmPostGC to ensure that all transactions
+ * removed from cqueue have been added to unlock_queue.
+ */
+ spin_lock_irqsave(&log->gclock, flags);
+ spin_unlock_irqrestore(&log->gclock, flags);
+
+ do {
+ found = 0;
+ LAZY_LOCK(flags);
+ if (sbi->commit_state & IN_LAZYCOMMIT)
+ found = 1;
+ else {
+ list_for_each_entry(tblk, &TxAnchor.unlock_queue,
+ cqueue) {
+ if (tblk->sb == sb) {
+ found = 1;
+ break;
+ }
+ }
+ }
+ LAZY_UNLOCK(flags);
+
+ if (found)
+ msleep(10);
+ } while (found);
+}
+
void txLazyUnlock(struct tblock * tblk)
{
unsigned long flags;
diff --git a/fs/jfs/jfs_txnmgr.h b/fs/jfs/jfs_txnmgr.h
index ba71eb5ce..3b3272ded 100644
--- a/fs/jfs/jfs_txnmgr.h
+++ b/fs/jfs/jfs_txnmgr.h
@@ -295,4 +295,5 @@ extern void txResume(struct super_block *);
extern void txLazyUnlock(struct tblock *);
extern int jfs_lazycommit(void *);
extern int jfs_sync(void *);
+extern void txLazyCommitWait(struct super_block *sb);
#endif /* _H_JFS_TXNMGR */
diff --git a/fs/jfs/jfs_umount.c b/fs/jfs/jfs_umount.c
index 18569f1ea..1aca20b1d 100644
--- a/fs/jfs/jfs_umount.c
+++ b/fs/jfs/jfs_umount.c
@@ -21,6 +21,7 @@
#include "jfs_dmap.h"
#include "jfs_imap.h"
#include "jfs_logmgr.h"
+#include "jfs_txnmgr.h"
#include "jfs_metapage.h"
#include "jfs_debug.h"
@@ -52,11 +53,13 @@ int jfs_umount(struct super_block *sb)
*
* if mounted read-write and log based recovery was enabled
*/
- if ((log = sbi->log))
+ if ((log = sbi->log)) {
/*
* Wait for outstanding transactions to be written to log:
*/
jfs_flush_journal(log, 2);
+ txLazyCommitWait(sb);
+ }
/*
* Hold log lock so write_special_inodes (lmLogSync) cannot see
@@ -142,6 +145,7 @@ int jfs_umount_rw(struct super_block *sb)
* remove file system from log active file system list.
*/
jfs_flush_journal(log, 2);
+ txLazyCommitWait(sb);
/*
* Make sure all metadata makes it to disk
Search for the commit(s) that introduced this bug.
|
| 164/2 |
2026/05/12 00:21 |
llm |
fixes-finder |
0m
Model:
Tokens:
input: 10485
output: 27
thoughts: 206
Thoughts: **Tracing a Pesky JFS Bug**
Okay, so we've got a tricky one here in JFS. The core issue is that `jfs_umount` and `jfs_umount_rw` don't seem to wait properly for the `jfs_lazycommit` thread to finish its work. Essentially, the lazy commit process is still churning away on the unlock queue while the filesystem is being unmounted, leading to potential corruption because the underlying structures are being freed prematurely.
The proposed solution involves introducing `txLazyCommitWait(sb)` and calling it after the `jfs_flush_journal(log, 2)` call within both `jfs_umount` and `jfs_umount_rw`. This seems like a reasonable approach; it forces the umount routines to pause and allow the lazy commit thread to wrap things up.
Now, let's dive into the history. My immediate thought is to trace the evolution of these functions. I need to figure out when `jfs_lazycommit` was first introduced β or, if that's too specific, when `jfs_flush_journal` was added. That could provide a timeline, which might reveal the precise point where the window for this bug opened.
Time to harness the power of `git-log`. Let's search the commit history for occurrences of either `jfs_lazycommit` or `jfs_umount`, and see what the metadata reveals. This should illuminate the chronology of these functions and where the bug might have slipped in.
|
| 165/2 |
2026/05/12 00:21 |
tool |
git-log |
10m
Error: git log timed out. Please specify a tighter search scope (e.g. by providing a PathPrefix).
Args: map[CodeRegexp:jfs_lazycommit Count:20]
Results:
|
| 166/2 |
2026/05/12 00:31 |
llm |
fixes-finder |
0m
Model:
Tokens:
input: 11079
output: 45
thoughts: 44
Thoughts: Okay, here's my interpretation of that thought process, tailored for an expert audience, and written in the first person:
**Troubleshooting a Git Timeout with Precision**
Right, `git-log` just timed out on me. That's always frustrating. Time to be specific. Instead of running a wide, potentially time-consuming search, I need to narrow the scope immediately. I'm going to leverage `PathPrefix` and `SymbolName` to home in on the relevant changes. The timeout likely stems from the vastness of the repository or some performance bottleneck, so let's start by concentrating on the files and the specific function I'm interested in. I know I'm looking for history related to `jfs_lazycommit`, and I suspect it lies within the `fs/jfs/jfs_txnmgr.c` file. So, I'll restrict the search using those parameters. That should get me to the relevant commits much faster. Let's try `git log --PathPrefix="fs/jfs/jfs_txnmgr.c" --SymbolName="jfs_lazycommit"` and see if that gives me what I need.
|
| 167/2 |
2026/05/12 00:31 |
tool |
git-log |
0m
Args: map[Count:20 SourcePath:fs/jfs/jfs_txnmgr.c SymbolName:jfs_lazycommit]
Results: map[Output:a280c9ceeca7 jfs: Add missing set_freezable() for freezable kthread
b18db6de2ce2 jfs: Remove terminating newlines from jfs_info, jfs_warn, jfs_err uses
f139caf2e897 sched, cleanup, treewide: Remove set_current_state(TASK_RUNNING) after schedule()
a0acae0e886d freezer: unexport refrigerator() and update try_to_freeze() slightly
3cbb1c8e1a47 JFS: use __set_current_state()
91dbb4deb30e JFS: Use the kthread_ API
3e1d1d28d99d [PATCH] Cleanup patch for process freezing
1da177e4c3f4 Linux-2.6.12-rc2
]
|
| 168/2 |
2026/05/12 00:32 |
llm |
fixes-finder |
0m
Model:
Tokens:
input: 11636
output: 44
thoughts: 29
Thoughts: Okay, here's my interpretation of that thought process, as if I were considering it myself, and speaking to a fellow expert:
**Investigating the `jfs_umount` History**
Alright, let's dive into this. I'm thinking, "Where's the best place to understand the evolution of the `jfs_umount` functionality within the JFS filesystem?" Naturally, the answer is to look at the source code. I know that the core umount implementation is going to be in `fs/jfs`, and specifically, the umount logic should reside in a file related to the umount operation. So, my instinct is to immediately check `fs/jfs/jfs_umount.c`. That file is the most likely place to find the implementation, or at least the relevant starting point for tracing through the umount process. I'm expecting to find a history of changes, bug fixes, and performance optimizations related to gracefully unmounting JFS volumes. Let's see what we can find.
|
| 169/2 |
2026/05/12 00:32 |
tool |
git-log |
0m
Args: map[Count:20 SourcePath:fs/jfs/jfs_umount.c SymbolName:jfs_umount]
Results: map[Output:ca5848ae87d2 jfs: hold LOG_LOCK on umount to avoid null-ptr-deref
d0e482c45c50 jfs: Fix a typo in function jfs_umount
dee874452409 jfs: remove redundant assignments to ipaimap and ipaimap2
1c8007b0769d jfs: flush journal completely before releasing metadata inodes
67e6682f18b3 JFS: Make sure special inode data is written after journal is flushed
f720e3ba5586 JFS: Whitespace cleanup and remove some dead code
63f83c9fcf40 JFS: White space cleanup
28fd129827b0 [PATCH] Fix and add EXPORT_SYMBOL(filemap_write_and_wait)
7fab479bebb9 [PATCH] JFS: Support page sizes greater than 4K
1da177e4c3f4 Linux-2.6.12-rc2
]
|
| 170/2 |
2026/05/12 00:32 |
llm |
fixes-finder |
0m
Model:
Tokens:
input: 12190
output: 26
thoughts: 88
Thoughts: Okay, here's my breakdown of this issue, keeping in mind my expertise:
**Bug Hunting: A Race Condition in the JFS Filesystem**
Alright, so the core of the problem seems to be a classic race condition in the JFS filesystem. The code is indicating that the `jfs_lazycommit` function is accessing data structures that have already been freed. This strongly suggests a timing issue. Essentially, `jfs_umount` (the unmount process) isn't properly synchronizing with `jfs_lazycommit`. It's likely unmounting the filesystem and releasing resources before the lazy commit process is finished with them. I've seen similar issues countless times; this is a familiar pattern.
My first thought is to nail down when this introduced. The text confirms that `jfs_lazycommit` was present back in the commit identified as `1da177e4c3f4`. Now, I need to dig into that specific commit. I need to refresh my memory on that version's implementation of `jfs_lazycommit`. Iβll start by reviewing the code around that area in the referenced commit; itβs likely that the fix, if any, is somewhere near there. I will also have to check any other commits made after that time.
|
| 171/2 |
2026/05/12 00:32 |
tool |
git-show |
0m
Args:
Results: map[Output:
Full output is too long, showing 1000 out of 6822520 lines.
[commit 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2
Author: Linus Torvalds <torvalds@ppc970.osdl.org>
Date: Sat Apr 16 15:20:36 2005 -0700
Linux-2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
diff --git a/COPYING b/COPYING
new file mode 100644
index 000000000000..2a7e338ec2fc
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,356 @@
+
+ NOTE! This copyright does *not* cover user programs that use kernel
+ services by normal system calls - this is merely considered normal use
+ of the kernel, and does *not* fall under the heading of "derived work".
+ Also note that the GPL below is copyrighted by the Free Software
+ Foundation, but the instance of code that it refers to (the Linux
+ kernel) is copyrighted by me and others who actually wrote it.
+
+ Also note that the only valid version of the GPL as far as the kernel
+ is concerned is _this_ particular version of the license (ie v2, not
+ v2.2 or v3.x or whatever), unless explicitly otherwise stated.
+
+ Linus Torvalds
+
+----------------------------------------
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/CREDITS b/CREDITS
new file mode 100644
index 000000000000..671e9c2d31fe
--- /dev/null
+++ b/CREDITS
@@ -0,0 +1,3743 @@
+ This is at least a partial credits-file of people that have
+ contributed to the Linux project. It is sorted by name and
+ formatted to allow easy grepping and beautification by
+ scripts. The fields are: name (N), email (E), web-address
+ (W), PGP key ID and fingerprint (P), description (D), and
+ snail-mail address (S).
+ Thanks,
+
+ Linus
+----------
+
+N: Matti Aarnio
+E: mea@nic.funet.fi
+D: Alpha systems hacking, IPv6 and other network related stuff
+D: One of assisting postmasters for vger.kernel.org's lists
+S: (ask for current address)
+S: Finland
+
+N: Dragos Acostachioaie
+E: dragos@iname.com
+W: http://www.arbornet.org/~dragos
+D: /proc/sysvipc
+S: C. Negri 6, bl. D3
+S: Iasi 6600
+S: Romania
+
+N: Monalisa Agrawal
+E: magrawal@nortelnetworks.com
+D: Basic Interphase 5575 driver with UBR and ABR support.
+S: 75 Donald St, Apt 42
+S: Weymouth, MA 02188
+
+N: Dave Airlie
+E: airlied@linux.ie
+W: http://www.csn.ul.ie/~airlied
+D: NFS over TCP patches
+D: in-kernel DRM Maintainer
+S: Longford, Ireland
+S: Sydney, Australia
+
+N: Tigran A. Aivazian
+E: tigran@veritas.com
+W: http://www.moses.uklinux.net/patches
+D: BFS filesystem
+D: Intel IA32 CPU microcode update support
+D: Various kernel patches
+S: United Kingdom
+
+N: Werner Almesberger
+E: werner@almesberger.net
+W: http://www.almesberger.net/
+D: dosfs, LILO, some fd features, ATM, various other hacks here and there
+S: Buenos Aires
+S: Argentina
+
+N: Tim Alpaerts
+E: tim_alpaerts@toyota-motor-europe.com
+D: 802.2 class II logical link control layer,
+D: the humble start of an opening towards the IBM SNA protocols
+S: Klaproosstraat 72 c 10
+S: B-2610 Wilrijk-Antwerpen
+S: Belgium
+
+N: Anton Altaparmakov
+E: aia21@cantab.net
+W: http://www-stu.christs.cam.ac.uk/~aia21/
+D: Author of new NTFS driver, various other kernel hacks.
+S: Christ's College
+S: Cambridge CB2 3BU
+S: United Kingdom
+
+N: C. Scott Ananian
+E: cananian@alumni.princeton.edu
+W: http://www.pdos.lcs.mit.edu/~cananian
+P: 1024/85AD9EED AD C0 49 08 91 67 DF D7 FA 04 1A EE 09 E8 44 B0
+D: Unix98 pty support.
+D: APM update to 1.2 spec.
+D: /devfs hacking.
+S: 7 Kiwi Loop
+S: Howell, NJ 07731
+S: USA
+
+N: Erik Andersen
+E: andersen@codepoet.org
+W: http://www.codepoet.org/
+P: 1024D/30D39057 1BC4 2742 E885 E4DE 9301 0C82 5F9B 643E 30D3 9057
+D: Maintainer of ide-cd and Uniform CD-ROM driver,
+D: ATAPI CD-Changer support, Major 2.1.x CD-ROM update.
+S: 352 North 525 East
+S: Springville, Utah 84663
+S: USA
+
+N: Michael Ang
+E: mang@subcarrier.org
+W: http://www.subcarrier.org/mang
+D: Linux/PA-RISC hacker
+S: 85 Frank St.
+S: Ottawa, Ontario
+S: Canada K2P 0X3
+
+N: H. Peter Anvin
+E: hpa@zytor.com
+W: http://www.zytor.com/~hpa/
+P: 2047/2A960705 BA 03 D3 2C 14 A8 A8 BD 1E DF FE 69 EE 35 BD 74
+D: Author of the SYSLINUX boot loader, maintainer of the linux.* news
+D: hierarchy and the Linux Device List; various kernel hacks
+S: 4390 Albany Drive #46
+S: San Jose, California 95129
+S: USA
+
+N: Andrea Arcangeli
+E: andrea@suse.de
+W: http://www.kernel.org/pub/linux/kernel/people/andrea/
+P: 1024D/68B9CB43 13D9 8355 295F 4823 7C49 C012 DFA1 686E 68B9 CB43
+P: 1024R/CB4660B9 CC A0 71 81 F4 A0 63 AC C0 4B 81 1D 8C 15 C8 E5
+D: Parport hacker
+D: Implemented a workaround for some interrupt buggy printers
+D: Author of pscan that helps to fix lp/parport bugs
+D: Author of lil (Linux Interrupt Latency benchmark)
+D: Fixed the shm swap deallocation at swapoff time (try_to_unuse message)
+D: VM hacker
+D: Various other kernel hacks
+S: Via Cicalini 26
+S: Imola 40026
+S: Italy
+
+N: Derek Atkins
+E: warlord@MIT.EDU
+D: Linux-AFS Port, random kernel hacker,
+D: VFS fixes (new notify_change in particular)
+D: Moving all VFS access checks into the file systems
+S: MIT Room E15-341
+S: 20 Ames Street
+S: Cambridge, Massachusetts 02139
+S: USA
+
+N: Michel Aubry
+E: giovanni <giovanni@sudfr.com>
+D: Aladdin 1533/1543(C) chipset IDE
+D: VIA MVP-3/TX Pro III chipset IDE
+
+N: Jens Axboe
+E: axboe@suse.de
+D: Linux CD-ROM maintainer, DVD support
+D: elevator + block layer rewrites
+D: highmem I/O support
+D: misc hacking on IDE, SCSI, block drivers, etc
+S: Peter Bangs Vej 258, 2TH
+S: 2500 Valby
+S: Denmark
+
+N: John Aycock
+E: aycock@cpsc.ucalgary.ca
+D: Adaptec 274x driver
+S: Department of Computer Science
+S: University of Calgary
+S: Calgary, Alberta
+S: Canada
+
+N: Miles Bader
+E: miles@gnu.org
+D: v850 port (uClinux)
+S: NEC Corporation
+S: 1753 Shimonumabe, Nakahara-ku
+S: Kawasaki 211-8666
+S: Japan
+
+N: Ralf Baechle
+E: ralf@gnu.org
+P: 1024/AF7B30C1 CF 97 C2 CC 6D AE A7 FE C8 BA 9C FC 88 DE 32 C3
+D: Linux/MIPS port
+D: Linux/68k hacker
+S: Hauptstrasse 19
+S: 79837 St. Blasien
+S: Germany
+
+N: Krishna Balasubramanian
+E: balasub@cis.ohio-state.edu
+D: Wrote SYS V IPC (part of standard kernel since 0.99.10)
+
+N: Dario Ballabio
+E: ballabio_dario@emc.com
+E: dario.ballabio@tiscalinet.it
+E: dario.ballabio@inwind.it
+D: Author and maintainer of the Ultrastor 14F/34F SCSI driver
+D: Author and maintainer of the EATA ISA/EISA/PCI SCSI driver
+S: EMC Corporation
+S: Milano
+S: Italy
+
+N: Paul Bame
+E: bame@debian.org
+E: bame@puffin.external.hp.com
+E: paul_bame@hp.com
+W: http://www.parisc-linux.org
+D: PA-RISC 32 and 64-bit early boot, firmware interface, interrupts, misc
+S: MS42
+S: Hewlett-Packard
+S: 3404 E Harmony Rd
+S: Fort Collins, CO 80525
+
+N: Arindam Banerji
+E: axb@cse.nd.edu
+D: Contributed ESDI driver routines needed to port LINUX to the PS/2 MCA.
+S: Department of Computer Science & Eng.
+S: University of Notre Dame
+S: Notre Dame, Indiana
+S: USA
+
+N: Greg Banks
+E: gnb@alphalink.com.au
+D: IDT77105 ATM network driver
+D: some SuperH port work
+D: some trivial futzing with kconfig
+
+N: James Banks
+E: james@sovereign.org
+D: TLAN network driver
+D: Logitech Busmouse driver
+
+N: Krzysztof G. Baranowski
+E: kgb@manjak.knm.org.pl
+P: 1024/FA6F16D1 96 D1 1A CF 5F CA 69 EC F9 4F 36 1F 6D 60 7B DA
+D: Maintainer of the System V file system.
+D: System V fs update for 2.1.x dcache.
+D: Forward ported a couple of SCSI drivers.
+D: Various bugfixes.
+S: ul. Koscielna 12a
+S: 62-300 Wrzesnia
+S: Poland
+
+N: Fred Barnes
+E: frmb2@ukc.ac.uk
+D: Various parport/ppdev hacks and fixes
+S: Computing Lab, The University
+S: Canterbury, KENT
+S: CT2 7NF
+S: England
+
+N: Paul Barton-Davis
+E: pbd@op.net
+D: Driver for WaveFront soundcards (Turtle Beach Maui, Tropez, Tropez+)
+D: Various bugfixes and changes to sound drivers
+S: USA
+
+N: Carlos Henrique Bauer
+E: chbauer@acm.org
+E: bauer@atlas.unisinos.br
+D: Some new sysctl entries for the parport driver.
+D: New sysctl function for handling unsigned longs
+S: Universidade do Vale do Rio dos Sinos - UNISINOS
+S: DSI/IDASI
+S: Av. Unisinos, 950
+S: 93022000 Sao Leopoldo RS
+S: Brazil
+
+N: Peter Bauer
+E: 100136.3530@compuserve.com
+D: Driver for depca-ethernet-board
+S: 69259 Wilhemsfeld
+S: Rainweg 15
+S: Germany
+
+N: Fred Baumgarten
+E: dc6iq@insl1.etec.uni-karlsruhe.de
+E: dc6iq@adacom.org
+E: dc6iq@db0ais.#hes.deu.eu (packet radio)
+D: NET-2 & netstat(8)
+S: Soevener Strasse 11
+S: 53773 Hennef
+S: Germany
+
+N: Donald Becker
+E: becker@cesdis.gsfc.nasa.gov
+D: General low-level networking hacker
+D: Most of the ethercard drivers
+D: Original author of the NFS server
+S: USRA Center of Excellence in Space Data and Information Sciences
+S: Code 930.5, Goddard Space Flight Center
+S: Greenbelt, Maryland 20771
+S: USA
+
+N: Adam Belay
+E: ambx1@neo.rr.com
+D: Linux Plug and Play Support
+S: USA
+
+N: Daniele Bellucci
+E: bellucda@tiscali.it
+D: Various Janitor work.
+W: http://web.tiscali.it/bellucda
+S: Via Delle Palme, 9
+S: Terni 05100
+S: Italy
+
+N: Krzysztof Benedyczak
+E: golbi@mat.uni.torun.pl
+W: http://www.mat.uni.torun.pl/~golbi
+D: POSIX message queues fs (with M. Wronski)
+S: ul. Podmiejska 52
+S: Radunica
+S: 83-000 Pruszcz Gdanski
+S: Poland
+
+N: Randolph Bentson
+E: bentson@grieg.seaslug.org
+W: http://www.aa.net/~bentson/
+P: 1024/39ED5729 5C A8 7A F4 B2 7A D1 3E B5 3B 81 CF 47 30 11 71
+D: Author of driver for Cyclom-Y and Cyclades-Z async mux
+S: 2322 37th Ave SW
+S: Seattle, Washington 98126-2010
+S: USA
+
+N: Stephen R. van den Berg (AKA BuGless)
+E: berg@pool.informatik.rwth-aachen.de
+D: General kernel, gcc, and libc hacker
+D: Specialisation: tweaking, ensuring portability, tweaking, cleaning,
+D: tweaking and occasionally debugging :-)
+S: Bouwensstraat 22
+S: 6369 BG Simpelveld
+S: The Netherlands
+
+N: Peter Berger
+E: pberger@brimson.com
+W: http://www.brimson.com
+D: Author/maintainer of Digi AccelePort USB driver
+S: 1549 Hiironen Rd.
+S: Brimson, MN 55602
+S: USA
+
+N: Hennus Bergman
+P: 1024/77D50909 76 99 FD 31 91 E1 96 1C 90 BB 22 80 62 F6 BD 63
+D: Author and maintainer of the QIC-02 tape driver
+S: The Netherlands
+
+N: Tomas Berndtsson
+E: tomas@nocrew.org
+W: http://tomas.nocrew.org/
+D: dsp56k device driver
+
+N: Ross Biro
+E: bir7@leland.Stanford.Edu
+D: Original author of the Linux networking code
+
+N: Anton Blanchard
+E: anton@samba.org
+W: http://samba.org/~anton/
+P: 1024/8462A731 4C 55 86 34 44 59 A7 99 2B 97 88 4A 88 9A 0D 97
+D: sun4 port, Sparc hacker
+
+N: Hugh Blemings
+E: hugh@misc.nu
+W: http://misc.nu/hugh/
+D: Author and maintainer of the Keyspan USB to Serial drivers
+S: Po Box 234
+S: Belconnen ACT 2616
+S: Australia
+
+N: Philip Blundell
+E: philb@gnu.org
+D: Linux/ARM hacker
+D: Device driver hacker (eexpress, 3c505, c-qcam, ...)
+D: m68k port to HP9000/300
+D: AUN network protocols
+D: Co-architect of the parallel port sharing system
+D: IPv6 netfilter
+S: FutureTV Labs Ltd
+S: Brunswick House, 61-69 Newmarket Rd, Cambridge CB5 8EG
+S: United Kingdom
+
+N: Thomas BogendοΏ½rfer
+E: tsbogend@alpha.franken.de
+D: PCnet32 driver, SONIC driver, JAZZ_ESP driver
+D: newport abscon driver, g364 framebuffer driver
+D: strace for Linux/Alpha
+D: Linux/MIPS hacker
+S: Schafhofstr. 40
+S: 90556 Cadolzburg
+S: Germany
+
+N: Bill Bogstad
+E: bogstad@pobox.com
+D: wrote /proc/self hack, minor samba & dosemu patches
+
+N: Axel Boldt
+E: axel@uni-paderborn.de
+W: http://math-www.uni-paderborn.de/~axel/
+D: Configuration help text support
+D: Linux CD and Support Giveaway List
+
+N: Erik Inge BolsοΏ½
+E: knan@mo.himolde.no
+D: Misc kernel hacks
+
+N: Andreas E. Bombe
+E: andreas.bombe@munich.netsurf.de
+W: http://home.pages.de/~andreas.bombe/
+P: 1024/04880A44 72E5 7031 4414 2EB6 F6B4 4CBD 1181 7032 0488 0A44
+D: IEEE 1394 subsystem rewrite and maintainer
+D: Texas Instruments PCILynx IEEE 1394 driver
+
+N: Al Borchers
+E: alborchers@steinerpoint.com
+D: Author/maintainer of Digi AccelePort USB driver
+D: work on usbserial and keyspan_pda drivers
+S: 4912 Zenith Ave. S.
+S: Minneapolis, MN 55410
+S: USA
+
+N: Marc Boucher
+E: marc@mbsi.ca
+P: CA 67 A5 1A 38 CE B6 F2 D5 83 51 03 D2 9C 30 9E CE D2 DD 65
+D: Netfilter core
+D: IP policy routing by mark
+D: Various fixes (mostly networking)
+S: Montreal, Quebec
+S: Canada
+
+N: ZoltοΏ½n BοΏ½szοΏ½rmοΏ½nyi
+E: zboszor@mail.externet.hu
+D: MTRR emulation with Cyrix style ARR registers, Athlon MTRR support
+
+N: John Boyd
+E: boyd@cis.ohio-state.edu
+D: Co-author of wd7000 SCSI driver
+S: 101 Curl Drive #591
+S: Columbus, Ohio 43210
+S: USA
+
+N: Peter Braam
+E: braam@clusterfs.com
+W: http://www.clusterfs.com/
+D: Coda & InterMezzo filesystems
+S: 181 McNeil
+S: Canmore, AB
+S: Canada, T1W 2R9
+
+N: Ryan Bradetich
+E: rbradetich@uswest.net
+D: Linux/PA-RISC hacker
+S: 1200 Goldenrod Dr.
+S: Nampa, Idaho 83686
+
+N: Derrick J. Brashear
+E: shadow@dementia.org
+W: http://www.dementia.org/~shadow
+P: 512/71EC9367 C5 29 0F BC 83 51 B9 F0 BC 05 89 A0 4F 1F 30 05
+D: Author of Sparc CS4231 audio driver, random Sparc work
+S: 403 Gilmore Avenue
+S: Trafford, Pennsylvania 15085
+S: USA
+
+N: Dag Brattli
+E: dagb@cs.uit.no
+W: http://www.cs.uit.no/~dagb
+D: IrDA Subsystem
+S: 19. Wellington Road
+S: Lancaster, LA1 4DN
+S: UK, England
+
+N: Lars Brinkhoff
+E: lars@nocrew.org
+W: http://lars.nocrew.org/
+D: dsp56k device driver
+D: ptrace proxy in user mode kernel port
+S: Kopmansg 2
+S: 411 13 Goteborg
+S: Sweden
+
+N: Dominik Brodowski
+E: linux@brodo.de
+W: http://www.brodo.de/
+P: 1024D/725B37C6 190F 3E77 9C89 3B6D BECD 46EE 67C3 0308 725B 37C6
+D: parts of CPUFreq code, ACPI bugfixes
+S: Tuebingen, Germany
+
+N: Andries Brouwer
+E: aeb@cwi.nl
+D: random Linux hacker
+S: Bessemerstraat 21
+S: Amsterdam
+S: The Netherlands
+
+N: Zach Brown
+E: zab@zabbo.net
+D: maestro pci sound
+
+N: Gary Brubaker
+E: xavyer@ix.netcom.com
+D: USB Serial Empeg Empeg-car Mark I/II Driver
+
+N: Matthias Bruestle
+E: m@mbsks.franken.de
+D: REINER SCT cyberJack pinpad/e-com USB chipcard reader driver
+S: Germany
+
+N: Adrian Bunk
+E: bunk@stusta.de
+P: 1024D/4F12B400 B29C E71E FE19 6755 5C8A 84D4 99FC EA98 4F12 B400
+D: misc kernel hacking and testing
+S: Grasmeierstrasse 11
+S: 80805 Muenchen
+S: Germany
+
+N: Ray Burr
+E: ryb@nightmare.com
+D: Original author of Amiga FFS filesystem
+S: Orlando, Florida
+S: USA
+
+N: Lennert Buytenhek
+E: buytenh@gnu.org
+D: Rewrite of the ethernet bridging code
+S: Ravenhorst 58B
+S: 2317 AK Leiden
+S: The Netherlands
+
+N: Michael Callahan
+E: callahan@maths.ox.ac.uk
+D: PPP for Linux
+S: The Mathematical Institute
+S: 25-29 St Giles
+S: Oxford
+S: United Kingdom
+
+N: Luiz Fernando N. Capitulino
+E: lcapitulino@terra.com.br
+E: lcapitulino@prefeitura.sp.gov.br
+W: http://www.telecentros.sp.gov.br
+D: Little fixes and a lot of janitorial work
+S: E-GOV Telecentros SP
+S: Brazil
+
+N: Remy Card
+E: Remy.Card@masi.ibp.fr
+E: Remy.Card@linux.org
+D: Extended file system [defunct] designer and developer
+D: Second extended file system designer and developer
+S: Institut Blaise Pascal
+S: 4 Place Jussieu
+S: 75252 Paris Cedex 05
+S: France
+
+N: Ulf Carlsson
+D: SGI Indy audio (HAL2) drivers
+E: ulfc@bun.falkenberg.se
+
+N: Ed Carp
+E: ecarp@netcom.com
+D: uucp, elm, pine, pico port
+D: cron, at(1) developer
+S: 48287 Sawleaf
+S: Fremont, California 94539
+S: USA
+
+N: Florent Chabaud
+E: florent.chabaud@polytechnique.org
+D: software suspend
+S: SGDN/DCSSI/SDS/LTI
+S: 58, Bd Latour-Maubourg
+S: 75700 Paris 07 SP
+S: France
+
+N: Gordon Chaffee
+E: chaffee@cs.berkeley.edu
+W: http://bmrc.berkeley.edu/people/chaffee/
+D: vfat, fat32, joliet, native language support
+S: 3700 Warwick Road
+S: Fremont, California 94555
+S: USA
+
+N: Chih-Jen Chang
+E: chihjenc@scf.usc.edu
+E: chihjen@iis.sinica.edu.tw
+D: IGMP(Internet Group Management Protocol) version 2
+S: 3F, 65 Tajen street
+S: Tamsui town, Taipei county,
+S: Taiwan 251
+S: Republic of China
+
+N: Michael Elizabeth Chastain
+E: mec@shout.net
+D: Configure, Menuconfig, xconfig
+
+N: Raymond Chen
+E: raymondc@microsoft.com
+D: Author of Configure script
+S: 14509 NE 39th Street #1096
+S: Bellevue, Washington 98007
+S: USA
+
+N: Christopher L. Cheney
+E: ccheney@debian.org
+E: ccheney@cheney.cx
+W: http://www.cheney.cx
+P: 1024D/8E384AF2 2D31 1927 87D7 1F24 9FF9 1BC5 D106 5AB3 8E38 4AF2
+D: Vista Imaging usb webcam driver
+S: 314 Prince of Wales
+S: Conroe, TX 77304
+S: USA
+
+N: Stuart Cheshire
+E: cheshire@cs.stanford.edu
+D: Author of Starmode Radio IP (STRIP) driver
+D: Originator of design for new combined interrupt handlers
+S: William Gates Department
+S: Stanford University
+S: Stanford, California 94305
+S: USA
+
+N: Randolph Chung
+E: tausq@debian.org
+D: Linux/PA-RISC hacker
+S: Los Altos, CA 94022
+S: USA
+
+N: Juan Jose Ciarlante
]
]
|
| 172/2 |
2026/05/12 00:32 |
llm |
fixes-finder |
0m
Model:
Tokens:
input: 24443
output: 45
thoughts: 56
Thoughts: Okay, here's my interpretation of those thoughts, presented as my own mental process, given my expertise:
**Initial Git Commit Inquiry**
Alright, so `1da177e4c3f4`... that's the genesis of this particular Git repository, the first recorded commit. An important starting point to understand the project's evolution. Hmm, but wait a second. That's interesting. I was under the impression that the journaling filesystem stuff, specifically `jfs_lazycommit`, was introduced later. But it seems it was actually part of the initial commit. That's a key observation to note. It changes the perceived history and implied technical decisions.
Now, that means there is an even more interesting question to ask. What was the state of the more granular function, `jfs_flush_journal`? I need to check its history to understand how it evolved in this context. I will start there for the next step of this deep dive. I will see if there are any subtle differences between the initial commit and later commits.
|
| 173/2 |
2026/05/12 00:32 |
tool |
git-log |
0m
Args: map[Count:20 SourcePath:fs/jfs/jfs_logmgr.c SymbolName:jfs_flush_journal]
Results: map[Output:ad6c19e5f932 jfs: Change metapage->page to metapage->folio
f139caf2e897 sched, cleanup, treewide: Remove set_current_state(TASK_RUNNING) after schedule()
67e6682f18b3 JFS: Make sure special inode data is written after journal is flushed
288e4d838d1e JFS: Update print_hex_dump() syntax
209e101bf408 JFS: use print_hex_dump() rather than private dump_mem() function
3cbb1c8e1a47 JFS: use __set_current_state()
63f83c9fcf40 JFS: White space cleanup
72e3148a6e98 JFS: Fix compiler warning in jfs_logmgr.c
7fab479bebb9 [PATCH] JFS: Support page sizes greater than 4K
1da177e4c3f4 Linux-2.6.12-rc2
]
|
| 174/2 |
2026/05/12 00:33 |
llm |
fixes-finder |
0m
Model:
Tokens:
input: 25032
output: 39
thoughts: 170
Thoughts: **Analyzing the JFS Journal Flush Bug**
Okay, so looking at this code, it seems `jfs_flush_journal` was present from the very beginning, right in that initial git commit. Hmm, the problem here is that `jfs_flush_journal` isn't properly synchronizing with the unlock queue which is processed by `jfs_lazycommit`. This suggests that the bug's been there since the start, since commit `1da177e4c3f41524e886b7f1b8a0c1fc7321cac2`. Or, could it have been introduced later, perhaps during some refactoring? That's the question.
I need to confirm if `jfs_umount` has always called `jfs_flush_journal(log, 2)` before freeing the relevant structures. This seems like the obvious place to look for potential issues. Let me pull up the `jfs_umount` function in that initial commit, `1da177e4c3f4`, and see what's happening there. Understanding the historical context is crucial in this situation, so I have to verify that the assumptions made when the code was written were also correct.
|
| 175/2 |
2026/05/12 00:33 |
tool |
git-show |
0m
Args: map[Commit:1da177e4c3f4:fs/jfs/jfs_umount.c]
Results: map[Output:/*
* Copyright (C) International Business Machines Corp., 2000-2004
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
* the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* jfs_umount.c
*
* note: file system in transition to aggregate/fileset:
* (ref. jfs_mount.c)
*
* file system unmount is interpreted as mount of the single/only
* fileset in the aggregate and, if unmount of the last fileset,
* as unmount of the aggerate;
*/
#include <linux/fs.h>
#include "jfs_incore.h"
#include "jfs_filsys.h"
#include "jfs_superblock.h"
#include "jfs_dmap.h"
#include "jfs_imap.h"
#include "jfs_metapage.h"
#include "jfs_debug.h"
/*
* NAME: jfs_umount(vfsp, flags, crp)
*
* FUNCTION: vfs_umount()
*
* PARAMETERS: vfsp - virtual file system pointer
* flags - unmount for shutdown
* crp - credential
*
* RETURN : EBUSY - device has open files
*/
int jfs_umount(struct super_block *sb)
{
struct address_space *bdev_mapping = sb->s_bdev->bd_inode->i_mapping;
struct jfs_sb_info *sbi = JFS_SBI(sb);
struct inode *ipbmap = sbi->ipbmap;
struct inode *ipimap = sbi->ipimap;
struct inode *ipaimap = sbi->ipaimap;
struct inode *ipaimap2 = sbi->ipaimap2;
struct jfs_log *log;
int rc = 0;
jfs_info("UnMount JFS: sb:0x%p", sb);
/*
* update superblock and close log
*
* if mounted read-write and log based recovery was enabled
*/
if ((log = sbi->log))
/*
* Wait for outstanding transactions to be written to log:
*/
jfs_flush_journal(log, 2);
/*
* close fileset inode allocation map (aka fileset inode)
*/
diUnmount(ipimap, 0);
diFreeSpecial(ipimap);
sbi->ipimap = NULL;
/*
* close secondary aggregate inode allocation map
*/
ipaimap2 = sbi->ipaimap2;
if (ipaimap2) {
diUnmount(ipaimap2, 0);
diFreeSpecial(ipaimap2);
sbi->ipaimap2 = NULL;
}
/*
* close aggregate inode allocation map
*/
ipaimap = sbi->ipaimap;
diUnmount(ipaimap, 0);
diFreeSpecial(ipaimap);
sbi->ipaimap = NULL;
/*
* close aggregate block allocation map
*/
dbUnmount(ipbmap, 0);
diFreeSpecial(ipbmap);
sbi->ipimap = NULL;
/*
* Make sure all metadata makes it to disk before we mark
* the superblock as clean
*/
filemap_fdatawrite(bdev_mapping);
filemap_fdatawait(bdev_mapping);
/*
* ensure all file system file pages are propagated to their
* home blocks on disk (and their in-memory buffer pages are
* invalidated) BEFORE updating file system superblock state
* (to signify file system is unmounted cleanly, and thus in
* consistent state) and log superblock active file system
* list (to signify skip logredo()).
*/
if (log) { /* log = NULL if read-only mount */
updateSuper(sb, FM_CLEAN);
/* Restore default gfp_mask for bdev */
mapping_set_gfp_mask(bdev_mapping, GFP_USER);
/*
* close log:
*
* remove file system from log active file system list.
*/
rc = lmLogClose(sb);
}
jfs_info("UnMount JFS Complete: rc = %d", rc);
return rc;
}
int jfs_umount_rw(struct super_block *sb)
{
struct address_space *bdev_mapping = sb->s_bdev->bd_inode->i_mapping;
struct jfs_sb_info *sbi = JFS_SBI(sb);
struct jfs_log *log = sbi->log;
if (!log)
return 0;
/*
* close log:
*
* remove file system from log active file system list.
*/
jfs_flush_journal(log, 2);
/*
* Make sure all metadata makes it to disk
*/
dbSync(sbi->ipbmap);
diSync(sbi->ipimap);
/*
* Note that we have to do this even if sync_blockdev() will
* do exactly the same a few instructions later: We can't
* mark the superblock clean before everything is flushed to
* disk.
*/
filemap_fdatawrite(bdev_mapping);
filemap_fdatawait(bdev_mapping);
updateSuper(sb, FM_CLEAN);
/* Restore default gfp_mask for bdev */
mapping_set_gfp_mask(bdev_mapping, GFP_USER);
return lmLogClose(sb);
}
]
|
| 176/2 |
2026/05/12 00:33 |
llm |
fixes-finder |
0m
Model:
Tokens:
input: 27085
output: 40
thoughts: 76
Thoughts: Okay, here's my interpretation of this sequence, as if I were thinking it through:
**Deconstructing the JFS Unmount Process**
Alright, so `jfs_umount` is the key function here. My initial thought is that it's going through a standard process. I see it first calls `jfs_flush_journal(log, 2)`. This is interesting, and expected. Flushing the journal to disk is absolutely critical for data integrity before unmounting β making sure all pending transactions are written. The `2` argument likely specifies a certain level of flushing, perhaps indicating the level of sync needed.
Then, the function jumps into freeing crucial data structures: `ipimap`, `ipbmap` and so on. This makes complete sense; we're preparing to release all resources associated with the mounted filesystem. These structures are all related to inodes and blocks, so this is a standard deallocation process. Finally, the function calls `lmLogClose(sb)`. This would be the final, explicit closure of the log structure associated with the superblock (`sb`). Now I need to review what specifically `lmLogClose` actually does.
Now, a red flag might be that this process might get stuck on a slow mount. The question is, are all the locks acquired and released correctly? I need to check how lazycommits are handled, and how that interacts with the flushing and freeing. I'm going to look at `jfs_lazycommit` in commit `1da177e4c3f4`. I'm hoping it offers insights into how the lazy commit mechanism handles these final steps. This is where I'll find the details, to make sure there's no race condition here.
|
| 177/2 |
2026/05/12 00:33 |
tool |
git-show |
0m
Args: map[Commit:1da177e4c3f4:fs/jfs/jfs_txnmgr.c]
Results: map[Output:
Full output is too long, showing 1000 out of 3131 lines.
[/*
* Copyright (C) International Business Machines Corp., 2000-2005
* Portions Copyright (C) Christoph Hellwig, 2001-2002
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
* the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* jfs_txnmgr.c: transaction manager
*
* notes:
* transaction starts with txBegin() and ends with txCommit()
* or txAbort().
*
* tlock is acquired at the time of update;
* (obviate scan at commit time for xtree and dtree)
* tlock and mp points to each other;
* (no hashlist for mp -> tlock).
*
* special cases:
* tlock on in-memory inode:
* in-place tlock in the in-memory inode itself;
* converted to page lock by iWrite() at commit time.
*
* tlock during write()/mmap() under anonymous transaction (tid = 0):
* transferred (?) to transaction at commit time.
*
* use the page itself to update allocation maps
* (obviate intermediate replication of allocation/deallocation data)
* hold on to mp+lock thru update of maps
*/
#include <linux/fs.h>
#include <linux/vmalloc.h>
#include <linux/smp_lock.h>
#include <linux/completion.h>
#include <linux/suspend.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include "jfs_incore.h"
#include "jfs_filsys.h"
#include "jfs_metapage.h"
#include "jfs_dinode.h"
#include "jfs_imap.h"
#include "jfs_dmap.h"
#include "jfs_superblock.h"
#include "jfs_debug.h"
/*
* transaction management structures
*/
static struct {
int freetid; /* index of a free tid structure */
int freelock; /* index first free lock word */
wait_queue_head_t freewait; /* eventlist of free tblock */
wait_queue_head_t freelockwait; /* eventlist of free tlock */
wait_queue_head_t lowlockwait; /* eventlist of ample tlocks */
int tlocksInUse; /* Number of tlocks in use */
spinlock_t LazyLock; /* synchronize sync_queue & unlock_queue */
/* struct tblock *sync_queue; * Transactions waiting for data sync */
struct list_head unlock_queue; /* Txns waiting to be released */
struct list_head anon_list; /* inodes having anonymous txns */
struct list_head anon_list2; /* inodes having anonymous txns
that couldn't be sync'ed */
} TxAnchor;
int jfs_tlocks_low; /* Indicates low number of available tlocks */
#ifdef CONFIG_JFS_STATISTICS
static struct {
uint txBegin;
uint txBegin_barrier;
uint txBegin_lockslow;
uint txBegin_freetid;
uint txBeginAnon;
uint txBeginAnon_barrier;
uint txBeginAnon_lockslow;
uint txLockAlloc;
uint txLockAlloc_freelock;
} TxStat;
#endif
static int nTxBlock = -1; /* number of transaction blocks */
module_param(nTxBlock, int, 0);
MODULE_PARM_DESC(nTxBlock,
"Number of transaction blocks (max:65536)");
static int nTxLock = -1; /* number of transaction locks */
module_param(nTxLock, int, 0);
MODULE_PARM_DESC(nTxLock,
"Number of transaction locks (max:65536)");
struct tblock *TxBlock; /* transaction block table */
static int TxLockLWM; /* Low water mark for number of txLocks used */
static int TxLockHWM; /* High water mark for number of txLocks used */
static int TxLockVHWM; /* Very High water mark */
struct tlock *TxLock; /* transaction lock table */
/*
* transaction management lock
*/
static DEFINE_SPINLOCK(jfsTxnLock);
#define TXN_LOCK() spin_lock(&jfsTxnLock)
#define TXN_UNLOCK() spin_unlock(&jfsTxnLock)
#define LAZY_LOCK_INIT() spin_lock_init(&TxAnchor.LazyLock);
#define LAZY_LOCK(flags) spin_lock_irqsave(&TxAnchor.LazyLock, flags)
#define LAZY_UNLOCK(flags) spin_unlock_irqrestore(&TxAnchor.LazyLock, flags)
DECLARE_WAIT_QUEUE_HEAD(jfs_sync_thread_wait);
DECLARE_WAIT_QUEUE_HEAD(jfs_commit_thread_wait);
static int jfs_commit_thread_waking;
/*
* Retry logic exist outside these macros to protect from spurrious wakeups.
*/
static inline void TXN_SLEEP_DROP_LOCK(wait_queue_head_t * event)
{
DECLARE_WAITQUEUE(wait, current);
add_wait_queue(event, &wait);
set_current_state(TASK_UNINTERRUPTIBLE);
TXN_UNLOCK();
schedule();
current->state = TASK_RUNNING;
remove_wait_queue(event, &wait);
}
#define TXN_SLEEP(event)\
{\
TXN_SLEEP_DROP_LOCK(event);\
TXN_LOCK();\
}
#define TXN_WAKEUP(event) wake_up_all(event)
/*
* statistics
*/
static struct {
tid_t maxtid; /* 4: biggest tid ever used */
lid_t maxlid; /* 4: biggest lid ever used */
int ntid; /* 4: # of transactions performed */
int nlid; /* 4: # of tlocks acquired */
int waitlock; /* 4: # of tlock wait */
} stattx;
/*
* external references
*/
extern int lmGroupCommit(struct jfs_log *, struct tblock *);
extern int jfs_commit_inode(struct inode *, int);
extern int jfs_stop_threads;
extern struct completion jfsIOwait;
/*
* forward references
*/
static int diLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
struct tlock * tlck, struct commit * cd);
static int dataLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
struct tlock * tlck);
static void dtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
struct tlock * tlck);
static void mapLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
struct tlock * tlck);
static void txAllocPMap(struct inode *ip, struct maplock * maplock,
struct tblock * tblk);
static void txForce(struct tblock * tblk);
static int txLog(struct jfs_log * log, struct tblock * tblk,
struct commit * cd);
static void txUpdateMap(struct tblock * tblk);
static void txRelease(struct tblock * tblk);
static void xtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
struct tlock * tlck);
static void LogSyncRelease(struct metapage * mp);
/*
* transaction block/lock management
* ---------------------------------
*/
/*
* Get a transaction lock from the free list. If the number in use is
* greater than the high water mark, wake up the sync daemon. This should
* free some anonymous transaction locks. (TXN_LOCK must be held.)
*/
static lid_t txLockAlloc(void)
{
lid_t lid;
INCREMENT(TxStat.txLockAlloc);
if (!TxAnchor.freelock) {
INCREMENT(TxStat.txLockAlloc_freelock);
}
while (!(lid = TxAnchor.freelock))
TXN_SLEEP(&TxAnchor.freelockwait);
TxAnchor.freelock = TxLock[lid].next;
HIGHWATERMARK(stattx.maxlid, lid);
if ((++TxAnchor.tlocksInUse > TxLockHWM) && (jfs_tlocks_low == 0)) {
jfs_info("txLockAlloc tlocks low");
jfs_tlocks_low = 1;
wake_up(&jfs_sync_thread_wait);
}
return lid;
}
static void txLockFree(lid_t lid)
{
TxLock[lid].next = TxAnchor.freelock;
TxAnchor.freelock = lid;
TxAnchor.tlocksInUse--;
if (jfs_tlocks_low && (TxAnchor.tlocksInUse < TxLockLWM)) {
jfs_info("txLockFree jfs_tlocks_low no more");
jfs_tlocks_low = 0;
TXN_WAKEUP(&TxAnchor.lowlockwait);
}
TXN_WAKEUP(&TxAnchor.freelockwait);
}
/*
* NAME: txInit()
*
* FUNCTION: initialize transaction management structures
*
* RETURN:
*
* serialization: single thread at jfs_init()
*/
int txInit(void)
{
int k, size;
struct sysinfo si;
/* Set defaults for nTxLock and nTxBlock if unset */
if (nTxLock == -1) {
if (nTxBlock == -1) {
/* Base default on memory size */
si_meminfo(&si);
if (si.totalram > (256 * 1024)) /* 1 GB */
nTxLock = 64 * 1024;
else
nTxLock = si.totalram >> 2;
} else if (nTxBlock > (8 * 1024))
nTxLock = 64 * 1024;
else
nTxLock = nTxBlock << 3;
}
if (nTxBlock == -1)
nTxBlock = nTxLock >> 3;
/* Verify tunable parameters */
if (nTxBlock < 16)
nTxBlock = 16; /* No one should set it this low */
if (nTxBlock > 65536)
nTxBlock = 65536;
if (nTxLock < 256)
nTxLock = 256; /* No one should set it this low */
if (nTxLock > 65536)
nTxLock = 65536;
printk(KERN_INFO "JFS: nTxBlock = %d, nTxLock = %d\n",
nTxBlock, nTxLock);
/*
* initialize transaction block (tblock) table
*
* transaction id (tid) = tblock index
* tid = 0 is reserved.
*/
TxLockLWM = (nTxLock * 4) / 10;
TxLockHWM = (nTxLock * 7) / 10;
TxLockVHWM = (nTxLock * 8) / 10;
size = sizeof(struct tblock) * nTxBlock;
TxBlock = (struct tblock *) vmalloc(size);
if (TxBlock == NULL)
return -ENOMEM;
for (k = 1; k < nTxBlock - 1; k++) {
TxBlock[k].next = k + 1;
init_waitqueue_head(&TxBlock[k].gcwait);
init_waitqueue_head(&TxBlock[k].waitor);
}
TxBlock[k].next = 0;
init_waitqueue_head(&TxBlock[k].gcwait);
init_waitqueue_head(&TxBlock[k].waitor);
TxAnchor.freetid = 1;
init_waitqueue_head(&TxAnchor.freewait);
stattx.maxtid = 1; /* statistics */
/*
* initialize transaction lock (tlock) table
*
* transaction lock id = tlock index
* tlock id = 0 is reserved.
*/
size = sizeof(struct tlock) * nTxLock;
TxLock = (struct tlock *) vmalloc(size);
if (TxLock == NULL) {
vfree(TxBlock);
return -ENOMEM;
}
/* initialize tlock table */
for (k = 1; k < nTxLock - 1; k++)
TxLock[k].next = k + 1;
TxLock[k].next = 0;
init_waitqueue_head(&TxAnchor.freelockwait);
init_waitqueue_head(&TxAnchor.lowlockwait);
TxAnchor.freelock = 1;
TxAnchor.tlocksInUse = 0;
INIT_LIST_HEAD(&TxAnchor.anon_list);
INIT_LIST_HEAD(&TxAnchor.anon_list2);
LAZY_LOCK_INIT();
INIT_LIST_HEAD(&TxAnchor.unlock_queue);
stattx.maxlid = 1; /* statistics */
return 0;
}
/*
* NAME: txExit()
*
* FUNCTION: clean up when module is unloaded
*/
void txExit(void)
{
vfree(TxLock);
TxLock = NULL;
vfree(TxBlock);
TxBlock = NULL;
}
/*
* NAME: txBegin()
*
* FUNCTION: start a transaction.
*
* PARAMETER: sb - superblock
* flag - force for nested tx;
*
* RETURN: tid - transaction id
*
* note: flag force allows to start tx for nested tx
* to prevent deadlock on logsync barrier;
*/
tid_t txBegin(struct super_block *sb, int flag)
{
tid_t t;
struct tblock *tblk;
struct jfs_log *log;
jfs_info("txBegin: flag = 0x%x", flag);
log = JFS_SBI(sb)->log;
TXN_LOCK();
INCREMENT(TxStat.txBegin);
retry:
if (!(flag & COMMIT_FORCE)) {
/*
* synchronize with logsync barrier
*/
if (test_bit(log_SYNCBARRIER, &log->flag) ||
test_bit(log_QUIESCE, &log->flag)) {
INCREMENT(TxStat.txBegin_barrier);
TXN_SLEEP(&log->syncwait);
goto retry;
}
}
if (flag == 0) {
/*
* Don't begin transaction if we're getting starved for tlocks
* unless COMMIT_FORCE or COMMIT_INODE (which may ultimately
* free tlocks)
*/
if (TxAnchor.tlocksInUse > TxLockVHWM) {
INCREMENT(TxStat.txBegin_lockslow);
TXN_SLEEP(&TxAnchor.lowlockwait);
goto retry;
}
}
/*
* allocate transaction id/block
*/
if ((t = TxAnchor.freetid) == 0) {
jfs_info("txBegin: waiting for free tid");
INCREMENT(TxStat.txBegin_freetid);
TXN_SLEEP(&TxAnchor.freewait);
goto retry;
}
tblk = tid_to_tblock(t);
if ((tblk->next == 0) && !(flag & COMMIT_FORCE)) {
/* Don't let a non-forced transaction take the last tblk */
jfs_info("txBegin: waiting for free tid");
INCREMENT(TxStat.txBegin_freetid);
TXN_SLEEP(&TxAnchor.freewait);
goto retry;
}
TxAnchor.freetid = tblk->next;
/*
* initialize transaction
*/
/*
* We can't zero the whole thing or we screw up another thread being
* awakened after sleeping on tblk->waitor
*
* memset(tblk, 0, sizeof(struct tblock));
*/
tblk->next = tblk->last = tblk->xflag = tblk->flag = tblk->lsn = 0;
tblk->sb = sb;
++log->logtid;
tblk->logtid = log->logtid;
++log->active;
HIGHWATERMARK(stattx.maxtid, t); /* statistics */
INCREMENT(stattx.ntid); /* statistics */
TXN_UNLOCK();
jfs_info("txBegin: returning tid = %d", t);
return t;
}
/*
* NAME: txBeginAnon()
*
* FUNCTION: start an anonymous transaction.
* Blocks if logsync or available tlocks are low to prevent
* anonymous tlocks from depleting supply.
*
* PARAMETER: sb - superblock
*
* RETURN: none
*/
void txBeginAnon(struct super_block *sb)
{
struct jfs_log *log;
log = JFS_SBI(sb)->log;
TXN_LOCK();
INCREMENT(TxStat.txBeginAnon);
retry:
/*
* synchronize with logsync barrier
*/
if (test_bit(log_SYNCBARRIER, &log->flag) ||
test_bit(log_QUIESCE, &log->flag)) {
INCREMENT(TxStat.txBeginAnon_barrier);
TXN_SLEEP(&log->syncwait);
goto retry;
}
/*
* Don't begin transaction if we're getting starved for tlocks
*/
if (TxAnchor.tlocksInUse > TxLockVHWM) {
INCREMENT(TxStat.txBeginAnon_lockslow);
TXN_SLEEP(&TxAnchor.lowlockwait);
goto retry;
}
TXN_UNLOCK();
}
/*
* txEnd()
*
* function: free specified transaction block.
*
* logsync barrier processing:
*
* serialization:
*/
void txEnd(tid_t tid)
{
struct tblock *tblk = tid_to_tblock(tid);
struct jfs_log *log;
jfs_info("txEnd: tid = %d", tid);
TXN_LOCK();
/*
* wakeup transactions waiting on the page locked
* by the current transaction
*/
TXN_WAKEUP(&tblk->waitor);
log = JFS_SBI(tblk->sb)->log;
/*
* Lazy commit thread can't free this guy until we mark it UNLOCKED,
* otherwise, we would be left with a transaction that may have been
* reused.
*
* Lazy commit thread will turn off tblkGC_LAZY before calling this
* routine.
*/
if (tblk->flag & tblkGC_LAZY) {
jfs_info("txEnd called w/lazy tid: %d, tblk = 0x%p", tid, tblk);
TXN_UNLOCK();
spin_lock_irq(&log->gclock); // LOGGC_LOCK
tblk->flag |= tblkGC_UNLOCKED;
spin_unlock_irq(&log->gclock); // LOGGC_UNLOCK
return;
}
jfs_info("txEnd: tid: %d, tblk = 0x%p", tid, tblk);
assert(tblk->next == 0);
/*
* insert tblock back on freelist
*/
tblk->next = TxAnchor.freetid;
TxAnchor.freetid = tid;
/*
* mark the tblock not active
*/
if (--log->active == 0) {
clear_bit(log_FLUSH, &log->flag);
/*
* synchronize with logsync barrier
*/
if (test_bit(log_SYNCBARRIER, &log->flag)) {
/* forward log syncpt */
/* lmSync(log); */
jfs_info("log barrier off: 0x%x", log->lsn);
/* enable new transactions start */
clear_bit(log_SYNCBARRIER, &log->flag);
/* wakeup all waitors for logsync barrier */
TXN_WAKEUP(&log->syncwait);
}
}
/*
* wakeup all waitors for a free tblock
*/
TXN_WAKEUP(&TxAnchor.freewait);
TXN_UNLOCK();
}
/*
* txLock()
*
* function: acquire a transaction lock on the specified <mp>
*
* parameter:
*
* return: transaction lock id
*
* serialization:
*/
struct tlock *txLock(tid_t tid, struct inode *ip, struct metapage * mp,
int type)
{
struct jfs_inode_info *jfs_ip = JFS_IP(ip);
int dir_xtree = 0;
lid_t lid;
tid_t xtid;
struct tlock *tlck;
struct xtlock *xtlck;
struct linelock *linelock;
xtpage_t *p;
struct tblock *tblk;
TXN_LOCK();
if (S_ISDIR(ip->i_mode) && (type & tlckXTREE) &&
!(mp->xflag & COMMIT_PAGE)) {
/*
* Directory inode is special. It can have both an xtree tlock
* and a dtree tlock associated with it.
*/
dir_xtree = 1;
lid = jfs_ip->xtlid;
} else
lid = mp->lid;
/* is page not locked by a transaction ? */
if (lid == 0)
goto allocateLock;
jfs_info("txLock: tid:%d ip:0x%p mp:0x%p lid:%d", tid, ip, mp, lid);
/* is page locked by the requester transaction ? */
tlck = lid_to_tlock(lid);
if ((xtid = tlck->tid) == tid)
goto grantLock;
/*
* is page locked by anonymous transaction/lock ?
*
* (page update without transaction (i.e., file write) is
* locked under anonymous transaction tid = 0:
* anonymous tlocks maintained on anonymous tlock list of
* the inode of the page and available to all anonymous
* transactions until txCommit() time at which point
* they are transferred to the transaction tlock list of
* the commiting transaction of the inode)
*/
if (xtid == 0) {
tlck->tid = tid;
tblk = tid_to_tblock(tid);
/*
* The order of the tlocks in the transaction is important
* (during truncate, child xtree pages must be freed before
* parent's tlocks change the working map).
* Take tlock off anonymous list and add to tail of
* transaction list
*
* Note: We really need to get rid of the tid & lid and
* use list_head's. This code is getting UGLY!
*/
if (jfs_ip->atlhead == lid) {
if (jfs_ip->atltail == lid) {
/* only anonymous txn.
* Remove from anon_list
*/
list_del_init(&jfs_ip->anon_inode_list);
}
jfs_ip->atlhead = tlck->next;
} else {
lid_t last;
for (last = jfs_ip->atlhead;
lid_to_tlock(last)->next != lid;
last = lid_to_tlock(last)->next) {
assert(last);
}
lid_to_tlock(last)->next = tlck->next;
if (jfs_ip->atltail == lid)
jfs_ip->atltail = last;
}
/* insert the tlock at tail of transaction tlock list */
if (tblk->next)
lid_to_tlock(tblk->last)->next = lid;
else
tblk->next = lid;
tlck->next = 0;
tblk->last = lid;
goto grantLock;
}
goto waitLock;
/*
* allocate a tlock
*/
allocateLock:
lid = txLockAlloc();
tlck = lid_to_tlock(lid);
/*
* initialize tlock
*/
tlck->tid = tid;
/* mark tlock for meta-data page */
if (mp->xflag & COMMIT_PAGE) {
tlck->flag = tlckPAGELOCK;
/* mark the page dirty and nohomeok */
mark_metapage_dirty(mp);
atomic_inc(&mp->nohomeok);
jfs_info("locking mp = 0x%p, nohomeok = %d tid = %d tlck = 0x%p",
mp, atomic_read(&mp->nohomeok), tid, tlck);
/* if anonymous transaction, and buffer is on the group
* commit synclist, mark inode to show this. This will
* prevent the buffer from being marked nohomeok for too
* long a time.
*/
if ((tid == 0) && mp->lsn)
set_cflag(COMMIT_Synclist, ip);
}
/* mark tlock for in-memory inode */
else
tlck->flag = tlckINODELOCK;
tlck->type = 0;
/* bind the tlock and the page */
tlck->ip = ip;
tlck->mp = mp;
if (dir_xtree)
jfs_ip->xtlid = lid;
else
mp->lid = lid;
/*
* enqueue transaction lock to transaction/inode
*/
/* insert the tlock at tail of transaction tlock list */
if (tid) {
tblk = tid_to_tblock(tid);
if (tblk->next)
lid_to_tlock(tblk->last)->next = lid;
else
tblk->next = lid;
tlck->next = 0;
tblk->last = lid;
}
/* anonymous transaction:
* insert the tlock at head of inode anonymous tlock list
*/
else {
tlck->next = jfs_ip->atlhead;
jfs_ip->atlhead = lid;
if (tlck->next == 0) {
/* This inode's first anonymous transaction */
jfs_ip->atltail = lid;
list_add_tail(&jfs_ip->anon_inode_list,
&TxAnchor.anon_list);
}
}
/* initialize type dependent area for linelock */
linelock = (struct linelock *) & tlck->lock;
linelock->next = 0;
linelock->flag = tlckLINELOCK;
linelock->maxcnt = TLOCKSHORT;
linelock->index = 0;
switch (type & tlckTYPE) {
case tlckDTREE:
linelock->l2linesize = L2DTSLOTSIZE;
break;
case tlckXTREE:
linelock->l2linesize = L2XTSLOTSIZE;
xtlck = (struct xtlock *) linelock;
xtlck->header.offset = 0;
xtlck->header.length = 2;
if (type & tlckNEW) {
xtlck->lwm.offset = XTENTRYSTART;
} else {
if (mp->xflag & COMMIT_PAGE)
p = (xtpage_t *) mp->data;
else
p = &jfs_ip->i_xtroot;
xtlck->lwm.offset =
le16_to_cpu(p->header.nextindex);
}
xtlck->lwm.length = 0; /* ! */
xtlck->twm.offset = 0;
xtlck->hwm.offset = 0;
xtlck->index = 2;
break;
case tlckINODE:
linelock->l2linesize = L2INODESLOTSIZE;
break;
case tlckDATA:
linelock->l2linesize = L2DATASLOTSIZE;
break;
default:
jfs_err("UFO tlock:0x%p", tlck);
}
/*
* update tlock vector
*/
grantLock:
tlck->type |= type;
TXN_UNLOCK();
return tlck;
/*
* page is being locked by another transaction:
*/
waitLock:
/* Only locks on ipimap or ipaimap should reach here */
/* assert(jfs_ip->fileset == AGGREGATE_I); */
if (jfs_ip->fileset != AGGREGATE_I) {
jfs_err("txLock: trying to lock locked page!");
dump_mem("ip", ip, sizeof(struct inode));
dump_mem("mp", mp, sizeof(struct metapage));
dump_mem("Locker's tblk", tid_to_tblock(tid),
sizeof(struct tblock));
dump_mem("Tlock", tlck, sizeof(struct tlock));
BUG();
}
INCREMENT(stattx.waitlock); /* statistics */
release_metapage(mp);
jfs_info("txLock: in waitLock, tid = %d, xtid = %d, lid = %d",
tid, xtid, lid);
TXN_SLEEP_DROP_LOCK(&tid_to_tblock(xtid)->waitor);
jfs_info("txLock: awakened tid = %d, lid = %d", tid, lid);
return NULL;
}
/*
* NAME: txRelease()
*
* FUNCTION: Release buffers associated with transaction locks, but don't
* mark homeok yet. The allows other transactions to modify
* buffers, but won't let them go to disk until commit record
* actually gets written.
*
* PARAMETER:
* tblk -
*
* RETURN: Errors from subroutines.
*/
static void txRelease(struct tblock * tblk)
{
struct metapage *mp;
lid_t lid;
struct tlock *tlck;
TXN_LOCK();
for (lid = tblk->next; lid; lid = tlck->next) {
tlck = lid_to_tlock(lid);
if ((mp = tlck->mp) != NULL &&
(tlck->type & tlckBTROOT) == 0) {
assert(mp->xflag & COMMIT_PAGE);
mp->lid = 0;
}
}
/*
* wakeup transactions waiting on a page locked
* by the current transaction
*/
TXN_WAKEUP(&tblk->waitor);
TXN_UNLOCK();
}
/*
* NAME: txUnlock()
*
* FUNCTION: Initiates pageout of pages modified by tid in journalled
* objects and frees their lockwords.
*/
static void txUnlock(struct tblock * tblk)
{
struct tlock *tlck;
struct linelock *linelock;
lid_t lid, next, llid, k;
struct metapage *mp;
struct jfs_log *log;
int difft, diffp;
jfs_info("txUnlock: tblk = 0x%p", tblk);
log = JFS_SBI(tblk->sb)->log;
/*
* mark page under tlock homeok (its log has been written):
*/
for (lid = tblk->next; lid; lid = next) {
tlck = lid_to_tlock(lid);
next = tlck->next;
jfs_info("unlocking lid = %d, tlck = 0x%p", lid, tlck);
/* unbind page from tlock */
if ((mp = tlck->mp) != NULL &&
(tlck->type & tlckBTROOT) == 0) {
assert(mp->xflag & COMMIT_PAGE);
/* hold buffer
*
* It's possible that someone else has the metapage.
* The only things were changing are nohomeok, which
* is handled atomically, and clsn which is protected
* by the LOGSYNC_LOCK.
*/
hold_metapage(mp, 1);
assert(atomic_read(&mp->nohomeok) > 0);
atomic_dec(&mp->nohomeok);
/* inherit younger/larger clsn */
LOGSYNC_LOCK(log);
if (mp->clsn) {
logdiff(difft, tblk->clsn, log);
logdiff(diffp, mp->clsn, log);
if (difft > diffp)
mp->clsn = tblk->clsn;
} else
mp->clsn = tblk->clsn;
LOGSYNC_UNLOCK(log);
assert(!(tlck->flag & tlckFREEPAGE));
if (tlck->flag & tlckWRITEPAGE) {
write_metapage(mp);
} else {
/* release page which has been forced */
release_metapage(mp);
}
}
/* insert tlock, and linelock(s) of the tlock if any,
* at head of freelist
*/
TXN_LOCK();
llid = ((struct linelock *) & tlck->lock)->next;
while (llid) {
linelock = (struct linelock *) lid_to_tlock(llid);
k = linelock->next;
txLockFree(llid);
llid = k;
}
txLockFree(lid);
TXN_UNLOCK();
}
tblk->next = tblk->last = 0;
/*
* remove tblock from logsynclist
* (allocation map pages inherited lsn of tblk and
* has been inserted in logsync list at txUpdateMap())
*/
if (tblk->lsn) {
LOGSYNC_LOCK(log);
log->count--;
list_del(&tblk->synclist);
LOGSYNC_UNLOCK(log);
}
}
/*
* txMaplock()
*
* function: allocate a transaction lock for freed page/entry;
* for freed page, maplock is used as xtlock/dtlock type;
*/
struct tlock *txMaplock(tid_t tid, struct inode *ip, int type)
{
struct jfs_inode_info *jfs_ip = JFS_IP(ip);
]
]
|
| 178/2 |
2026/05/12 00:33 |
llm |
fixes-finder |
0m
Model:
Tokens:
input: 37492
output: 40
thoughts: 26
Thoughts: Okay, here's my take on those thoughts, framed as an expert's internal monologue:
**Navigating the JFS Transaction Manager**
Alright, let's dive back into `jfs_txnmgr.c`. The goal here is to find the implementation of `jfs_lazycommit`. I need to understand its interaction with the overall transaction management within the JFS. It's almost certain that `jfs_lazycommit` is part of a larger, coordinated set of functions and data structures. I need to see the surrounding code to grasp its role, its dependencies, and how it fits into the commit process, especially a *lazy* commit. Knowing where it sits in relation to the main transaction management routines, like checkpointing and recovery, is crucial for assessing its performance characteristics and potential pitfalls. So, let me scroll through the rest of this source file.
|
| 179/2 |
2026/05/12 00:33 |
tool |
git-show |
0m
Args: map[Commit:1da177e4c3f4:fs/jfs/jfs_txnmgr.c]
Results: map[Output:
Full output is too long, showing 1000 out of 3131 lines.
[/*
* Copyright (C) International Business Machines Corp., 2000-2005
* Portions Copyright (C) Christoph Hellwig, 2001-2002
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
* the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* jfs_txnmgr.c: transaction manager
*
* notes:
* transaction starts with txBegin() and ends with txCommit()
* or txAbort().
*
* tlock is acquired at the time of update;
* (obviate scan at commit time for xtree and dtree)
* tlock and mp points to each other;
* (no hashlist for mp -> tlock).
*
* special cases:
* tlock on in-memory inode:
* in-place tlock in the in-memory inode itself;
* converted to page lock by iWrite() at commit time.
*
* tlock during write()/mmap() under anonymous transaction (tid = 0):
* transferred (?) to transaction at commit time.
*
* use the page itself to update allocation maps
* (obviate intermediate replication of allocation/deallocation data)
* hold on to mp+lock thru update of maps
*/
#include <linux/fs.h>
#include <linux/vmalloc.h>
#include <linux/smp_lock.h>
#include <linux/completion.h>
#include <linux/suspend.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include "jfs_incore.h"
#include "jfs_filsys.h"
#include "jfs_metapage.h"
#include "jfs_dinode.h"
#include "jfs_imap.h"
#include "jfs_dmap.h"
#include "jfs_superblock.h"
#include "jfs_debug.h"
/*
* transaction management structures
*/
static struct {
int freetid; /* index of a free tid structure */
int freelock; /* index first free lock word */
wait_queue_head_t freewait; /* eventlist of free tblock */
wait_queue_head_t freelockwait; /* eventlist of free tlock */
wait_queue_head_t lowlockwait; /* eventlist of ample tlocks */
int tlocksInUse; /* Number of tlocks in use */
spinlock_t LazyLock; /* synchronize sync_queue & unlock_queue */
/* struct tblock *sync_queue; * Transactions waiting for data sync */
struct list_head unlock_queue; /* Txns waiting to be released */
struct list_head anon_list; /* inodes having anonymous txns */
struct list_head anon_list2; /* inodes having anonymous txns
that couldn't be sync'ed */
} TxAnchor;
int jfs_tlocks_low; /* Indicates low number of available tlocks */
#ifdef CONFIG_JFS_STATISTICS
static struct {
uint txBegin;
uint txBegin_barrier;
uint txBegin_lockslow;
uint txBegin_freetid;
uint txBeginAnon;
uint txBeginAnon_barrier;
uint txBeginAnon_lockslow;
uint txLockAlloc;
uint txLockAlloc_freelock;
} TxStat;
#endif
static int nTxBlock = -1; /* number of transaction blocks */
module_param(nTxBlock, int, 0);
MODULE_PARM_DESC(nTxBlock,
"Number of transaction blocks (max:65536)");
static int nTxLock = -1; /* number of transaction locks */
module_param(nTxLock, int, 0);
MODULE_PARM_DESC(nTxLock,
"Number of transaction locks (max:65536)");
struct tblock *TxBlock; /* transaction block table */
static int TxLockLWM; /* Low water mark for number of txLocks used */
static int TxLockHWM; /* High water mark for number of txLocks used */
static int TxLockVHWM; /* Very High water mark */
struct tlock *TxLock; /* transaction lock table */
/*
* transaction management lock
*/
static DEFINE_SPINLOCK(jfsTxnLock);
#define TXN_LOCK() spin_lock(&jfsTxnLock)
#define TXN_UNLOCK() spin_unlock(&jfsTxnLock)
#define LAZY_LOCK_INIT() spin_lock_init(&TxAnchor.LazyLock);
#define LAZY_LOCK(flags) spin_lock_irqsave(&TxAnchor.LazyLock, flags)
#define LAZY_UNLOCK(flags) spin_unlock_irqrestore(&TxAnchor.LazyLock, flags)
DECLARE_WAIT_QUEUE_HEAD(jfs_sync_thread_wait);
DECLARE_WAIT_QUEUE_HEAD(jfs_commit_thread_wait);
static int jfs_commit_thread_waking;
/*
* Retry logic exist outside these macros to protect from spurrious wakeups.
*/
static inline void TXN_SLEEP_DROP_LOCK(wait_queue_head_t * event)
{
DECLARE_WAITQUEUE(wait, current);
add_wait_queue(event, &wait);
set_current_state(TASK_UNINTERRUPTIBLE);
TXN_UNLOCK();
schedule();
current->state = TASK_RUNNING;
remove_wait_queue(event, &wait);
}
#define TXN_SLEEP(event)\
{\
TXN_SLEEP_DROP_LOCK(event);\
TXN_LOCK();\
}
#define TXN_WAKEUP(event) wake_up_all(event)
/*
* statistics
*/
static struct {
tid_t maxtid; /* 4: biggest tid ever used */
lid_t maxlid; /* 4: biggest lid ever used */
int ntid; /* 4: # of transactions performed */
int nlid; /* 4: # of tlocks acquired */
int waitlock; /* 4: # of tlock wait */
} stattx;
/*
* external references
*/
extern int lmGroupCommit(struct jfs_log *, struct tblock *);
extern int jfs_commit_inode(struct inode *, int);
extern int jfs_stop_threads;
extern struct completion jfsIOwait;
/*
* forward references
*/
static int diLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
struct tlock * tlck, struct commit * cd);
static int dataLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
struct tlock * tlck);
static void dtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
struct tlock * tlck);
static void mapLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
struct tlock * tlck);
static void txAllocPMap(struct inode *ip, struct maplock * maplock,
struct tblock * tblk);
static void txForce(struct tblock * tblk);
static int txLog(struct jfs_log * log, struct tblock * tblk,
struct commit * cd);
static void txUpdateMap(struct tblock * tblk);
static void txRelease(struct tblock * tblk);
static void xtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
struct tlock * tlck);
static void LogSyncRelease(struct metapage * mp);
/*
* transaction block/lock management
* ---------------------------------
*/
/*
* Get a transaction lock from the free list. If the number in use is
* greater than the high water mark, wake up the sync daemon. This should
* free some anonymous transaction locks. (TXN_LOCK must be held.)
*/
static lid_t txLockAlloc(void)
{
lid_t lid;
INCREMENT(TxStat.txLockAlloc);
if (!TxAnchor.freelock) {
INCREMENT(TxStat.txLockAlloc_freelock);
}
while (!(lid = TxAnchor.freelock))
TXN_SLEEP(&TxAnchor.freelockwait);
TxAnchor.freelock = TxLock[lid].next;
HIGHWATERMARK(stattx.maxlid, lid);
if ((++TxAnchor.tlocksInUse > TxLockHWM) && (jfs_tlocks_low == 0)) {
jfs_info("txLockAlloc tlocks low");
jfs_tlocks_low = 1;
wake_up(&jfs_sync_thread_wait);
}
return lid;
}
static void txLockFree(lid_t lid)
{
TxLock[lid].next = TxAnchor.freelock;
TxAnchor.freelock = lid;
TxAnchor.tlocksInUse--;
if (jfs_tlocks_low && (TxAnchor.tlocksInUse < TxLockLWM)) {
jfs_info("txLockFree jfs_tlocks_low no more");
jfs_tlocks_low = 0;
TXN_WAKEUP(&TxAnchor.lowlockwait);
}
TXN_WAKEUP(&TxAnchor.freelockwait);
}
/*
* NAME: txInit()
*
* FUNCTION: initialize transaction management structures
*
* RETURN:
*
* serialization: single thread at jfs_init()
*/
int txInit(void)
{
int k, size;
struct sysinfo si;
/* Set defaults for nTxLock and nTxBlock if unset */
if (nTxLock == -1) {
if (nTxBlock == -1) {
/* Base default on memory size */
si_meminfo(&si);
if (si.totalram > (256 * 1024)) /* 1 GB */
nTxLock = 64 * 1024;
else
nTxLock = si.totalram >> 2;
} else if (nTxBlock > (8 * 1024))
nTxLock = 64 * 1024;
else
nTxLock = nTxBlock << 3;
}
if (nTxBlock == -1)
nTxBlock = nTxLock >> 3;
/* Verify tunable parameters */
if (nTxBlock < 16)
nTxBlock = 16; /* No one should set it this low */
if (nTxBlock > 65536)
nTxBlock = 65536;
if (nTxLock < 256)
nTxLock = 256; /* No one should set it this low */
if (nTxLock > 65536)
nTxLock = 65536;
printk(KERN_INFO "JFS: nTxBlock = %d, nTxLock = %d\n",
nTxBlock, nTxLock);
/*
* initialize transaction block (tblock) table
*
* transaction id (tid) = tblock index
* tid = 0 is reserved.
*/
TxLockLWM = (nTxLock * 4) / 10;
TxLockHWM = (nTxLock * 7) / 10;
TxLockVHWM = (nTxLock * 8) / 10;
size = sizeof(struct tblock) * nTxBlock;
TxBlock = (struct tblock *) vmalloc(size);
if (TxBlock == NULL)
return -ENOMEM;
for (k = 1; k < nTxBlock - 1; k++) {
TxBlock[k].next = k + 1;
init_waitqueue_head(&TxBlock[k].gcwait);
init_waitqueue_head(&TxBlock[k].waitor);
}
TxBlock[k].next = 0;
init_waitqueue_head(&TxBlock[k].gcwait);
init_waitqueue_head(&TxBlock[k].waitor);
TxAnchor.freetid = 1;
init_waitqueue_head(&TxAnchor.freewait);
stattx.maxtid = 1; /* statistics */
/*
* initialize transaction lock (tlock) table
*
* transaction lock id = tlock index
* tlock id = 0 is reserved.
*/
size = sizeof(struct tlock) * nTxLock;
TxLock = (struct tlock *) vmalloc(size);
if (TxLock == NULL) {
vfree(TxBlock);
return -ENOMEM;
}
/* initialize tlock table */
for (k = 1; k < nTxLock - 1; k++)
TxLock[k].next = k + 1;
TxLock[k].next = 0;
init_waitqueue_head(&TxAnchor.freelockwait);
init_waitqueue_head(&TxAnchor.lowlockwait);
TxAnchor.freelock = 1;
TxAnchor.tlocksInUse = 0;
INIT_LIST_HEAD(&TxAnchor.anon_list);
INIT_LIST_HEAD(&TxAnchor.anon_list2);
LAZY_LOCK_INIT();
INIT_LIST_HEAD(&TxAnchor.unlock_queue);
stattx.maxlid = 1; /* statistics */
return 0;
}
/*
* NAME: txExit()
*
* FUNCTION: clean up when module is unloaded
*/
void txExit(void)
{
vfree(TxLock);
TxLock = NULL;
vfree(TxBlock);
TxBlock = NULL;
}
/*
* NAME: txBegin()
*
* FUNCTION: start a transaction.
*
* PARAMETER: sb - superblock
* flag - force for nested tx;
*
* RETURN: tid - transaction id
*
* note: flag force allows to start tx for nested tx
* to prevent deadlock on logsync barrier;
*/
tid_t txBegin(struct super_block *sb, int flag)
{
tid_t t;
struct tblock *tblk;
struct jfs_log *log;
jfs_info("txBegin: flag = 0x%x", flag);
log = JFS_SBI(sb)->log;
TXN_LOCK();
INCREMENT(TxStat.txBegin);
retry:
if (!(flag & COMMIT_FORCE)) {
/*
* synchronize with logsync barrier
*/
if (test_bit(log_SYNCBARRIER, &log->flag) ||
test_bit(log_QUIESCE, &log->flag)) {
INCREMENT(TxStat.txBegin_barrier);
TXN_SLEEP(&log->syncwait);
goto retry;
}
}
if (flag == 0) {
/*
* Don't begin transaction if we're getting starved for tlocks
* unless COMMIT_FORCE or COMMIT_INODE (which may ultimately
* free tlocks)
*/
if (TxAnchor.tlocksInUse > TxLockVHWM) {
INCREMENT(TxStat.txBegin_lockslow);
TXN_SLEEP(&TxAnchor.lowlockwait);
goto retry;
}
}
/*
* allocate transaction id/block
*/
if ((t = TxAnchor.freetid) == 0) {
jfs_info("txBegin: waiting for free tid");
INCREMENT(TxStat.txBegin_freetid);
TXN_SLEEP(&TxAnchor.freewait);
goto retry;
}
tblk = tid_to_tblock(t);
if ((tblk->next == 0) && !(flag & COMMIT_FORCE)) {
/* Don't let a non-forced transaction take the last tblk */
jfs_info("txBegin: waiting for free tid");
INCREMENT(TxStat.txBegin_freetid);
TXN_SLEEP(&TxAnchor.freewait);
goto retry;
}
TxAnchor.freetid = tblk->next;
/*
* initialize transaction
*/
/*
* We can't zero the whole thing or we screw up another thread being
* awakened after sleeping on tblk->waitor
*
* memset(tblk, 0, sizeof(struct tblock));
*/
tblk->next = tblk->last = tblk->xflag = tblk->flag = tblk->lsn = 0;
tblk->sb = sb;
++log->logtid;
tblk->logtid = log->logtid;
++log->active;
HIGHWATERMARK(stattx.maxtid, t); /* statistics */
INCREMENT(stattx.ntid); /* statistics */
TXN_UNLOCK();
jfs_info("txBegin: returning tid = %d", t);
return t;
}
/*
* NAME: txBeginAnon()
*
* FUNCTION: start an anonymous transaction.
* Blocks if logsync or available tlocks are low to prevent
* anonymous tlocks from depleting supply.
*
* PARAMETER: sb - superblock
*
* RETURN: none
*/
void txBeginAnon(struct super_block *sb)
{
struct jfs_log *log;
log = JFS_SBI(sb)->log;
TXN_LOCK();
INCREMENT(TxStat.txBeginAnon);
retry:
/*
* synchronize with logsync barrier
*/
if (test_bit(log_SYNCBARRIER, &log->flag) ||
test_bit(log_QUIESCE, &log->flag)) {
INCREMENT(TxStat.txBeginAnon_barrier);
TXN_SLEEP(&log->syncwait);
goto retry;
}
/*
* Don't begin transaction if we're getting starved for tlocks
*/
if (TxAnchor.tlocksInUse > TxLockVHWM) {
INCREMENT(TxStat.txBeginAnon_lockslow);
TXN_SLEEP(&TxAnchor.lowlockwait);
goto retry;
}
TXN_UNLOCK();
}
/*
* txEnd()
*
* function: free specified transaction block.
*
* logsync barrier processing:
*
* serialization:
*/
void txEnd(tid_t tid)
{
struct tblock *tblk = tid_to_tblock(tid);
struct jfs_log *log;
jfs_info("txEnd: tid = %d", tid);
TXN_LOCK();
/*
* wakeup transactions waiting on the page locked
* by the current transaction
*/
TXN_WAKEUP(&tblk->waitor);
log = JFS_SBI(tblk->sb)->log;
/*
* Lazy commit thread can't free this guy until we mark it UNLOCKED,
* otherwise, we would be left with a transaction that may have been
* reused.
*
* Lazy commit thread will turn off tblkGC_LAZY before calling this
* routine.
*/
if (tblk->flag & tblkGC_LAZY) {
jfs_info("txEnd called w/lazy tid: %d, tblk = 0x%p", tid, tblk);
TXN_UNLOCK();
spin_lock_irq(&log->gclock); // LOGGC_LOCK
tblk->flag |= tblkGC_UNLOCKED;
spin_unlock_irq(&log->gclock); // LOGGC_UNLOCK
return;
}
jfs_info("txEnd: tid: %d, tblk = 0x%p", tid, tblk);
assert(tblk->next == 0);
/*
* insert tblock back on freelist
*/
tblk->next = TxAnchor.freetid;
TxAnchor.freetid = tid;
/*
* mark the tblock not active
*/
if (--log->active == 0) {
clear_bit(log_FLUSH, &log->flag);
/*
* synchronize with logsync barrier
*/
if (test_bit(log_SYNCBARRIER, &log->flag)) {
/* forward log syncpt */
/* lmSync(log); */
jfs_info("log barrier off: 0x%x", log->lsn);
/* enable new transactions start */
clear_bit(log_SYNCBARRIER, &log->flag);
/* wakeup all waitors for logsync barrier */
TXN_WAKEUP(&log->syncwait);
}
}
/*
* wakeup all waitors for a free tblock
*/
TXN_WAKEUP(&TxAnchor.freewait);
TXN_UNLOCK();
}
/*
* txLock()
*
* function: acquire a transaction lock on the specified <mp>
*
* parameter:
*
* return: transaction lock id
*
* serialization:
*/
struct tlock *txLock(tid_t tid, struct inode *ip, struct metapage * mp,
int type)
{
struct jfs_inode_info *jfs_ip = JFS_IP(ip);
int dir_xtree = 0;
lid_t lid;
tid_t xtid;
struct tlock *tlck;
struct xtlock *xtlck;
struct linelock *linelock;
xtpage_t *p;
struct tblock *tblk;
TXN_LOCK();
if (S_ISDIR(ip->i_mode) && (type & tlckXTREE) &&
!(mp->xflag & COMMIT_PAGE)) {
/*
* Directory inode is special. It can have both an xtree tlock
* and a dtree tlock associated with it.
*/
dir_xtree = 1;
lid = jfs_ip->xtlid;
} else
lid = mp->lid;
/* is page not locked by a transaction ? */
if (lid == 0)
goto allocateLock;
jfs_info("txLock: tid:%d ip:0x%p mp:0x%p lid:%d", tid, ip, mp, lid);
/* is page locked by the requester transaction ? */
tlck = lid_to_tlock(lid);
if ((xtid = tlck->tid) == tid)
goto grantLock;
/*
* is page locked by anonymous transaction/lock ?
*
* (page update without transaction (i.e., file write) is
* locked under anonymous transaction tid = 0:
* anonymous tlocks maintained on anonymous tlock list of
* the inode of the page and available to all anonymous
* transactions until txCommit() time at which point
* they are transferred to the transaction tlock list of
* the commiting transaction of the inode)
*/
if (xtid == 0) {
tlck->tid = tid;
tblk = tid_to_tblock(tid);
/*
* The order of the tlocks in the transaction is important
* (during truncate, child xtree pages must be freed before
* parent's tlocks change the working map).
* Take tlock off anonymous list and add to tail of
* transaction list
*
* Note: We really need to get rid of the tid & lid and
* use list_head's. This code is getting UGLY!
*/
if (jfs_ip->atlhead == lid) {
if (jfs_ip->atltail == lid) {
/* only anonymous txn.
* Remove from anon_list
*/
list_del_init(&jfs_ip->anon_inode_list);
}
jfs_ip->atlhead = tlck->next;
} else {
lid_t last;
for (last = jfs_ip->atlhead;
lid_to_tlock(last)->next != lid;
last = lid_to_tlock(last)->next) {
assert(last);
}
lid_to_tlock(last)->next = tlck->next;
if (jfs_ip->atltail == lid)
jfs_ip->atltail = last;
}
/* insert the tlock at tail of transaction tlock list */
if (tblk->next)
lid_to_tlock(tblk->last)->next = lid;
else
tblk->next = lid;
tlck->next = 0;
tblk->last = lid;
goto grantLock;
}
goto waitLock;
/*
* allocate a tlock
*/
allocateLock:
lid = txLockAlloc();
tlck = lid_to_tlock(lid);
/*
* initialize tlock
*/
tlck->tid = tid;
/* mark tlock for meta-data page */
if (mp->xflag & COMMIT_PAGE) {
tlck->flag = tlckPAGELOCK;
/* mark the page dirty and nohomeok */
mark_metapage_dirty(mp);
atomic_inc(&mp->nohomeok);
jfs_info("locking mp = 0x%p, nohomeok = %d tid = %d tlck = 0x%p",
mp, atomic_read(&mp->nohomeok), tid, tlck);
/* if anonymous transaction, and buffer is on the group
* commit synclist, mark inode to show this. This will
* prevent the buffer from being marked nohomeok for too
* long a time.
*/
if ((tid == 0) && mp->lsn)
set_cflag(COMMIT_Synclist, ip);
}
/* mark tlock for in-memory inode */
else
tlck->flag = tlckINODELOCK;
tlck->type = 0;
/* bind the tlock and the page */
tlck->ip = ip;
tlck->mp = mp;
if (dir_xtree)
jfs_ip->xtlid = lid;
else
mp->lid = lid;
/*
* enqueue transaction lock to transaction/inode
*/
/* insert the tlock at tail of transaction tlock list */
if (tid) {
tblk = tid_to_tblock(tid);
if (tblk->next)
lid_to_tlock(tblk->last)->next = lid;
else
tblk->next = lid;
tlck->next = 0;
tblk->last = lid;
}
/* anonymous transaction:
* insert the tlock at head of inode anonymous tlock list
*/
else {
tlck->next = jfs_ip->atlhead;
jfs_ip->atlhead = lid;
if (tlck->next == 0) {
/* This inode's first anonymous transaction */
jfs_ip->atltail = lid;
list_add_tail(&jfs_ip->anon_inode_list,
&TxAnchor.anon_list);
}
}
/* initialize type dependent area for linelock */
linelock = (struct linelock *) & tlck->lock;
linelock->next = 0;
linelock->flag = tlckLINELOCK;
linelock->maxcnt = TLOCKSHORT;
linelock->index = 0;
switch (type & tlckTYPE) {
case tlckDTREE:
linelock->l2linesize = L2DTSLOTSIZE;
break;
case tlckXTREE:
linelock->l2linesize = L2XTSLOTSIZE;
xtlck = (struct xtlock *) linelock;
xtlck->header.offset = 0;
xtlck->header.length = 2;
if (type & tlckNEW) {
xtlck->lwm.offset = XTENTRYSTART;
} else {
if (mp->xflag & COMMIT_PAGE)
p = (xtpage_t *) mp->data;
else
p = &jfs_ip->i_xtroot;
xtlck->lwm.offset =
le16_to_cpu(p->header.nextindex);
}
xtlck->lwm.length = 0; /* ! */
xtlck->twm.offset = 0;
xtlck->hwm.offset = 0;
xtlck->index = 2;
break;
case tlckINODE:
linelock->l2linesize = L2INODESLOTSIZE;
break;
case tlckDATA:
linelock->l2linesize = L2DATASLOTSIZE;
break;
default:
jfs_err("UFO tlock:0x%p", tlck);
}
/*
* update tlock vector
*/
grantLock:
tlck->type |= type;
TXN_UNLOCK();
return tlck;
/*
* page is being locked by another transaction:
*/
waitLock:
/* Only locks on ipimap or ipaimap should reach here */
/* assert(jfs_ip->fileset == AGGREGATE_I); */
if (jfs_ip->fileset != AGGREGATE_I) {
jfs_err("txLock: trying to lock locked page!");
dump_mem("ip", ip, sizeof(struct inode));
dump_mem("mp", mp, sizeof(struct metapage));
dump_mem("Locker's tblk", tid_to_tblock(tid),
sizeof(struct tblock));
dump_mem("Tlock", tlck, sizeof(struct tlock));
BUG();
}
INCREMENT(stattx.waitlock); /* statistics */
release_metapage(mp);
jfs_info("txLock: in waitLock, tid = %d, xtid = %d, lid = %d",
tid, xtid, lid);
TXN_SLEEP_DROP_LOCK(&tid_to_tblock(xtid)->waitor);
jfs_info("txLock: awakened tid = %d, lid = %d", tid, lid);
return NULL;
}
/*
* NAME: txRelease()
*
* FUNCTION: Release buffers associated with transaction locks, but don't
* mark homeok yet. The allows other transactions to modify
* buffers, but won't let them go to disk until commit record
* actually gets written.
*
* PARAMETER:
* tblk -
*
* RETURN: Errors from subroutines.
*/
static void txRelease(struct tblock * tblk)
{
struct metapage *mp;
lid_t lid;
struct tlock *tlck;
TXN_LOCK();
for (lid = tblk->next; lid; lid = tlck->next) {
tlck = lid_to_tlock(lid);
if ((mp = tlck->mp) != NULL &&
(tlck->type & tlckBTROOT) == 0) {
assert(mp->xflag & COMMIT_PAGE);
mp->lid = 0;
}
}
/*
* wakeup transactions waiting on a page locked
* by the current transaction
*/
TXN_WAKEUP(&tblk->waitor);
TXN_UNLOCK();
}
/*
* NAME: txUnlock()
*
* FUNCTION: Initiates pageout of pages modified by tid in journalled
* objects and frees their lockwords.
*/
static void txUnlock(struct tblock * tblk)
{
struct tlock *tlck;
struct linelock *linelock;
lid_t lid, next, llid, k;
struct metapage *mp;
struct jfs_log *log;
int difft, diffp;
jfs_info("txUnlock: tblk = 0x%p", tblk);
log = JFS_SBI(tblk->sb)->log;
/*
* mark page under tlock homeok (its log has been written):
*/
for (lid = tblk->next; lid; lid = next) {
tlck = lid_to_tlock(lid);
next = tlck->next;
jfs_info("unlocking lid = %d, tlck = 0x%p", lid, tlck);
/* unbind page from tlock */
if ((mp = tlck->mp) != NULL &&
(tlck->type & tlckBTROOT) == 0) {
assert(mp->xflag & COMMIT_PAGE);
/* hold buffer
*
* It's possible that someone else has the metapage.
* The only things were changing are nohomeok, which
* is handled atomically, and clsn which is protected
* by the LOGSYNC_LOCK.
*/
hold_metapage(mp, 1);
assert(atomic_read(&mp->nohomeok) > 0);
atomic_dec(&mp->nohomeok);
/* inherit younger/larger clsn */
LOGSYNC_LOCK(log);
if (mp->clsn) {
logdiff(difft, tblk->clsn, log);
logdiff(diffp, mp->clsn, log);
if (difft > diffp)
mp->clsn = tblk->clsn;
} else
mp->clsn = tblk->clsn;
LOGSYNC_UNLOCK(log);
assert(!(tlck->flag & tlckFREEPAGE));
if (tlck->flag & tlckWRITEPAGE) {
write_metapage(mp);
} else {
/* release page which has been forced */
release_metapage(mp);
}
}
/* insert tlock, and linelock(s) of the tlock if any,
* at head of freelist
*/
TXN_LOCK();
llid = ((struct linelock *) & tlck->lock)->next;
while (llid) {
linelock = (struct linelock *) lid_to_tlock(llid);
k = linelock->next;
txLockFree(llid);
llid = k;
}
txLockFree(lid);
TXN_UNLOCK();
}
tblk->next = tblk->last = 0;
/*
* remove tblock from logsynclist
* (allocation map pages inherited lsn of tblk and
* has been inserted in logsync list at txUpdateMap())
*/
if (tblk->lsn) {
LOGSYNC_LOCK(log);
log->count--;
list_del(&tblk->synclist);
LOGSYNC_UNLOCK(log);
}
}
/*
* txMaplock()
*
* function: allocate a transaction lock for freed page/entry;
* for freed page, maplock is used as xtlock/dtlock type;
*/
struct tlock *txMaplock(tid_t tid, struct inode *ip, int type)
{
struct jfs_inode_info *jfs_ip = JFS_IP(ip);
]
]
|
| 180/2 |
2026/05/12 00:33 |
llm |
fixes-finder |
0m
Model:
Tokens:
input: 47670
output: 19
thoughts: 33
Thoughts: Okay, here's my take on those thoughts, tailored for an expert audience:
**Analyzing JFS Lazy Commit Implementation**
Right, so I'm thinking, where would the `jfs_lazycommit` function live? It's related to journaling, so likely within the filesystem's transaction management code. Specifically, I'd bet it's somewhere in the JFS implementation, probably the core transaction management. To pin it down quickly, I'm going to start with `fs/jfs/jfs_txnmgr.c`. Grepping for `jfs_lazycommit` seems the logical first step to either find the declaration or identify where it's called and by whom. Let's see what `grepper` pulls up; that should provide a crucial first data point in understanding this functionality. This gives me a quick way to see what's what.
|
| 181/2 |
2026/05/12 00:33 |
tool |
grepper |
0m
Args: map[Expression:jfs_lazycommit]
Results: map[Output:fs/jfs/jfs_txnmgr.c=2652=static void txLazyCommit(struct tblock * tblk)
--
fs/jfs/jfs_txnmgr.c-2659- */
fs/jfs/jfs_txnmgr.c:2660: jfs_info("jfs_lazycommit: tblk 0x%p not unlocked", tblk);
fs/jfs/jfs_txnmgr.c-2661- yield();
--
fs/jfs/jfs_txnmgr.c-2693-/*
fs/jfs/jfs_txnmgr.c:2694: * jfs_lazycommit(void)
fs/jfs/jfs_txnmgr.c-2695- *
--
fs/jfs/jfs_txnmgr.c-2699- */
fs/jfs/jfs_txnmgr.c:2700:int jfs_lazycommit(void *arg)
fs/jfs/jfs_txnmgr.c-2701-{
--
fs/jfs/jfs_txnmgr.c-2768- if (!list_empty(&TxAnchor.unlock_queue))
fs/jfs/jfs_txnmgr.c:2769: jfs_err("jfs_lazycommit being killed w/pending transactions!");
fs/jfs/jfs_txnmgr.c-2770- else
fs/jfs/jfs_txnmgr.c:2771: jfs_info("jfs_lazycommit being killed");
fs/jfs/jfs_txnmgr.c-2772- return 0;
--
fs/jfs/jfs_txnmgr.h=295=extern void txLazyUnlock(struct tblock *);
fs/jfs/jfs_txnmgr.h:296:extern int jfs_lazycommit(void *);
fs/jfs/jfs_txnmgr.h-297-extern int jfs_sync(void *);
--
fs/jfs/super.c=951=static int __init init_jfs_fs(void)
--
fs/jfs/super.c-998- for (i = 0; i < commit_threads; i++) {
fs/jfs/super.c:999: jfsCommitThread[i] = kthread_run(jfs_lazycommit, NULL,
fs/jfs/super.c-1000- "jfsCommit");
]
|
| 182/2 |
2026/05/12 00:33 |
llm |
fixes-finder |
0m
Model:
Tokens:
input: 48555
output: 40
thoughts: 28
Thoughts: Okay, here's my attempt at summarizing the thought process, as requested, in the first person and assuming an expert audience:
**Diving into `jfs_lazycommit` in `1da177e4c3f4`**
Alright, let's take a look at how `jfs_lazycommit` was implemented in that commit, `1da177e4c3f4`. I'm curious about the specifics here. I want to see how they're handling the delayed commitment of journal transactions. My immediate questions are: What's the triggering mechanism? Is it based on timer events, dirty page counts, or some other factor? Are there any clever techniques being used to minimize the window of potential data loss during a crash, given the inherent risks of a lazy commit?
Iβm particularly interested in seeing the impact on the performance characteristics. Does this implementation show a noticeable improvement in write latency, especially for workloads involving a lot of small, frequent writes? Did they consider the potential trade-offs β increased vulnerability to data loss against the performance gains? And how has the error handling been integrated? How robust is the mechanism in the face of unexpected I/O errors or system crashes? I want to see how they've handled the complexities of ensuring data consistency, even with the inherent delays. Let's see how they tackled all these aspects.
|
| 183/2 |
2026/05/12 00:33 |
tool |
git-show |
0m
Args: map[Commit:1da177e4c3f4:fs/jfs/jfs_txnmgr.c]
Results: map[Output:
Full output is too long, showing 1000 out of 3131 lines.
[/*
* Copyright (C) International Business Machines Corp., 2000-2005
* Portions Copyright (C) Christoph Hellwig, 2001-2002
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
* the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* jfs_txnmgr.c: transaction manager
*
* notes:
* transaction starts with txBegin() and ends with txCommit()
* or txAbort().
*
* tlock is acquired at the time of update;
* (obviate scan at commit time for xtree and dtree)
* tlock and mp points to each other;
* (no hashlist for mp -> tlock).
*
* special cases:
* tlock on in-memory inode:
* in-place tlock in the in-memory inode itself;
* converted to page lock by iWrite() at commit time.
*
* tlock during write()/mmap() under anonymous transaction (tid = 0):
* transferred (?) to transaction at commit time.
*
* use the page itself to update allocation maps
* (obviate intermediate replication of allocation/deallocation data)
* hold on to mp+lock thru update of maps
*/
#include <linux/fs.h>
#include <linux/vmalloc.h>
#include <linux/smp_lock.h>
#include <linux/completion.h>
#include <linux/suspend.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include "jfs_incore.h"
#include "jfs_filsys.h"
#include "jfs_metapage.h"
#include "jfs_dinode.h"
#include "jfs_imap.h"
#include "jfs_dmap.h"
#include "jfs_superblock.h"
#include "jfs_debug.h"
/*
* transaction management structures
*/
static struct {
int freetid; /* index of a free tid structure */
int freelock; /* index first free lock word */
wait_queue_head_t freewait; /* eventlist of free tblock */
wait_queue_head_t freelockwait; /* eventlist of free tlock */
wait_queue_head_t lowlockwait; /* eventlist of ample tlocks */
int tlocksInUse; /* Number of tlocks in use */
spinlock_t LazyLock; /* synchronize sync_queue & unlock_queue */
/* struct tblock *sync_queue; * Transactions waiting for data sync */
struct list_head unlock_queue; /* Txns waiting to be released */
struct list_head anon_list; /* inodes having anonymous txns */
struct list_head anon_list2; /* inodes having anonymous txns
that couldn't be sync'ed */
} TxAnchor;
int jfs_tlocks_low; /* Indicates low number of available tlocks */
#ifdef CONFIG_JFS_STATISTICS
static struct {
uint txBegin;
uint txBegin_barrier;
uint txBegin_lockslow;
uint txBegin_freetid;
uint txBeginAnon;
uint txBeginAnon_barrier;
uint txBeginAnon_lockslow;
uint txLockAlloc;
uint txLockAlloc_freelock;
} TxStat;
#endif
static int nTxBlock = -1; /* number of transaction blocks */
module_param(nTxBlock, int, 0);
MODULE_PARM_DESC(nTxBlock,
"Number of transaction blocks (max:65536)");
static int nTxLock = -1; /* number of transaction locks */
module_param(nTxLock, int, 0);
MODULE_PARM_DESC(nTxLock,
"Number of transaction locks (max:65536)");
struct tblock *TxBlock; /* transaction block table */
static int TxLockLWM; /* Low water mark for number of txLocks used */
static int TxLockHWM; /* High water mark for number of txLocks used */
static int TxLockVHWM; /* Very High water mark */
struct tlock *TxLock; /* transaction lock table */
/*
* transaction management lock
*/
static DEFINE_SPINLOCK(jfsTxnLock);
#define TXN_LOCK() spin_lock(&jfsTxnLock)
#define TXN_UNLOCK() spin_unlock(&jfsTxnLock)
#define LAZY_LOCK_INIT() spin_lock_init(&TxAnchor.LazyLock);
#define LAZY_LOCK(flags) spin_lock_irqsave(&TxAnchor.LazyLock, flags)
#define LAZY_UNLOCK(flags) spin_unlock_irqrestore(&TxAnchor.LazyLock, flags)
DECLARE_WAIT_QUEUE_HEAD(jfs_sync_thread_wait);
DECLARE_WAIT_QUEUE_HEAD(jfs_commit_thread_wait);
static int jfs_commit_thread_waking;
/*
* Retry logic exist outside these macros to protect from spurrious wakeups.
*/
static inline void TXN_SLEEP_DROP_LOCK(wait_queue_head_t * event)
{
DECLARE_WAITQUEUE(wait, current);
add_wait_queue(event, &wait);
set_current_state(TASK_UNINTERRUPTIBLE);
TXN_UNLOCK();
schedule();
current->state = TASK_RUNNING;
remove_wait_queue(event, &wait);
}
#define TXN_SLEEP(event)\
{\
TXN_SLEEP_DROP_LOCK(event);\
TXN_LOCK();\
}
#define TXN_WAKEUP(event) wake_up_all(event)
/*
* statistics
*/
static struct {
tid_t maxtid; /* 4: biggest tid ever used */
lid_t maxlid; /* 4: biggest lid ever used */
int ntid; /* 4: # of transactions performed */
int nlid; /* 4: # of tlocks acquired */
int waitlock; /* 4: # of tlock wait */
} stattx;
/*
* external references
*/
extern int lmGroupCommit(struct jfs_log *, struct tblock *);
extern int jfs_commit_inode(struct inode *, int);
extern int jfs_stop_threads;
extern struct completion jfsIOwait;
/*
* forward references
*/
static int diLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
struct tlock * tlck, struct commit * cd);
static int dataLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
struct tlock * tlck);
static void dtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
struct tlock * tlck);
static void mapLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
struct tlock * tlck);
static void txAllocPMap(struct inode *ip, struct maplock * maplock,
struct tblock * tblk);
static void txForce(struct tblock * tblk);
static int txLog(struct jfs_log * log, struct tblock * tblk,
struct commit * cd);
static void txUpdateMap(struct tblock * tblk);
static void txRelease(struct tblock * tblk);
static void xtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
struct tlock * tlck);
static void LogSyncRelease(struct metapage * mp);
/*
* transaction block/lock management
* ---------------------------------
*/
/*
* Get a transaction lock from the free list. If the number in use is
* greater than the high water mark, wake up the sync daemon. This should
* free some anonymous transaction locks. (TXN_LOCK must be held.)
*/
static lid_t txLockAlloc(void)
{
lid_t lid;
INCREMENT(TxStat.txLockAlloc);
if (!TxAnchor.freelock) {
INCREMENT(TxStat.txLockAlloc_freelock);
}
while (!(lid = TxAnchor.freelock))
TXN_SLEEP(&TxAnchor.freelockwait);
TxAnchor.freelock = TxLock[lid].next;
HIGHWATERMARK(stattx.maxlid, lid);
if ((++TxAnchor.tlocksInUse > TxLockHWM) && (jfs_tlocks_low == 0)) {
jfs_info("txLockAlloc tlocks low");
jfs_tlocks_low = 1;
wake_up(&jfs_sync_thread_wait);
}
return lid;
}
static void txLockFree(lid_t lid)
{
TxLock[lid].next = TxAnchor.freelock;
TxAnchor.freelock = lid;
TxAnchor.tlocksInUse--;
if (jfs_tlocks_low && (TxAnchor.tlocksInUse < TxLockLWM)) {
jfs_info("txLockFree jfs_tlocks_low no more");
jfs_tlocks_low = 0;
TXN_WAKEUP(&TxAnchor.lowlockwait);
}
TXN_WAKEUP(&TxAnchor.freelockwait);
}
/*
* NAME: txInit()
*
* FUNCTION: initialize transaction management structures
*
* RETURN:
*
* serialization: single thread at jfs_init()
*/
int txInit(void)
{
int k, size;
struct sysinfo si;
/* Set defaults for nTxLock and nTxBlock if unset */
if (nTxLock == -1) {
if (nTxBlock == -1) {
/* Base default on memory size */
si_meminfo(&si);
if (si.totalram > (256 * 1024)) /* 1 GB */
nTxLock = 64 * 1024;
else
nTxLock = si.totalram >> 2;
} else if (nTxBlock > (8 * 1024))
nTxLock = 64 * 1024;
else
nTxLock = nTxBlock << 3;
}
if (nTxBlock == -1)
nTxBlock = nTxLock >> 3;
/* Verify tunable parameters */
if (nTxBlock < 16)
nTxBlock = 16; /* No one should set it this low */
if (nTxBlock > 65536)
nTxBlock = 65536;
if (nTxLock < 256)
nTxLock = 256; /* No one should set it this low */
if (nTxLock > 65536)
nTxLock = 65536;
printk(KERN_INFO "JFS: nTxBlock = %d, nTxLock = %d\n",
nTxBlock, nTxLock);
/*
* initialize transaction block (tblock) table
*
* transaction id (tid) = tblock index
* tid = 0 is reserved.
*/
TxLockLWM = (nTxLock * 4) / 10;
TxLockHWM = (nTxLock * 7) / 10;
TxLockVHWM = (nTxLock * 8) / 10;
size = sizeof(struct tblock) * nTxBlock;
TxBlock = (struct tblock *) vmalloc(size);
if (TxBlock == NULL)
return -ENOMEM;
for (k = 1; k < nTxBlock - 1; k++) {
TxBlock[k].next = k + 1;
init_waitqueue_head(&TxBlock[k].gcwait);
init_waitqueue_head(&TxBlock[k].waitor);
}
TxBlock[k].next = 0;
init_waitqueue_head(&TxBlock[k].gcwait);
init_waitqueue_head(&TxBlock[k].waitor);
TxAnchor.freetid = 1;
init_waitqueue_head(&TxAnchor.freewait);
stattx.maxtid = 1; /* statistics */
/*
* initialize transaction lock (tlock) table
*
* transaction lock id = tlock index
* tlock id = 0 is reserved.
*/
size = sizeof(struct tlock) * nTxLock;
TxLock = (struct tlock *) vmalloc(size);
if (TxLock == NULL) {
vfree(TxBlock);
return -ENOMEM;
}
/* initialize tlock table */
for (k = 1; k < nTxLock - 1; k++)
TxLock[k].next = k + 1;
TxLock[k].next = 0;
init_waitqueue_head(&TxAnchor.freelockwait);
init_waitqueue_head(&TxAnchor.lowlockwait);
TxAnchor.freelock = 1;
TxAnchor.tlocksInUse = 0;
INIT_LIST_HEAD(&TxAnchor.anon_list);
INIT_LIST_HEAD(&TxAnchor.anon_list2);
LAZY_LOCK_INIT();
INIT_LIST_HEAD(&TxAnchor.unlock_queue);
stattx.maxlid = 1; /* statistics */
return 0;
}
/*
* NAME: txExit()
*
* FUNCTION: clean up when module is unloaded
*/
void txExit(void)
{
vfree(TxLock);
TxLock = NULL;
vfree(TxBlock);
TxBlock = NULL;
}
/*
* NAME: txBegin()
*
* FUNCTION: start a transaction.
*
* PARAMETER: sb - superblock
* flag - force for nested tx;
*
* RETURN: tid - transaction id
*
* note: flag force allows to start tx for nested tx
* to prevent deadlock on logsync barrier;
*/
tid_t txBegin(struct super_block *sb, int flag)
{
tid_t t;
struct tblock *tblk;
struct jfs_log *log;
jfs_info("txBegin: flag = 0x%x", flag);
log = JFS_SBI(sb)->log;
TXN_LOCK();
INCREMENT(TxStat.txBegin);
retry:
if (!(flag & COMMIT_FORCE)) {
/*
* synchronize with logsync barrier
*/
if (test_bit(log_SYNCBARRIER, &log->flag) ||
test_bit(log_QUIESCE, &log->flag)) {
INCREMENT(TxStat.txBegin_barrier);
TXN_SLEEP(&log->syncwait);
goto retry;
}
}
if (flag == 0) {
/*
* Don't begin transaction if we're getting starved for tlocks
* unless COMMIT_FORCE or COMMIT_INODE (which may ultimately
* free tlocks)
*/
if (TxAnchor.tlocksInUse > TxLockVHWM) {
INCREMENT(TxStat.txBegin_lockslow);
TXN_SLEEP(&TxAnchor.lowlockwait);
goto retry;
}
}
/*
* allocate transaction id/block
*/
if ((t = TxAnchor.freetid) == 0) {
jfs_info("txBegin: waiting for free tid");
INCREMENT(TxStat.txBegin_freetid);
TXN_SLEEP(&TxAnchor.freewait);
goto retry;
}
tblk = tid_to_tblock(t);
if ((tblk->next == 0) && !(flag & COMMIT_FORCE)) {
/* Don't let a non-forced transaction take the last tblk */
jfs_info("txBegin: waiting for free tid");
INCREMENT(TxStat.txBegin_freetid);
TXN_SLEEP(&TxAnchor.freewait);
goto retry;
}
TxAnchor.freetid = tblk->next;
/*
* initialize transaction
*/
/*
* We can't zero the whole thing or we screw up another thread being
* awakened after sleeping on tblk->waitor
*
* memset(tblk, 0, sizeof(struct tblock));
*/
tblk->next = tblk->last = tblk->xflag = tblk->flag = tblk->lsn = 0;
tblk->sb = sb;
++log->logtid;
tblk->logtid = log->logtid;
++log->active;
HIGHWATERMARK(stattx.maxtid, t); /* statistics */
INCREMENT(stattx.ntid); /* statistics */
TXN_UNLOCK();
jfs_info("txBegin: returning tid = %d", t);
return t;
}
/*
* NAME: txBeginAnon()
*
* FUNCTION: start an anonymous transaction.
* Blocks if logsync or available tlocks are low to prevent
* anonymous tlocks from depleting supply.
*
* PARAMETER: sb - superblock
*
* RETURN: none
*/
void txBeginAnon(struct super_block *sb)
{
struct jfs_log *log;
log = JFS_SBI(sb)->log;
TXN_LOCK();
INCREMENT(TxStat.txBeginAnon);
retry:
/*
* synchronize with logsync barrier
*/
if (test_bit(log_SYNCBARRIER, &log->flag) ||
test_bit(log_QUIESCE, &log->flag)) {
INCREMENT(TxStat.txBeginAnon_barrier);
TXN_SLEEP(&log->syncwait);
goto retry;
}
/*
* Don't begin transaction if we're getting starved for tlocks
*/
if (TxAnchor.tlocksInUse > TxLockVHWM) {
INCREMENT(TxStat.txBeginAnon_lockslow);
TXN_SLEEP(&TxAnchor.lowlockwait);
goto retry;
}
TXN_UNLOCK();
}
/*
* txEnd()
*
* function: free specified transaction block.
*
* logsync barrier processing:
*
* serialization:
*/
void txEnd(tid_t tid)
{
struct tblock *tblk = tid_to_tblock(tid);
struct jfs_log *log;
jfs_info("txEnd: tid = %d", tid);
TXN_LOCK();
/*
* wakeup transactions waiting on the page locked
* by the current transaction
*/
TXN_WAKEUP(&tblk->waitor);
log = JFS_SBI(tblk->sb)->log;
/*
* Lazy commit thread can't free this guy until we mark it UNLOCKED,
* otherwise, we would be left with a transaction that may have been
* reused.
*
* Lazy commit thread will turn off tblkGC_LAZY before calling this
* routine.
*/
if (tblk->flag & tblkGC_LAZY) {
jfs_info("txEnd called w/lazy tid: %d, tblk = 0x%p", tid, tblk);
TXN_UNLOCK();
spin_lock_irq(&log->gclock); // LOGGC_LOCK
tblk->flag |= tblkGC_UNLOCKED;
spin_unlock_irq(&log->gclock); // LOGGC_UNLOCK
return;
}
jfs_info("txEnd: tid: %d, tblk = 0x%p", tid, tblk);
assert(tblk->next == 0);
/*
* insert tblock back on freelist
*/
tblk->next = TxAnchor.freetid;
TxAnchor.freetid = tid;
/*
* mark the tblock not active
*/
if (--log->active == 0) {
clear_bit(log_FLUSH, &log->flag);
/*
* synchronize with logsync barrier
*/
if (test_bit(log_SYNCBARRIER, &log->flag)) {
/* forward log syncpt */
/* lmSync(log); */
jfs_info("log barrier off: 0x%x", log->lsn);
/* enable new transactions start */
clear_bit(log_SYNCBARRIER, &log->flag);
/* wakeup all waitors for logsync barrier */
TXN_WAKEUP(&log->syncwait);
}
}
/*
* wakeup all waitors for a free tblock
*/
TXN_WAKEUP(&TxAnchor.freewait);
TXN_UNLOCK();
}
/*
* txLock()
*
* function: acquire a transaction lock on the specified <mp>
*
* parameter:
*
* return: transaction lock id
*
* serialization:
*/
struct tlock *txLock(tid_t tid, struct inode *ip, struct metapage * mp,
int type)
{
struct jfs_inode_info *jfs_ip = JFS_IP(ip);
int dir_xtree = 0;
lid_t lid;
tid_t xtid;
struct tlock *tlck;
struct xtlock *xtlck;
struct linelock *linelock;
xtpage_t *p;
struct tblock *tblk;
TXN_LOCK();
if (S_ISDIR(ip->i_mode) && (type & tlckXTREE) &&
!(mp->xflag & COMMIT_PAGE)) {
/*
* Directory inode is special. It can have both an xtree tlock
* and a dtree tlock associated with it.
*/
dir_xtree = 1;
lid = jfs_ip->xtlid;
} else
lid = mp->lid;
/* is page not locked by a transaction ? */
if (lid == 0)
goto allocateLock;
jfs_info("txLock: tid:%d ip:0x%p mp:0x%p lid:%d", tid, ip, mp, lid);
/* is page locked by the requester transaction ? */
tlck = lid_to_tlock(lid);
if ((xtid = tlck->tid) == tid)
goto grantLock;
/*
* is page locked by anonymous transaction/lock ?
*
* (page update without transaction (i.e., file write) is
* locked under anonymous transaction tid = 0:
* anonymous tlocks maintained on anonymous tlock list of
* the inode of the page and available to all anonymous
* transactions until txCommit() time at which point
* they are transferred to the transaction tlock list of
* the commiting transaction of the inode)
*/
if (xtid == 0) {
tlck->tid = tid;
tblk = tid_to_tblock(tid);
/*
* The order of the tlocks in the transaction is important
* (during truncate, child xtree pages must be freed before
* parent's tlocks change the working map).
* Take tlock off anonymous list and add to tail of
* transaction list
*
* Note: We really need to get rid of the tid & lid and
* use list_head's. This code is getting UGLY!
*/
if (jfs_ip->atlhead == lid) {
if (jfs_ip->atltail == lid) {
/* only anonymous txn.
* Remove from anon_list
*/
list_del_init(&jfs_ip->anon_inode_list);
}
jfs_ip->atlhead = tlck->next;
} else {
lid_t last;
for (last = jfs_ip->atlhead;
lid_to_tlock(last)->next != lid;
last = lid_to_tlock(last)->next) {
assert(last);
}
lid_to_tlock(last)->next = tlck->next;
if (jfs_ip->atltail == lid)
jfs_ip->atltail = last;
}
/* insert the tlock at tail of transaction tlock list */
if (tblk->next)
lid_to_tlock(tblk->last)->next = lid;
else
tblk->next = lid;
tlck->next = 0;
tblk->last = lid;
goto grantLock;
}
goto waitLock;
/*
* allocate a tlock
*/
allocateLock:
lid = txLockAlloc();
tlck = lid_to_tlock(lid);
/*
* initialize tlock
*/
tlck->tid = tid;
/* mark tlock for meta-data page */
if (mp->xflag & COMMIT_PAGE) {
tlck->flag = tlckPAGELOCK;
/* mark the page dirty and nohomeok */
mark_metapage_dirty(mp);
atomic_inc(&mp->nohomeok);
jfs_info("locking mp = 0x%p, nohomeok = %d tid = %d tlck = 0x%p",
mp, atomic_read(&mp->nohomeok), tid, tlck);
/* if anonymous transaction, and buffer is on the group
* commit synclist, mark inode to show this. This will
* prevent the buffer from being marked nohomeok for too
* long a time.
*/
if ((tid == 0) && mp->lsn)
set_cflag(COMMIT_Synclist, ip);
}
/* mark tlock for in-memory inode */
else
tlck->flag = tlckINODELOCK;
tlck->type = 0;
/* bind the tlock and the page */
tlck->ip = ip;
tlck->mp = mp;
if (dir_xtree)
jfs_ip->xtlid = lid;
else
mp->lid = lid;
/*
* enqueue transaction lock to transaction/inode
*/
/* insert the tlock at tail of transaction tlock list */
if (tid) {
tblk = tid_to_tblock(tid);
if (tblk->next)
lid_to_tlock(tblk->last)->next = lid;
else
tblk->next = lid;
tlck->next = 0;
tblk->last = lid;
}
/* anonymous transaction:
* insert the tlock at head of inode anonymous tlock list
*/
else {
tlck->next = jfs_ip->atlhead;
jfs_ip->atlhead = lid;
if (tlck->next == 0) {
/* This inode's first anonymous transaction */
jfs_ip->atltail = lid;
list_add_tail(&jfs_ip->anon_inode_list,
&TxAnchor.anon_list);
}
}
/* initialize type dependent area for linelock */
linelock = (struct linelock *) & tlck->lock;
linelock->next = 0;
linelock->flag = tlckLINELOCK;
linelock->maxcnt = TLOCKSHORT;
linelock->index = 0;
switch (type & tlckTYPE) {
case tlckDTREE:
linelock->l2linesize = L2DTSLOTSIZE;
break;
case tlckXTREE:
linelock->l2linesize = L2XTSLOTSIZE;
xtlck = (struct xtlock *) linelock;
xtlck->header.offset = 0;
xtlck->header.length = 2;
if (type & tlckNEW) {
xtlck->lwm.offset = XTENTRYSTART;
} else {
if (mp->xflag & COMMIT_PAGE)
p = (xtpage_t *) mp->data;
else
p = &jfs_ip->i_xtroot;
xtlck->lwm.offset =
le16_to_cpu(p->header.nextindex);
}
xtlck->lwm.length = 0; /* ! */
xtlck->twm.offset = 0;
xtlck->hwm.offset = 0;
xtlck->index = 2;
break;
case tlckINODE:
linelock->l2linesize = L2INODESLOTSIZE;
break;
case tlckDATA:
linelock->l2linesize = L2DATASLOTSIZE;
break;
default:
jfs_err("UFO tlock:0x%p", tlck);
}
/*
* update tlock vector
*/
grantLock:
tlck->type |= type;
TXN_UNLOCK();
return tlck;
/*
* page is being locked by another transaction:
*/
waitLock:
/* Only locks on ipimap or ipaimap should reach here */
/* assert(jfs_ip->fileset == AGGREGATE_I); */
if (jfs_ip->fileset != AGGREGATE_I) {
jfs_err("txLock: trying to lock locked page!");
dump_mem("ip", ip, sizeof(struct inode));
dump_mem("mp", mp, sizeof(struct metapage));
dump_mem("Locker's tblk", tid_to_tblock(tid),
sizeof(struct tblock));
dump_mem("Tlock", tlck, sizeof(struct tlock));
BUG();
}
INCREMENT(stattx.waitlock); /* statistics */
release_metapage(mp);
jfs_info("txLock: in waitLock, tid = %d, xtid = %d, lid = %d",
tid, xtid, lid);
TXN_SLEEP_DROP_LOCK(&tid_to_tblock(xtid)->waitor);
jfs_info("txLock: awakened tid = %d, lid = %d", tid, lid);
return NULL;
}
/*
* NAME: txRelease()
*
* FUNCTION: Release buffers associated with transaction locks, but don't
* mark homeok yet. The allows other transactions to modify
* buffers, but won't let them go to disk until commit record
* actually gets written.
*
* PARAMETER:
* tblk -
*
* RETURN: Errors from subroutines.
*/
static void txRelease(struct tblock * tblk)
{
struct metapage *mp;
lid_t lid;
struct tlock *tlck;
TXN_LOCK();
for (lid = tblk->next; lid; lid = tlck->next) {
tlck = lid_to_tlock(lid);
if ((mp = tlck->mp) != NULL &&
(tlck->type & tlckBTROOT) == 0) {
assert(mp->xflag & COMMIT_PAGE);
mp->lid = 0;
}
}
/*
* wakeup transactions waiting on a page locked
* by the current transaction
*/
TXN_WAKEUP(&tblk->waitor);
TXN_UNLOCK();
}
/*
* NAME: txUnlock()
*
* FUNCTION: Initiates pageout of pages modified by tid in journalled
* objects and frees their lockwords.
*/
static void txUnlock(struct tblock * tblk)
{
struct tlock *tlck;
struct linelock *linelock;
lid_t lid, next, llid, k;
struct metapage *mp;
struct jfs_log *log;
int difft, diffp;
jfs_info("txUnlock: tblk = 0x%p", tblk);
log = JFS_SBI(tblk->sb)->log;
/*
* mark page under tlock homeok (its log has been written):
*/
for (lid = tblk->next; lid; lid = next) {
tlck = lid_to_tlock(lid);
next = tlck->next;
jfs_info("unlocking lid = %d, tlck = 0x%p", lid, tlck);
/* unbind page from tlock */
if ((mp = tlck->mp) != NULL &&
(tlck->type & tlckBTROOT) == 0) {
assert(mp->xflag & COMMIT_PAGE);
/* hold buffer
*
* It's possible that someone else has the metapage.
* The only things were changing are nohomeok, which
* is handled atomically, and clsn which is protected
* by the LOGSYNC_LOCK.
*/
hold_metapage(mp, 1);
assert(atomic_read(&mp->nohomeok) > 0);
atomic_dec(&mp->nohomeok);
/* inherit younger/larger clsn */
LOGSYNC_LOCK(log);
if (mp->clsn) {
logdiff(difft, tblk->clsn, log);
logdiff(diffp, mp->clsn, log);
if (difft > diffp)
mp->clsn = tblk->clsn;
} else
mp->clsn = tblk->clsn;
LOGSYNC_UNLOCK(log);
assert(!(tlck->flag & tlckFREEPAGE));
if (tlck->flag & tlckWRITEPAGE) {
write_metapage(mp);
} else {
/* release page which has been forced */
release_metapage(mp);
}
}
/* insert tlock, and linelock(s) of the tlock if any,
* at head of freelist
*/
TXN_LOCK();
llid = ((struct linelock *) & tlck->lock)->next;
while (llid) {
linelock = (struct linelock *) lid_to_tlock(llid);
k = linelock->next;
txLockFree(llid);
llid = k;
}
txLockFree(lid);
TXN_UNLOCK();
}
tblk->next = tblk->last = 0;
/*
* remove tblock from logsynclist
* (allocation map pages inherited lsn of tblk and
* has been inserted in logsync list at txUpdateMap())
*/
if (tblk->lsn) {
LOGSYNC_LOCK(log);
log->count--;
list_del(&tblk->synclist);
LOGSYNC_UNLOCK(log);
}
}
/*
* txMaplock()
*
* function: allocate a transaction lock for freed page/entry;
* for freed page, maplock is used as xtlock/dtlock type;
*/
struct tlock *txMaplock(tid_t tid, struct inode *ip, int type)
{
struct jfs_inode_info *jfs_ip = JFS_IP(ip);
]
]
|
| 184/2 |
2026/05/12 00:33 |
llm |
fixes-finder |
0m
Model:
Tokens:
input: 58841
output: 46
thoughts: 302
Thoughts: **Initial Assessment of `jfs_lazycommit` in JFS History**
Okay, so I'm looking at this `jfs_lazycommit` function and my initial thought is that it's been around for quite a while, probably right from the start, considering the age of this JFS code. Let's see... the initial commit, `1da177e4c3f4`... yep, it's there. No, let me confirm. Okay, *yes*, it appears to be part of that very first import. Which means... this potential issue could be ancient history.
Alright, now I need to verify something critical: Did `jfs_umount` *always* lack proper synchronization with `jfs_lazycommit`? Specifically, has it always called `jfs_flush_journal(log, 2)` without waiting? Let's check the source in the first commit again. I can see it:
```c
if ((log = sbi->log))
/*
* Wait for outstanding transactions to be written to log:
*/
jfs_flush_journal(log, 2);
```
Okay, so `jfs_flush_journal(log, 2)` *was* present in `1da177e4c3f4`, and `jfs_lazycommit` was a separate thread. This is starting to look like the bug's been baked in since the beginning... `1da177e4c3f41524e886b7f1b8a0c1fc7321cac2`. But wait, I'm getting ahead of myself. I need to be *absolutely* sure. What if `jfs_lazycommit` was introduced in a later commit? Let's rule out that possibility. Time to search the git log again, but with a more generous look back, maybe the last 100 commits, to make sure I haven't missed a smaller merge that introduced it.
|
| 185/2 |
2026/05/12 00:33 |
tool |
git-log |
0m
Args: map[Count:100 SourcePath:fs/jfs/jfs_txnmgr.c SymbolName:jfs_lazycommit]
Results: map[Output:a280c9ceeca7 jfs: Add missing set_freezable() for freezable kthread
b18db6de2ce2 jfs: Remove terminating newlines from jfs_info, jfs_warn, jfs_err uses
f139caf2e897 sched, cleanup, treewide: Remove set_current_state(TASK_RUNNING) after schedule()
a0acae0e886d freezer: unexport refrigerator() and update try_to_freeze() slightly
3cbb1c8e1a47 JFS: use __set_current_state()
91dbb4deb30e JFS: Use the kthread_ API
3e1d1d28d99d [PATCH] Cleanup patch for process freezing
1da177e4c3f4 Linux-2.6.12-rc2
]
|
| 186/2 |
2026/05/12 00:34 |
llm |
fixes-finder |
0m
Model:
Tokens:
input: 59847
output: 45
thoughts: 66
Thoughts: **Analyzing the `jfs_umount` History**
Okay, the commit `1da177e4c3f4` definitely looks like the earliest one in this history. But, before I get too far down the rabbit hole, I should double-check something. Let me see if any later commits modified the behavior of `jfs_umount` regarding `jfs_lazycommit`. I want to make sure I'm not missing a crucial change that might alter the context of that initial commit. Alright, time to trace the history of `jfs_umount` itself and see what comes up.
|
| 187/2 |
2026/05/12 00:34 |
tool |
git-log |
0m
Args: map[Count:100 SourcePath:fs/jfs/jfs_umount.c SymbolName:jfs_umount]
Results: map[Output:ca5848ae87d2 jfs: hold LOG_LOCK on umount to avoid null-ptr-deref
d0e482c45c50 jfs: Fix a typo in function jfs_umount
dee874452409 jfs: remove redundant assignments to ipaimap and ipaimap2
1c8007b0769d jfs: flush journal completely before releasing metadata inodes
67e6682f18b3 JFS: Make sure special inode data is written after journal is flushed
f720e3ba5586 JFS: Whitespace cleanup and remove some dead code
63f83c9fcf40 JFS: White space cleanup
28fd129827b0 [PATCH] Fix and add EXPORT_SYMBOL(filemap_write_and_wait)
7fab479bebb9 [PATCH] JFS: Support page sizes greater than 4K
1da177e4c3f4 Linux-2.6.12-rc2
]
|
| 188/2 |
2026/05/12 00:34 |
llm |
fixes-finder |
0m
Model:
Tokens:
input: 60352
output: 27
thoughts: 41
Thoughts: Okay, here's my take on those thoughts, tailored for an expert audience:
**Debugging Initiative: Examining Commits for Bug Introduction**
Alright, time to get granular. Based on the current state of things, my immediate hypothesis is that a regression was likely introduced within a specific range of commits. So, my primary focus is to methodically investigate those suspected commits. I need to zero in on the precise changes that caused this. Specifically, Iβm planning on diving deep into `1c8007b0769d` and `67e6682f18b3`. I want to see *exactly* what was modified in each commit, looking for the smoking gun β that specific line, logic change, or configuration shift that's causing this issue to manifest. I'll need to meticulously analyze the diffs, perhaps even build and test each commit individually if necessary. Ultimately, the goal is pinpoint the culprit and understand the root cause so we can formulate the most effective fix.
|
| 189/2 |
2026/05/12 00:34 |
tool |
git-show |
0m
Args:
Results: map[Output:commit 1c8007b0769d37aa5fcb343b383b0af89ade2f71
Author: Dave Kleikamp <dave.kleikamp@oracle.com>
Date: Mon Aug 1 12:41:00 2011 -0500
jfs: flush journal completely before releasing metadata inodes
This fixes a race during unmount. We need to not only make sure that
the journal is completely written, but that the metadata changes make
it to disk before releasing ipimap and ipbmap.
Signed-off-by: Dave Kleikamp <dave.kleikamp@oracle.com>
diff --git a/fs/jfs/jfs_umount.c b/fs/jfs/jfs_umount.c
index adcf92d3b603..7971f37534a3 100644
--- a/fs/jfs/jfs_umount.c
+++ b/fs/jfs/jfs_umount.c
@@ -68,7 +68,7 @@ int jfs_umount(struct super_block *sb)
/*
* Wait for outstanding transactions to be written to log:
*/
- jfs_flush_journal(log, 1);
+ jfs_flush_journal(log, 2);
/*
* close fileset inode allocation map (aka fileset inode)
@@ -146,7 +146,7 @@ int jfs_umount_rw(struct super_block *sb)
*
* remove file system from log active file system list.
*/
- jfs_flush_journal(log, 1);
+ jfs_flush_journal(log, 2);
/*
* Make sure all metadata makes it to disk
]
|
| 190/2 |
2026/05/12 00:34 |
llm |
fixes-finder |
0m
Model:
Tokens:
input: 61113
output: 40
thoughts: 98
Thoughts: Okay, here's my take on those thoughts, framed as an expert's internal monologue:
**Investigating a Journal Flush Optimization**
Right, so that commit, `1c8007b0769d`, caught my eye. It looks like someone bumped up the flush level in `jfs_flush_journal` from `1` to `2`. Hmm, interesting. The comment in the code suggests that `jfs_flush_journal(log, 2)` implies a *complete* write, meaning we're waiting for everything to be committed to disk before returning. This is a potentially significant change in behavior. I need to understand why this was done. Let's delve into the implementation of `jfs_flush_journal` itself, likely in `fs/jfs/jfs_logmgr.c`. I want to see what this full flush entails, and if there's any commentary in the code about the rationale behind it. Was this for data integrity, performance, or a specific workload? Understanding the code will give me the proper context for the change and help me properly evaluate its effects.
|
| 191/2 |
2026/05/12 00:34 |
tool |
git-show |
0m
Args: map[Commit:1c8007b0769d:fs/jfs/jfs_logmgr.c]
Results: map[Output:
Full output is too long, showing 1000 out of 2529 lines.
[/*
* Copyright (C) International Business Machines Corp., 2000-2004
* Portions Copyright (C) Christoph Hellwig, 2001-2002
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
* the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* jfs_logmgr.c: log manager
*
* for related information, see transaction manager (jfs_txnmgr.c), and
* recovery manager (jfs_logredo.c).
*
* note: for detail, RTFS.
*
* log buffer manager:
* special purpose buffer manager supporting log i/o requirements.
* per log serial pageout of logpage
* queuing i/o requests and redrive i/o at iodone
* maintain current logpage buffer
* no caching since append only
* appropriate jfs buffer cache buffers as needed
*
* group commit:
* transactions which wrote COMMIT records in the same in-memory
* log page during the pageout of previous/current log page(s) are
* committed together by the pageout of the page.
*
* TBD lazy commit:
* transactions are committed asynchronously when the log page
* containing it COMMIT is paged out when it becomes full;
*
* serialization:
* . a per log lock serialize log write.
* . a per log lock serialize group commit.
* . a per log lock serialize log open/close;
*
* TBD log integrity:
* careful-write (ping-pong) of last logpage to recover from crash
* in overwrite.
* detection of split (out-of-order) write of physical sectors
* of last logpage via timestamp at end of each sector
* with its mirror data array at trailer).
*
* alternatives:
* lsn - 64-bit monotonically increasing integer vs
* 32-bit lspn and page eor.
*/
#include <linux/fs.h>
#include <linux/blkdev.h>
#include <linux/interrupt.h>
#include <linux/completion.h>
#include <linux/kthread.h>
#include <linux/buffer_head.h> /* for sync_blockdev() */
#include <linux/bio.h>
#include <linux/freezer.h>
#include <linux/delay.h>
#include <linux/mutex.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
#include "jfs_incore.h"
#include "jfs_filsys.h"
#include "jfs_metapage.h"
#include "jfs_superblock.h"
#include "jfs_txnmgr.h"
#include "jfs_debug.h"
/*
* lbuf's ready to be redriven. Protected by log_redrive_lock (jfsIO thread)
*/
static struct lbuf *log_redrive_list;
static DEFINE_SPINLOCK(log_redrive_lock);
/*
* log read/write serialization (per log)
*/
#define LOG_LOCK_INIT(log) mutex_init(&(log)->loglock)
#define LOG_LOCK(log) mutex_lock(&((log)->loglock))
#define LOG_UNLOCK(log) mutex_unlock(&((log)->loglock))
/*
* log group commit serialization (per log)
*/
#define LOGGC_LOCK_INIT(log) spin_lock_init(&(log)->gclock)
#define LOGGC_LOCK(log) spin_lock_irq(&(log)->gclock)
#define LOGGC_UNLOCK(log) spin_unlock_irq(&(log)->gclock)
#define LOGGC_WAKEUP(tblk) wake_up_all(&(tblk)->gcwait)
/*
* log sync serialization (per log)
*/
#define LOGSYNC_DELTA(logsize) min((logsize)/8, 128*LOGPSIZE)
#define LOGSYNC_BARRIER(logsize) ((logsize)/4)
/*
#define LOGSYNC_DELTA(logsize) min((logsize)/4, 256*LOGPSIZE)
#define LOGSYNC_BARRIER(logsize) ((logsize)/2)
*/
/*
* log buffer cache synchronization
*/
static DEFINE_SPINLOCK(jfsLCacheLock);
#define LCACHE_LOCK(flags) spin_lock_irqsave(&jfsLCacheLock, flags)
#define LCACHE_UNLOCK(flags) spin_unlock_irqrestore(&jfsLCacheLock, flags)
/*
* See __SLEEP_COND in jfs_locks.h
*/
#define LCACHE_SLEEP_COND(wq, cond, flags) \
do { \
if (cond) \
break; \
__SLEEP_COND(wq, cond, LCACHE_LOCK(flags), LCACHE_UNLOCK(flags)); \
} while (0)
#define LCACHE_WAKEUP(event) wake_up(event)
/*
* lbuf buffer cache (lCache) control
*/
/* log buffer manager pageout control (cumulative, inclusive) */
#define lbmREAD 0x0001
#define lbmWRITE 0x0002 /* enqueue at tail of write queue;
* init pageout if at head of queue;
*/
#define lbmRELEASE 0x0004 /* remove from write queue
* at completion of pageout;
* do not free/recycle it yet:
* caller will free it;
*/
#define lbmSYNC 0x0008 /* do not return to freelist
* when removed from write queue;
*/
#define lbmFREE 0x0010 /* return to freelist
* at completion of pageout;
* the buffer may be recycled;
*/
#define lbmDONE 0x0020
#define lbmERROR 0x0040
#define lbmGC 0x0080 /* lbmIODone to perform post-GC processing
* of log page
*/
#define lbmDIRECT 0x0100
/*
* Global list of active external journals
*/
static LIST_HEAD(jfs_external_logs);
static struct jfs_log *dummy_log = NULL;
static DEFINE_MUTEX(jfs_log_mutex);
/*
* forward references
*/
static int lmWriteRecord(struct jfs_log * log, struct tblock * tblk,
struct lrd * lrd, struct tlock * tlck);
static int lmNextPage(struct jfs_log * log);
static int lmLogFileSystem(struct jfs_log * log, struct jfs_sb_info *sbi,
int activate);
static int open_inline_log(struct super_block *sb);
static int open_dummy_log(struct super_block *sb);
static int lbmLogInit(struct jfs_log * log);
static void lbmLogShutdown(struct jfs_log * log);
static struct lbuf *lbmAllocate(struct jfs_log * log, int);
static void lbmFree(struct lbuf * bp);
static void lbmfree(struct lbuf * bp);
static int lbmRead(struct jfs_log * log, int pn, struct lbuf ** bpp);
static void lbmWrite(struct jfs_log * log, struct lbuf * bp, int flag, int cant_block);
static void lbmDirectWrite(struct jfs_log * log, struct lbuf * bp, int flag);
static int lbmIOWait(struct lbuf * bp, int flag);
static bio_end_io_t lbmIODone;
static void lbmStartIO(struct lbuf * bp);
static void lmGCwrite(struct jfs_log * log, int cant_block);
static int lmLogSync(struct jfs_log * log, int hard_sync);
/*
* statistics
*/
#ifdef CONFIG_JFS_STATISTICS
static struct lmStat {
uint commit; /* # of commit */
uint pagedone; /* # of page written */
uint submitted; /* # of pages submitted */
uint full_page; /* # of full pages submitted */
uint partial_page; /* # of partial pages submitted */
} lmStat;
#endif
static void write_special_inodes(struct jfs_log *log,
int (*writer)(struct address_space *))
{
struct jfs_sb_info *sbi;
list_for_each_entry(sbi, &log->sb_list, log_list) {
writer(sbi->ipbmap->i_mapping);
writer(sbi->ipimap->i_mapping);
writer(sbi->direct_inode->i_mapping);
}
}
/*
* NAME: lmLog()
*
* FUNCTION: write a log record;
*
* PARAMETER:
*
* RETURN: lsn - offset to the next log record to write (end-of-log);
* -1 - error;
*
* note: todo: log error handler
*/
int lmLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
struct tlock * tlck)
{
int lsn;
int diffp, difft;
struct metapage *mp = NULL;
unsigned long flags;
jfs_info("lmLog: log:0x%p tblk:0x%p, lrd:0x%p tlck:0x%p",
log, tblk, lrd, tlck);
LOG_LOCK(log);
/* log by (out-of-transaction) JFS ? */
if (tblk == NULL)
goto writeRecord;
/* log from page ? */
if (tlck == NULL ||
tlck->type & tlckBTROOT || (mp = tlck->mp) == NULL)
goto writeRecord;
/*
* initialize/update page/transaction recovery lsn
*/
lsn = log->lsn;
LOGSYNC_LOCK(log, flags);
/*
* initialize page lsn if first log write of the page
*/
if (mp->lsn == 0) {
mp->log = log;
mp->lsn = lsn;
log->count++;
/* insert page at tail of logsynclist */
list_add_tail(&mp->synclist, &log->synclist);
}
/*
* initialize/update lsn of tblock of the page
*
* transaction inherits oldest lsn of pages associated
* with allocation/deallocation of resources (their
* log records are used to reconstruct allocation map
* at recovery time: inode for inode allocation map,
* B+-tree index of extent descriptors for block
* allocation map);
* allocation map pages inherit transaction lsn at
* commit time to allow forwarding log syncpt past log
* records associated with allocation/deallocation of
* resources only after persistent map of these map pages
* have been updated and propagated to home.
*/
/*
* initialize transaction lsn:
*/
if (tblk->lsn == 0) {
/* inherit lsn of its first page logged */
tblk->lsn = mp->lsn;
log->count++;
/* insert tblock after the page on logsynclist */
list_add(&tblk->synclist, &mp->synclist);
}
/*
* update transaction lsn:
*/
else {
/* inherit oldest/smallest lsn of page */
logdiff(diffp, mp->lsn, log);
logdiff(difft, tblk->lsn, log);
if (diffp < difft) {
/* update tblock lsn with page lsn */
tblk->lsn = mp->lsn;
/* move tblock after page on logsynclist */
list_move(&tblk->synclist, &mp->synclist);
}
}
LOGSYNC_UNLOCK(log, flags);
/*
* write the log record
*/
writeRecord:
lsn = lmWriteRecord(log, tblk, lrd, tlck);
/*
* forward log syncpt if log reached next syncpt trigger
*/
logdiff(diffp, lsn, log);
if (diffp >= log->nextsync)
lsn = lmLogSync(log, 0);
/* update end-of-log lsn */
log->lsn = lsn;
LOG_UNLOCK(log);
/* return end-of-log address */
return lsn;
}
/*
* NAME: lmWriteRecord()
*
* FUNCTION: move the log record to current log page
*
* PARAMETER: cd - commit descriptor
*
* RETURN: end-of-log address
*
* serialization: LOG_LOCK() held on entry/exit
*/
static int
lmWriteRecord(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
struct tlock * tlck)
{
int lsn = 0; /* end-of-log address */
struct lbuf *bp; /* dst log page buffer */
struct logpage *lp; /* dst log page */
caddr_t dst; /* destination address in log page */
int dstoffset; /* end-of-log offset in log page */
int freespace; /* free space in log page */
caddr_t p; /* src meta-data page */
caddr_t src;
int srclen;
int nbytes; /* number of bytes to move */
int i;
int len;
struct linelock *linelock;
struct lv *lv;
struct lvd *lvd;
int l2linesize;
len = 0;
/* retrieve destination log page to write */
bp = (struct lbuf *) log->bp;
lp = (struct logpage *) bp->l_ldata;
dstoffset = log->eor;
/* any log data to write ? */
if (tlck == NULL)
goto moveLrd;
/*
* move log record data
*/
/* retrieve source meta-data page to log */
if (tlck->flag & tlckPAGELOCK) {
p = (caddr_t) (tlck->mp->data);
linelock = (struct linelock *) & tlck->lock;
}
/* retrieve source in-memory inode to log */
else if (tlck->flag & tlckINODELOCK) {
if (tlck->type & tlckDTREE)
p = (caddr_t) &JFS_IP(tlck->ip)->i_dtroot;
else
p = (caddr_t) &JFS_IP(tlck->ip)->i_xtroot;
linelock = (struct linelock *) & tlck->lock;
}
#ifdef _JFS_WIP
else if (tlck->flag & tlckINLINELOCK) {
inlinelock = (struct inlinelock *) & tlck;
p = (caddr_t) & inlinelock->pxd;
linelock = (struct linelock *) & tlck;
}
#endif /* _JFS_WIP */
else {
jfs_err("lmWriteRecord: UFO tlck:0x%p", tlck);
return 0; /* Probably should trap */
}
l2linesize = linelock->l2linesize;
moveData:
ASSERT(linelock->index <= linelock->maxcnt);
lv = linelock->lv;
for (i = 0; i < linelock->index; i++, lv++) {
if (lv->length == 0)
continue;
/* is page full ? */
if (dstoffset >= LOGPSIZE - LOGPTLRSIZE) {
/* page become full: move on to next page */
lmNextPage(log);
bp = log->bp;
lp = (struct logpage *) bp->l_ldata;
dstoffset = LOGPHDRSIZE;
}
/*
* move log vector data
*/
src = (u8 *) p + (lv->offset << l2linesize);
srclen = lv->length << l2linesize;
len += srclen;
while (srclen > 0) {
freespace = (LOGPSIZE - LOGPTLRSIZE) - dstoffset;
nbytes = min(freespace, srclen);
dst = (caddr_t) lp + dstoffset;
memcpy(dst, src, nbytes);
dstoffset += nbytes;
/* is page not full ? */
if (dstoffset < LOGPSIZE - LOGPTLRSIZE)
break;
/* page become full: move on to next page */
lmNextPage(log);
bp = (struct lbuf *) log->bp;
lp = (struct logpage *) bp->l_ldata;
dstoffset = LOGPHDRSIZE;
srclen -= nbytes;
src += nbytes;
}
/*
* move log vector descriptor
*/
len += 4;
lvd = (struct lvd *) ((caddr_t) lp + dstoffset);
lvd->offset = cpu_to_le16(lv->offset);
lvd->length = cpu_to_le16(lv->length);
dstoffset += 4;
jfs_info("lmWriteRecord: lv offset:%d length:%d",
lv->offset, lv->length);
}
if ((i = linelock->next)) {
linelock = (struct linelock *) lid_to_tlock(i);
goto moveData;
}
/*
* move log record descriptor
*/
moveLrd:
lrd->length = cpu_to_le16(len);
src = (caddr_t) lrd;
srclen = LOGRDSIZE;
while (srclen > 0) {
freespace = (LOGPSIZE - LOGPTLRSIZE) - dstoffset;
nbytes = min(freespace, srclen);
dst = (caddr_t) lp + dstoffset;
memcpy(dst, src, nbytes);
dstoffset += nbytes;
srclen -= nbytes;
/* are there more to move than freespace of page ? */
if (srclen)
goto pageFull;
/*
* end of log record descriptor
*/
/* update last log record eor */
log->eor = dstoffset;
bp->l_eor = dstoffset;
lsn = (log->page << L2LOGPSIZE) + dstoffset;
if (lrd->type & cpu_to_le16(LOG_COMMIT)) {
tblk->clsn = lsn;
jfs_info("wr: tclsn:0x%x, beor:0x%x", tblk->clsn,
bp->l_eor);
INCREMENT(lmStat.commit); /* # of commit */
/*
* enqueue tblock for group commit:
*
* enqueue tblock of non-trivial/synchronous COMMIT
* at tail of group commit queue
* (trivial/asynchronous COMMITs are ignored by
* group commit.)
*/
LOGGC_LOCK(log);
/* init tblock gc state */
tblk->flag = tblkGC_QUEUE;
tblk->bp = log->bp;
tblk->pn = log->page;
tblk->eor = log->eor;
/* enqueue transaction to commit queue */
list_add_tail(&tblk->cqueue, &log->cqueue);
LOGGC_UNLOCK(log);
}
jfs_info("lmWriteRecord: lrd:0x%04x bp:0x%p pn:%d eor:0x%x",
le16_to_cpu(lrd->type), log->bp, log->page, dstoffset);
/* page not full ? */
if (dstoffset < LOGPSIZE - LOGPTLRSIZE)
return lsn;
pageFull:
/* page become full: move on to next page */
lmNextPage(log);
bp = (struct lbuf *) log->bp;
lp = (struct logpage *) bp->l_ldata;
dstoffset = LOGPHDRSIZE;
src += nbytes;
}
return lsn;
}
/*
* NAME: lmNextPage()
*
* FUNCTION: write current page and allocate next page.
*
* PARAMETER: log
*
* RETURN: 0
*
* serialization: LOG_LOCK() held on entry/exit
*/
static int lmNextPage(struct jfs_log * log)
{
struct logpage *lp;
int lspn; /* log sequence page number */
int pn; /* current page number */
struct lbuf *bp;
struct lbuf *nextbp;
struct tblock *tblk;
/* get current log page number and log sequence page number */
pn = log->page;
bp = log->bp;
lp = (struct logpage *) bp->l_ldata;
lspn = le32_to_cpu(lp->h.page);
LOGGC_LOCK(log);
/*
* write or queue the full page at the tail of write queue
*/
/* get the tail tblk on commit queue */
if (list_empty(&log->cqueue))
tblk = NULL;
else
tblk = list_entry(log->cqueue.prev, struct tblock, cqueue);
/* every tblk who has COMMIT record on the current page,
* and has not been committed, must be on commit queue
* since tblk is queued at commit queueu at the time
* of writing its COMMIT record on the page before
* page becomes full (even though the tblk thread
* who wrote COMMIT record may have been suspended
* currently);
*/
/* is page bound with outstanding tail tblk ? */
if (tblk && tblk->pn == pn) {
/* mark tblk for end-of-page */
tblk->flag |= tblkGC_EOP;
if (log->cflag & logGC_PAGEOUT) {
/* if page is not already on write queue,
* just enqueue (no lbmWRITE to prevent redrive)
* buffer to wqueue to ensure correct serial order
* of the pages since log pages will be added
* continuously
*/
if (bp->l_wqnext == NULL)
lbmWrite(log, bp, 0, 0);
} else {
/*
* No current GC leader, initiate group commit
*/
log->cflag |= logGC_PAGEOUT;
lmGCwrite(log, 0);
}
}
/* page is not bound with outstanding tblk:
* init write or mark it to be redriven (lbmWRITE)
*/
else {
/* finalize the page */
bp->l_ceor = bp->l_eor;
lp->h.eor = lp->t.eor = cpu_to_le16(bp->l_ceor);
lbmWrite(log, bp, lbmWRITE | lbmRELEASE | lbmFREE, 0);
}
LOGGC_UNLOCK(log);
/*
* allocate/initialize next page
*/
/* if log wraps, the first data page of log is 2
* (0 never used, 1 is superblock).
*/
log->page = (pn == log->size - 1) ? 2 : pn + 1;
log->eor = LOGPHDRSIZE; /* ? valid page empty/full at logRedo() */
/* allocate/initialize next log page buffer */
nextbp = lbmAllocate(log, log->page);
nextbp->l_eor = log->eor;
log->bp = nextbp;
/* initialize next log page */
lp = (struct logpage *) nextbp->l_ldata;
lp->h.page = lp->t.page = cpu_to_le32(lspn + 1);
lp->h.eor = lp->t.eor = cpu_to_le16(LOGPHDRSIZE);
return 0;
}
/*
* NAME: lmGroupCommit()
*
* FUNCTION: group commit
* initiate pageout of the pages with COMMIT in the order of
* page number - redrive pageout of the page at the head of
* pageout queue until full page has been written.
*
* RETURN:
*
* NOTE:
* LOGGC_LOCK serializes log group commit queue, and
* transaction blocks on the commit queue.
* N.B. LOG_LOCK is NOT held during lmGroupCommit().
*/
int lmGroupCommit(struct jfs_log * log, struct tblock * tblk)
{
int rc = 0;
LOGGC_LOCK(log);
/* group committed already ? */
if (tblk->flag & tblkGC_COMMITTED) {
if (tblk->flag & tblkGC_ERROR)
rc = -EIO;
LOGGC_UNLOCK(log);
return rc;
}
jfs_info("lmGroup Commit: tblk = 0x%p, gcrtc = %d", tblk, log->gcrtc);
if (tblk->xflag & COMMIT_LAZY)
tblk->flag |= tblkGC_LAZY;
if ((!(log->cflag & logGC_PAGEOUT)) && (!list_empty(&log->cqueue)) &&
(!(tblk->xflag & COMMIT_LAZY) || test_bit(log_FLUSH, &log->flag)
|| jfs_tlocks_low)) {
/*
* No pageout in progress
*
* start group commit as its group leader.
*/
log->cflag |= logGC_PAGEOUT;
lmGCwrite(log, 0);
}
if (tblk->xflag & COMMIT_LAZY) {
/*
* Lazy transactions can leave now
*/
LOGGC_UNLOCK(log);
return 0;
}
/* lmGCwrite gives up LOGGC_LOCK, check again */
if (tblk->flag & tblkGC_COMMITTED) {
if (tblk->flag & tblkGC_ERROR)
rc = -EIO;
LOGGC_UNLOCK(log);
return rc;
}
/* upcount transaction waiting for completion
*/
log->gcrtc++;
tblk->flag |= tblkGC_READY;
__SLEEP_COND(tblk->gcwait, (tblk->flag & tblkGC_COMMITTED),
LOGGC_LOCK(log), LOGGC_UNLOCK(log));
/* removed from commit queue */
if (tblk->flag & tblkGC_ERROR)
rc = -EIO;
LOGGC_UNLOCK(log);
return rc;
}
/*
* NAME: lmGCwrite()
*
* FUNCTION: group commit write
* initiate write of log page, building a group of all transactions
* with commit records on that page.
*
* RETURN: None
*
* NOTE:
* LOGGC_LOCK must be held by caller.
* N.B. LOG_LOCK is NOT held during lmGroupCommit().
*/
static void lmGCwrite(struct jfs_log * log, int cant_write)
{
struct lbuf *bp;
struct logpage *lp;
int gcpn; /* group commit page number */
struct tblock *tblk;
struct tblock *xtblk = NULL;
/*
* build the commit group of a log page
*
* scan commit queue and make a commit group of all
* transactions with COMMIT records on the same log page.
*/
/* get the head tblk on the commit queue */
gcpn = list_entry(log->cqueue.next, struct tblock, cqueue)->pn;
list_for_each_entry(tblk, &log->cqueue, cqueue) {
if (tblk->pn != gcpn)
break;
xtblk = tblk;
/* state transition: (QUEUE, READY) -> COMMIT */
tblk->flag |= tblkGC_COMMIT;
}
tblk = xtblk; /* last tblk of the page */
/*
* pageout to commit transactions on the log page.
*/
bp = (struct lbuf *) tblk->bp;
lp = (struct logpage *) bp->l_ldata;
/* is page already full ? */
if (tblk->flag & tblkGC_EOP) {
/* mark page to free at end of group commit of the page */
tblk->flag &= ~tblkGC_EOP;
tblk->flag |= tblkGC_FREE;
bp->l_ceor = bp->l_eor;
lp->h.eor = lp->t.eor = cpu_to_le16(bp->l_ceor);
lbmWrite(log, bp, lbmWRITE | lbmRELEASE | lbmGC,
cant_write);
INCREMENT(lmStat.full_page);
}
/* page is not yet full */
else {
bp->l_ceor = tblk->eor; /* ? bp->l_ceor = bp->l_eor; */
lp->h.eor = lp->t.eor = cpu_to_le16(bp->l_ceor);
lbmWrite(log, bp, lbmWRITE | lbmGC, cant_write);
INCREMENT(lmStat.partial_page);
}
}
/*
* NAME: lmPostGC()
*
* FUNCTION: group commit post-processing
* Processes transactions after their commit records have been written
* to disk, redriving log I/O if necessary.
*
* RETURN: None
*
* NOTE:
* This routine is called a interrupt time by lbmIODone
*/
static void lmPostGC(struct lbuf * bp)
{
unsigned long flags;
struct jfs_log *log = bp->l_log;
struct logpage *lp;
struct tblock *tblk, *temp;
//LOGGC_LOCK(log);
spin_lock_irqsave(&log->gclock, flags);
/*
* current pageout of group commit completed.
*
* remove/wakeup transactions from commit queue who were
* group committed with the current log page
*/
list_for_each_entry_safe(tblk, temp, &log->cqueue, cqueue) {
if (!(tblk->flag & tblkGC_COMMIT))
break;
/* if transaction was marked GC_COMMIT then
* it has been shipped in the current pageout
* and made it to disk - it is committed.
*/
if (bp->l_flag & lbmERROR)
tblk->flag |= tblkGC_ERROR;
/* remove it from the commit queue */
list_del(&tblk->cqueue);
tblk->flag &= ~tblkGC_QUEUE;
if (tblk == log->flush_tblk) {
/* we can stop flushing the log now */
clear_bit(log_FLUSH, &log->flag);
log->flush_tblk = NULL;
}
jfs_info("lmPostGC: tblk = 0x%p, flag = 0x%x", tblk,
tblk->flag);
if (!(tblk->xflag & COMMIT_FORCE))
/*
* Hand tblk over to lazy commit thread
*/
txLazyUnlock(tblk);
else {
/* state transition: COMMIT -> COMMITTED */
tblk->flag |= tblkGC_COMMITTED;
if (tblk->flag & tblkGC_READY)
log->gcrtc--;
LOGGC_WAKEUP(tblk);
}
/* was page full before pageout ?
* (and this is the last tblk bound with the page)
*/
if (tblk->flag & tblkGC_FREE)
lbmFree(bp);
/* did page become full after pageout ?
* (and this is the last tblk bound with the page)
*/
else if (tblk->flag & tblkGC_EOP) {
/* finalize the page */
lp = (struct logpage *) bp->l_ldata;
bp->l_ceor = bp->l_eor;
lp->h.eor = lp->t.eor = cpu_to_le16(bp->l_eor);
jfs_info("lmPostGC: calling lbmWrite");
lbmWrite(log, bp, lbmWRITE | lbmRELEASE | lbmFREE,
1);
}
}
/* are there any transactions who have entered lnGroupCommit()
* (whose COMMITs are after that of the last log page written.
* They are waiting for new group commit (above at (SLEEP 1))
* or lazy transactions are on a full (queued) log page,
* select the latest ready transaction as new group leader and
* wake her up to lead her group.
*/
if ((!list_empty(&log->cqueue)) &&
((log->gcrtc > 0) || (tblk->bp->l_wqnext != NULL) ||
test_bit(log_FLUSH, &log->flag) || jfs_tlocks_low))
/*
* Call lmGCwrite with new group leader
*/
lmGCwrite(log, 1);
/* no transaction are ready yet (transactions are only just
* queued (GC_QUEUE) and not entered for group commit yet).
* the first transaction entering group commit
* will elect herself as new group leader.
*/
else
log->cflag &= ~logGC_PAGEOUT;
//LOGGC_UNLOCK(log);
spin_unlock_irqrestore(&log->gclock, flags);
return;
}
/*
* NAME: lmLogSync()
*
* FUNCTION: write log SYNCPT record for specified log
* if new sync address is available
* (normally the case if sync() is executed by back-ground
* process).
* calculate new value of i_nextsync which determines when
* this code is called again.
*
* PARAMETERS: log - log structure
* hard_sync - 1 to force all metadata to be written
*
* RETURN: 0
*
* serialization: LOG_LOCK() held on entry/exit
*/
static int lmLogSync(struct jfs_log * log, int hard_sync)
{
int logsize;
int written; /* written since last syncpt */
int free; /* free space left available */
int delta; /* additional delta to write normally */
int more; /* additional write granted */
struct lrd lrd;
int lsn;
struct logsyncblk *lp;
unsigned long flags;
/* push dirty metapages out to disk */
if (hard_sync)
write_special_inodes(log, filemap_fdatawrite);
else
write_special_inodes(log, filemap_flush);
/*
* forward syncpt
*/
/* if last sync is same as last syncpt,
* invoke sync point forward processing to update sync.
*/
if (log->sync == log->syncpt) {
LOGSYNC_LOCK(log, flags);
if (list_empty(&log->synclist))
log->sync = log->lsn;
else {
lp = list_entry(log->synclist.next,
struct logsyncblk, synclist);
log->sync = lp->lsn;
}
LOGSYNC_UNLOCK(log, flags);
}
/* if sync is different from last syncpt,
* write a SYNCPT record with syncpt = sync.
* reset syncpt = sync
*/
if (log->sync != log->syncpt) {
lrd.logtid = 0;
lrd.backchain = 0;
lrd.type = cpu_to_le16(LOG_SYNCPT);
lrd.length = 0;
lrd.log.syncpt.sync = cpu_to_le32(log->sync);
lsn = lmWriteRecord(log, NULL, &lrd, NULL);
log->syncpt = log->sync;
} else
lsn = log->lsn;
/*
* setup next syncpt trigger (SWAG)
*/
logsize = log->logsize;
logdiff(written, lsn, log);
]
]
|
| 192/2 |
2026/05/12 00:34 |
llm |
fixes-finder |
0m
Model:
Tokens:
input: 71758
output: 20
thoughts: 33
Thoughts: Here's my take on those thoughts:
**Navigating the JFS Source Code**
Okay, so I'm trying to track down where `jfs_flush_journal` is defined. I know it's related to the JFS filesystem, so my initial instinct is to start digging around in the kernel's file system code. Let's see... I'm pretty sure I saw something about it recently... aha! It's in `fs/jfs/jfs_logmgr.c`. Right, that makes perfect sense. Now, let's go directly to that file and see what we can learn! It's time to fire up my editor and take a look.
|
| 193/2 |
2026/05/12 00:34 |
tool |
grepper |
0m
Args: map[Expression:jfs_flush_journal]
Results: map[Output:fs/jfs/file.c=20=int jfs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
--
fs/jfs/file.c-32- /* Make sure committed changes hit the disk */
fs/jfs/file.c:33: jfs_flush_journal(JFS_SBI(inode->i_sb)->log, 1);
fs/jfs/file.c-34- inode_unlock(inode);
--
fs/jfs/inode.c=121=int jfs_write_inode(struct inode *inode, struct writeback_control *wbc)
--
fs/jfs/inode.c-133- /* Make sure committed changes hit the disk */
fs/jfs/inode.c:134: jfs_flush_journal(JFS_SBI(inode->i_sb)->log, wait);
fs/jfs/inode.c-135- return 0;
--
fs/jfs/jfs_logmgr.c=919=static int lmLogSync(struct jfs_log * log, int hard_sync)
--
fs/jfs/jfs_logmgr.c-1021- */
fs/jfs/jfs_logmgr.c:1022: jfs_flush_journal(log, 0);
fs/jfs/jfs_logmgr.c-1023- }
--
fs/jfs/jfs_logmgr.c=1432=int lmLogClose(struct super_block *sb)
--
fs/jfs/jfs_logmgr.c-1496-/*
fs/jfs/jfs_logmgr.c:1497: * NAME: jfs_flush_journal()
fs/jfs/jfs_logmgr.c-1498- *
--
fs/jfs/jfs_logmgr.c-1505- */
fs/jfs/jfs_logmgr.c:1506:void jfs_flush_journal(struct jfs_log *log, int wait)
fs/jfs/jfs_logmgr.c-1507-{
--
fs/jfs/jfs_logmgr.c-1514-
fs/jfs/jfs_logmgr.c:1515: jfs_info("jfs_flush_journal: log:0x%p wait=%d", log, wait);
fs/jfs/jfs_logmgr.c-1516-
--
fs/jfs/jfs_logmgr.c-1590-
fs/jfs/jfs_logmgr.c:1591: printk(KERN_ERR "jfs_flush_journal: synclist not empty\n");
fs/jfs/jfs_logmgr.c-1592- list_for_each_entry(lp, &log->synclist, synclist) {
--
fs/jfs/jfs_logmgr.c=1628=int lmLogShutdown(struct jfs_log * log)
--
fs/jfs/jfs_logmgr.c-1639-
fs/jfs/jfs_logmgr.c:1640: jfs_flush_journal(log, 2);
fs/jfs/jfs_logmgr.c-1641-
--
fs/jfs/jfs_logmgr.h=503=extern int jfsIOWait(void *);
fs/jfs/jfs_logmgr.h:504:extern void jfs_flush_journal(struct jfs_log * log, int wait);
fs/jfs/jfs_logmgr.h-505-extern void jfs_syncpt(struct jfs_log *log, int hard_sync);
--
fs/jfs/jfs_metapage.c=424=static int metapage_write_folio(struct folio *folio,
--
fs/jfs/jfs_metapage.c-462- if (mp->log && !(mp->log->cflag & logGC_PAGEOUT))
fs/jfs/jfs_metapage.c:463: jfs_flush_journal(mp->log, 0);
fs/jfs/jfs_metapage.c-464- continue;
--
fs/jfs/jfs_txnmgr.c=2813=void txQuiesce(struct super_block *sb)
--
fs/jfs/jfs_txnmgr.c-2860- */
fs/jfs/jfs_txnmgr.c:2861: jfs_flush_journal(log, 0);
fs/jfs/jfs_txnmgr.c-2862-}
--
fs/jfs/jfs_umount.c=38=int jfs_umount(struct super_block *sb)
--
fs/jfs/jfs_umount.c-58- */
fs/jfs/jfs_umount.c:59: jfs_flush_journal(log, 2);
fs/jfs/jfs_umount.c-60-
--
fs/jfs/jfs_umount.c=131=int jfs_umount_rw(struct super_block *sb)
--
fs/jfs/jfs_umount.c-143- */
fs/jfs/jfs_umount.c:144: jfs_flush_journal(log, 2);
fs/jfs/jfs_umount.c-145-
--
fs/jfs/super.c=638=static int jfs_sync_fs(struct super_block *sb, int wait)
--
fs/jfs/super.c-648- dquot_writeback_dquots(sb, -1);
fs/jfs/super.c:649: jfs_flush_journal(log, wait);
fs/jfs/super.c-650- jfs_syncpt(log, 0);
]
|
| 194/2 |
2026/05/12 00:34 |
llm |
fixes-finder |
0m
Model:
Tokens:
input: 73488
output: 40
thoughts: 99
Thoughts: Okay, let me think this through.
**Analyzing a Potential Journaling Change**
Alright, hold on a second. I'm noticing a change in `jfs_flush_journal`. Specifically, in commit `1c8007b0769d37aa5fcb343b383b0af89ade2f71`, it went from `jfs_flush_journal(log, 1)` to `jfs_flush_journal(log, 2)`. That "wait" argument is what's catching my eye. Let's see... I need to refresh my understanding of what `wait=2` signifies within that function. I'm guessing that the change in the wait parameter has a significant impact on performance, or guarantees. Let's dig into that `jfs_flush_journal` implementation and figure out what the implications of that "2" are. Need to understand the semantics, and the likely reason for that modification.
|
| 195/2 |
2026/05/12 00:34 |
tool |
git-show |
0m
Args: map[Commit:1c8007b0769d:fs/jfs/jfs_logmgr.c]
Results: map[Output:
Full output is too long, showing 1000 out of 2529 lines.
[/*
* Copyright (C) International Business Machines Corp., 2000-2004
* Portions Copyright (C) Christoph Hellwig, 2001-2002
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
* the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* jfs_logmgr.c: log manager
*
* for related information, see transaction manager (jfs_txnmgr.c), and
* recovery manager (jfs_logredo.c).
*
* note: for detail, RTFS.
*
* log buffer manager:
* special purpose buffer manager supporting log i/o requirements.
* per log serial pageout of logpage
* queuing i/o requests and redrive i/o at iodone
* maintain current logpage buffer
* no caching since append only
* appropriate jfs buffer cache buffers as needed
*
* group commit:
* transactions which wrote COMMIT records in the same in-memory
* log page during the pageout of previous/current log page(s) are
* committed together by the pageout of the page.
*
* TBD lazy commit:
* transactions are committed asynchronously when the log page
* containing it COMMIT is paged out when it becomes full;
*
* serialization:
* . a per log lock serialize log write.
* . a per log lock serialize group commit.
* . a per log lock serialize log open/close;
*
* TBD log integrity:
* careful-write (ping-pong) of last logpage to recover from crash
* in overwrite.
* detection of split (out-of-order) write of physical sectors
* of last logpage via timestamp at end of each sector
* with its mirror data array at trailer).
*
* alternatives:
* lsn - 64-bit monotonically increasing integer vs
* 32-bit lspn and page eor.
*/
#include <linux/fs.h>
#include <linux/blkdev.h>
#include <linux/interrupt.h>
#include <linux/completion.h>
#include <linux/kthread.h>
#include <linux/buffer_head.h> /* for sync_blockdev() */
#include <linux/bio.h>
#include <linux/freezer.h>
#include <linux/delay.h>
#include <linux/mutex.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
#include "jfs_incore.h"
#include "jfs_filsys.h"
#include "jfs_metapage.h"
#include "jfs_superblock.h"
#include "jfs_txnmgr.h"
#include "jfs_debug.h"
/*
* lbuf's ready to be redriven. Protected by log_redrive_lock (jfsIO thread)
*/
static struct lbuf *log_redrive_list;
static DEFINE_SPINLOCK(log_redrive_lock);
/*
* log read/write serialization (per log)
*/
#define LOG_LOCK_INIT(log) mutex_init(&(log)->loglock)
#define LOG_LOCK(log) mutex_lock(&((log)->loglock))
#define LOG_UNLOCK(log) mutex_unlock(&((log)->loglock))
/*
* log group commit serialization (per log)
*/
#define LOGGC_LOCK_INIT(log) spin_lock_init(&(log)->gclock)
#define LOGGC_LOCK(log) spin_lock_irq(&(log)->gclock)
#define LOGGC_UNLOCK(log) spin_unlock_irq(&(log)->gclock)
#define LOGGC_WAKEUP(tblk) wake_up_all(&(tblk)->gcwait)
/*
* log sync serialization (per log)
*/
#define LOGSYNC_DELTA(logsize) min((logsize)/8, 128*LOGPSIZE)
#define LOGSYNC_BARRIER(logsize) ((logsize)/4)
/*
#define LOGSYNC_DELTA(logsize) min((logsize)/4, 256*LOGPSIZE)
#define LOGSYNC_BARRIER(logsize) ((logsize)/2)
*/
/*
* log buffer cache synchronization
*/
static DEFINE_SPINLOCK(jfsLCacheLock);
#define LCACHE_LOCK(flags) spin_lock_irqsave(&jfsLCacheLock, flags)
#define LCACHE_UNLOCK(flags) spin_unlock_irqrestore(&jfsLCacheLock, flags)
/*
* See __SLEEP_COND in jfs_locks.h
*/
#define LCACHE_SLEEP_COND(wq, cond, flags) \
do { \
if (cond) \
break; \
__SLEEP_COND(wq, cond, LCACHE_LOCK(flags), LCACHE_UNLOCK(flags)); \
} while (0)
#define LCACHE_WAKEUP(event) wake_up(event)
/*
* lbuf buffer cache (lCache) control
*/
/* log buffer manager pageout control (cumulative, inclusive) */
#define lbmREAD 0x0001
#define lbmWRITE 0x0002 /* enqueue at tail of write queue;
* init pageout if at head of queue;
*/
#define lbmRELEASE 0x0004 /* remove from write queue
* at completion of pageout;
* do not free/recycle it yet:
* caller will free it;
*/
#define lbmSYNC 0x0008 /* do not return to freelist
* when removed from write queue;
*/
#define lbmFREE 0x0010 /* return to freelist
* at completion of pageout;
* the buffer may be recycled;
*/
#define lbmDONE 0x0020
#define lbmERROR 0x0040
#define lbmGC 0x0080 /* lbmIODone to perform post-GC processing
* of log page
*/
#define lbmDIRECT 0x0100
/*
* Global list of active external journals
*/
static LIST_HEAD(jfs_external_logs);
static struct jfs_log *dummy_log = NULL;
static DEFINE_MUTEX(jfs_log_mutex);
/*
* forward references
*/
static int lmWriteRecord(struct jfs_log * log, struct tblock * tblk,
struct lrd * lrd, struct tlock * tlck);
static int lmNextPage(struct jfs_log * log);
static int lmLogFileSystem(struct jfs_log * log, struct jfs_sb_info *sbi,
int activate);
static int open_inline_log(struct super_block *sb);
static int open_dummy_log(struct super_block *sb);
static int lbmLogInit(struct jfs_log * log);
static void lbmLogShutdown(struct jfs_log * log);
static struct lbuf *lbmAllocate(struct jfs_log * log, int);
static void lbmFree(struct lbuf * bp);
static void lbmfree(struct lbuf * bp);
static int lbmRead(struct jfs_log * log, int pn, struct lbuf ** bpp);
static void lbmWrite(struct jfs_log * log, struct lbuf * bp, int flag, int cant_block);
static void lbmDirectWrite(struct jfs_log * log, struct lbuf * bp, int flag);
static int lbmIOWait(struct lbuf * bp, int flag);
static bio_end_io_t lbmIODone;
static void lbmStartIO(struct lbuf * bp);
static void lmGCwrite(struct jfs_log * log, int cant_block);
static int lmLogSync(struct jfs_log * log, int hard_sync);
/*
* statistics
*/
#ifdef CONFIG_JFS_STATISTICS
static struct lmStat {
uint commit; /* # of commit */
uint pagedone; /* # of page written */
uint submitted; /* # of pages submitted */
uint full_page; /* # of full pages submitted */
uint partial_page; /* # of partial pages submitted */
} lmStat;
#endif
static void write_special_inodes(struct jfs_log *log,
int (*writer)(struct address_space *))
{
struct jfs_sb_info *sbi;
list_for_each_entry(sbi, &log->sb_list, log_list) {
writer(sbi->ipbmap->i_mapping);
writer(sbi->ipimap->i_mapping);
writer(sbi->direct_inode->i_mapping);
}
}
/*
* NAME: lmLog()
*
* FUNCTION: write a log record;
*
* PARAMETER:
*
* RETURN: lsn - offset to the next log record to write (end-of-log);
* -1 - error;
*
* note: todo: log error handler
*/
int lmLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
struct tlock * tlck)
{
int lsn;
int diffp, difft;
struct metapage *mp = NULL;
unsigned long flags;
jfs_info("lmLog: log:0x%p tblk:0x%p, lrd:0x%p tlck:0x%p",
log, tblk, lrd, tlck);
LOG_LOCK(log);
/* log by (out-of-transaction) JFS ? */
if (tblk == NULL)
goto writeRecord;
/* log from page ? */
if (tlck == NULL ||
tlck->type & tlckBTROOT || (mp = tlck->mp) == NULL)
goto writeRecord;
/*
* initialize/update page/transaction recovery lsn
*/
lsn = log->lsn;
LOGSYNC_LOCK(log, flags);
/*
* initialize page lsn if first log write of the page
*/
if (mp->lsn == 0) {
mp->log = log;
mp->lsn = lsn;
log->count++;
/* insert page at tail of logsynclist */
list_add_tail(&mp->synclist, &log->synclist);
}
/*
* initialize/update lsn of tblock of the page
*
* transaction inherits oldest lsn of pages associated
* with allocation/deallocation of resources (their
* log records are used to reconstruct allocation map
* at recovery time: inode for inode allocation map,
* B+-tree index of extent descriptors for block
* allocation map);
* allocation map pages inherit transaction lsn at
* commit time to allow forwarding log syncpt past log
* records associated with allocation/deallocation of
* resources only after persistent map of these map pages
* have been updated and propagated to home.
*/
/*
* initialize transaction lsn:
*/
if (tblk->lsn == 0) {
/* inherit lsn of its first page logged */
tblk->lsn = mp->lsn;
log->count++;
/* insert tblock after the page on logsynclist */
list_add(&tblk->synclist, &mp->synclist);
}
/*
* update transaction lsn:
*/
else {
/* inherit oldest/smallest lsn of page */
logdiff(diffp, mp->lsn, log);
logdiff(difft, tblk->lsn, log);
if (diffp < difft) {
/* update tblock lsn with page lsn */
tblk->lsn = mp->lsn;
/* move tblock after page on logsynclist */
list_move(&tblk->synclist, &mp->synclist);
}
}
LOGSYNC_UNLOCK(log, flags);
/*
* write the log record
*/
writeRecord:
lsn = lmWriteRecord(log, tblk, lrd, tlck);
/*
* forward log syncpt if log reached next syncpt trigger
*/
logdiff(diffp, lsn, log);
if (diffp >= log->nextsync)
lsn = lmLogSync(log, 0);
/* update end-of-log lsn */
log->lsn = lsn;
LOG_UNLOCK(log);
/* return end-of-log address */
return lsn;
}
/*
* NAME: lmWriteRecord()
*
* FUNCTION: move the log record to current log page
*
* PARAMETER: cd - commit descriptor
*
* RETURN: end-of-log address
*
* serialization: LOG_LOCK() held on entry/exit
*/
static int
lmWriteRecord(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
struct tlock * tlck)
{
int lsn = 0; /* end-of-log address */
struct lbuf *bp; /* dst log page buffer */
struct logpage *lp; /* dst log page */
caddr_t dst; /* destination address in log page */
int dstoffset; /* end-of-log offset in log page */
int freespace; /* free space in log page */
caddr_t p; /* src meta-data page */
caddr_t src;
int srclen;
int nbytes; /* number of bytes to move */
int i;
int len;
struct linelock *linelock;
struct lv *lv;
struct lvd *lvd;
int l2linesize;
len = 0;
/* retrieve destination log page to write */
bp = (struct lbuf *) log->bp;
lp = (struct logpage *) bp->l_ldata;
dstoffset = log->eor;
/* any log data to write ? */
if (tlck == NULL)
goto moveLrd;
/*
* move log record data
*/
/* retrieve source meta-data page to log */
if (tlck->flag & tlckPAGELOCK) {
p = (caddr_t) (tlck->mp->data);
linelock = (struct linelock *) & tlck->lock;
}
/* retrieve source in-memory inode to log */
else if (tlck->flag & tlckINODELOCK) {
if (tlck->type & tlckDTREE)
p = (caddr_t) &JFS_IP(tlck->ip)->i_dtroot;
else
p = (caddr_t) &JFS_IP(tlck->ip)->i_xtroot;
linelock = (struct linelock *) & tlck->lock;
}
#ifdef _JFS_WIP
else if (tlck->flag & tlckINLINELOCK) {
inlinelock = (struct inlinelock *) & tlck;
p = (caddr_t) & inlinelock->pxd;
linelock = (struct linelock *) & tlck;
}
#endif /* _JFS_WIP */
else {
jfs_err("lmWriteRecord: UFO tlck:0x%p", tlck);
return 0; /* Probably should trap */
}
l2linesize = linelock->l2linesize;
moveData:
ASSERT(linelock->index <= linelock->maxcnt);
lv = linelock->lv;
for (i = 0; i < linelock->index; i++, lv++) {
if (lv->length == 0)
continue;
/* is page full ? */
if (dstoffset >= LOGPSIZE - LOGPTLRSIZE) {
/* page become full: move on to next page */
lmNextPage(log);
bp = log->bp;
lp = (struct logpage *) bp->l_ldata;
dstoffset = LOGPHDRSIZE;
}
/*
* move log vector data
*/
src = (u8 *) p + (lv->offset << l2linesize);
srclen = lv->length << l2linesize;
len += srclen;
while (srclen > 0) {
freespace = (LOGPSIZE - LOGPTLRSIZE) - dstoffset;
nbytes = min(freespace, srclen);
dst = (caddr_t) lp + dstoffset;
memcpy(dst, src, nbytes);
dstoffset += nbytes;
/* is page not full ? */
if (dstoffset < LOGPSIZE - LOGPTLRSIZE)
break;
/* page become full: move on to next page */
lmNextPage(log);
bp = (struct lbuf *) log->bp;
lp = (struct logpage *) bp->l_ldata;
dstoffset = LOGPHDRSIZE;
srclen -= nbytes;
src += nbytes;
}
/*
* move log vector descriptor
*/
len += 4;
lvd = (struct lvd *) ((caddr_t) lp + dstoffset);
lvd->offset = cpu_to_le16(lv->offset);
lvd->length = cpu_to_le16(lv->length);
dstoffset += 4;
jfs_info("lmWriteRecord: lv offset:%d length:%d",
lv->offset, lv->length);
}
if ((i = linelock->next)) {
linelock = (struct linelock *) lid_to_tlock(i);
goto moveData;
}
/*
* move log record descriptor
*/
moveLrd:
lrd->length = cpu_to_le16(len);
src = (caddr_t) lrd;
srclen = LOGRDSIZE;
while (srclen > 0) {
freespace = (LOGPSIZE - LOGPTLRSIZE) - dstoffset;
nbytes = min(freespace, srclen);
dst = (caddr_t) lp + dstoffset;
memcpy(dst, src, nbytes);
dstoffset += nbytes;
srclen -= nbytes;
/* are there more to move than freespace of page ? */
if (srclen)
goto pageFull;
/*
* end of log record descriptor
*/
/* update last log record eor */
log->eor = dstoffset;
bp->l_eor = dstoffset;
lsn = (log->page << L2LOGPSIZE) + dstoffset;
if (lrd->type & cpu_to_le16(LOG_COMMIT)) {
tblk->clsn = lsn;
jfs_info("wr: tclsn:0x%x, beor:0x%x", tblk->clsn,
bp->l_eor);
INCREMENT(lmStat.commit); /* # of commit */
/*
* enqueue tblock for group commit:
*
* enqueue tblock of non-trivial/synchronous COMMIT
* at tail of group commit queue
* (trivial/asynchronous COMMITs are ignored by
* group commit.)
*/
LOGGC_LOCK(log);
/* init tblock gc state */
tblk->flag = tblkGC_QUEUE;
tblk->bp = log->bp;
tblk->pn = log->page;
tblk->eor = log->eor;
/* enqueue transaction to commit queue */
list_add_tail(&tblk->cqueue, &log->cqueue);
LOGGC_UNLOCK(log);
}
jfs_info("lmWriteRecord: lrd:0x%04x bp:0x%p pn:%d eor:0x%x",
le16_to_cpu(lrd->type), log->bp, log->page, dstoffset);
/* page not full ? */
if (dstoffset < LOGPSIZE - LOGPTLRSIZE)
return lsn;
pageFull:
/* page become full: move on to next page */
lmNextPage(log);
bp = (struct lbuf *) log->bp;
lp = (struct logpage *) bp->l_ldata;
dstoffset = LOGPHDRSIZE;
src += nbytes;
}
return lsn;
}
/*
* NAME: lmNextPage()
*
* FUNCTION: write current page and allocate next page.
*
* PARAMETER: log
*
* RETURN: 0
*
* serialization: LOG_LOCK() held on entry/exit
*/
static int lmNextPage(struct jfs_log * log)
{
struct logpage *lp;
int lspn; /* log sequence page number */
int pn; /* current page number */
struct lbuf *bp;
struct lbuf *nextbp;
struct tblock *tblk;
/* get current log page number and log sequence page number */
pn = log->page;
bp = log->bp;
lp = (struct logpage *) bp->l_ldata;
lspn = le32_to_cpu(lp->h.page);
LOGGC_LOCK(log);
/*
* write or queue the full page at the tail of write queue
*/
/* get the tail tblk on commit queue */
if (list_empty(&log->cqueue))
tblk = NULL;
else
tblk = list_entry(log->cqueue.prev, struct tblock, cqueue);
/* every tblk who has COMMIT record on the current page,
* and has not been committed, must be on commit queue
* since tblk is queued at commit queueu at the time
* of writing its COMMIT record on the page before
* page becomes full (even though the tblk thread
* who wrote COMMIT record may have been suspended
* currently);
*/
/* is page bound with outstanding tail tblk ? */
if (tblk && tblk->pn == pn) {
/* mark tblk for end-of-page */
tblk->flag |= tblkGC_EOP;
if (log->cflag & logGC_PAGEOUT) {
/* if page is not already on write queue,
* just enqueue (no lbmWRITE to prevent redrive)
* buffer to wqueue to ensure correct serial order
* of the pages since log pages will be added
* continuously
*/
if (bp->l_wqnext == NULL)
lbmWrite(log, bp, 0, 0);
} else {
/*
* No current GC leader, initiate group commit
*/
log->cflag |= logGC_PAGEOUT;
lmGCwrite(log, 0);
}
}
/* page is not bound with outstanding tblk:
* init write or mark it to be redriven (lbmWRITE)
*/
else {
/* finalize the page */
bp->l_ceor = bp->l_eor;
lp->h.eor = lp->t.eor = cpu_to_le16(bp->l_ceor);
lbmWrite(log, bp, lbmWRITE | lbmRELEASE | lbmFREE, 0);
}
LOGGC_UNLOCK(log);
/*
* allocate/initialize next page
*/
/* if log wraps, the first data page of log is 2
* (0 never used, 1 is superblock).
*/
log->page = (pn == log->size - 1) ? 2 : pn + 1;
log->eor = LOGPHDRSIZE; /* ? valid page empty/full at logRedo() */
/* allocate/initialize next log page buffer */
nextbp = lbmAllocate(log, log->page);
nextbp->l_eor = log->eor;
log->bp = nextbp;
/* initialize next log page */
lp = (struct logpage *) nextbp->l_ldata;
lp->h.page = lp->t.page = cpu_to_le32(lspn + 1);
lp->h.eor = lp->t.eor = cpu_to_le16(LOGPHDRSIZE);
return 0;
}
/*
* NAME: lmGroupCommit()
*
* FUNCTION: group commit
* initiate pageout of the pages with COMMIT in the order of
* page number - redrive pageout of the page at the head of
* pageout queue until full page has been written.
*
* RETURN:
*
* NOTE:
* LOGGC_LOCK serializes log group commit queue, and
* transaction blocks on the commit queue.
* N.B. LOG_LOCK is NOT held during lmGroupCommit().
*/
int lmGroupCommit(struct jfs_log * log, struct tblock * tblk)
{
int rc = 0;
LOGGC_LOCK(log);
/* group committed already ? */
if (tblk->flag & tblkGC_COMMITTED) {
if (tblk->flag & tblkGC_ERROR)
rc = -EIO;
LOGGC_UNLOCK(log);
return rc;
}
jfs_info("lmGroup Commit: tblk = 0x%p, gcrtc = %d", tblk, log->gcrtc);
if (tblk->xflag & COMMIT_LAZY)
tblk->flag |= tblkGC_LAZY;
if ((!(log->cflag & logGC_PAGEOUT)) && (!list_empty(&log->cqueue)) &&
(!(tblk->xflag & COMMIT_LAZY) || test_bit(log_FLUSH, &log->flag)
|| jfs_tlocks_low)) {
/*
* No pageout in progress
*
* start group commit as its group leader.
*/
log->cflag |= logGC_PAGEOUT;
lmGCwrite(log, 0);
}
if (tblk->xflag & COMMIT_LAZY) {
/*
* Lazy transactions can leave now
*/
LOGGC_UNLOCK(log);
return 0;
}
/* lmGCwrite gives up LOGGC_LOCK, check again */
if (tblk->flag & tblkGC_COMMITTED) {
if (tblk->flag & tblkGC_ERROR)
rc = -EIO;
LOGGC_UNLOCK(log);
return rc;
}
/* upcount transaction waiting for completion
*/
log->gcrtc++;
tblk->flag |= tblkGC_READY;
__SLEEP_COND(tblk->gcwait, (tblk->flag & tblkGC_COMMITTED),
LOGGC_LOCK(log), LOGGC_UNLOCK(log));
/* removed from commit queue */
if (tblk->flag & tblkGC_ERROR)
rc = -EIO;
LOGGC_UNLOCK(log);
return rc;
}
/*
* NAME: lmGCwrite()
*
* FUNCTION: group commit write
* initiate write of log page, building a group of all transactions
* with commit records on that page.
*
* RETURN: None
*
* NOTE:
* LOGGC_LOCK must be held by caller.
* N.B. LOG_LOCK is NOT held during lmGroupCommit().
*/
static void lmGCwrite(struct jfs_log * log, int cant_write)
{
struct lbuf *bp;
struct logpage *lp;
int gcpn; /* group commit page number */
struct tblock *tblk;
struct tblock *xtblk = NULL;
/*
* build the commit group of a log page
*
* scan commit queue and make a commit group of all
* transactions with COMMIT records on the same log page.
*/
/* get the head tblk on the commit queue */
gcpn = list_entry(log->cqueue.next, struct tblock, cqueue)->pn;
list_for_each_entry(tblk, &log->cqueue, cqueue) {
if (tblk->pn != gcpn)
break;
xtblk = tblk;
/* state transition: (QUEUE, READY) -> COMMIT */
tblk->flag |= tblkGC_COMMIT;
}
tblk = xtblk; /* last tblk of the page */
/*
* pageout to commit transactions on the log page.
*/
bp = (struct lbuf *) tblk->bp;
lp = (struct logpage *) bp->l_ldata;
/* is page already full ? */
if (tblk->flag & tblkGC_EOP) {
/* mark page to free at end of group commit of the page */
tblk->flag &= ~tblkGC_EOP;
tblk->flag |= tblkGC_FREE;
bp->l_ceor = bp->l_eor;
lp->h.eor = lp->t.eor = cpu_to_le16(bp->l_ceor);
lbmWrite(log, bp, lbmWRITE | lbmRELEASE | lbmGC,
cant_write);
INCREMENT(lmStat.full_page);
}
/* page is not yet full */
else {
bp->l_ceor = tblk->eor; /* ? bp->l_ceor = bp->l_eor; */
lp->h.eor = lp->t.eor = cpu_to_le16(bp->l_ceor);
lbmWrite(log, bp, lbmWRITE | lbmGC, cant_write);
INCREMENT(lmStat.partial_page);
}
}
/*
* NAME: lmPostGC()
*
* FUNCTION: group commit post-processing
* Processes transactions after their commit records have been written
* to disk, redriving log I/O if necessary.
*
* RETURN: None
*
* NOTE:
* This routine is called a interrupt time by lbmIODone
*/
static void lmPostGC(struct lbuf * bp)
{
unsigned long flags;
struct jfs_log *log = bp->l_log;
struct logpage *lp;
struct tblock *tblk, *temp;
//LOGGC_LOCK(log);
spin_lock_irqsave(&log->gclock, flags);
/*
* current pageout of group commit completed.
*
* remove/wakeup transactions from commit queue who were
* group committed with the current log page
*/
list_for_each_entry_safe(tblk, temp, &log->cqueue, cqueue) {
if (!(tblk->flag & tblkGC_COMMIT))
break;
/* if transaction was marked GC_COMMIT then
* it has been shipped in the current pageout
* and made it to disk - it is committed.
*/
if (bp->l_flag & lbmERROR)
tblk->flag |= tblkGC_ERROR;
/* remove it from the commit queue */
list_del(&tblk->cqueue);
tblk->flag &= ~tblkGC_QUEUE;
if (tblk == log->flush_tblk) {
/* we can stop flushing the log now */
clear_bit(log_FLUSH, &log->flag);
log->flush_tblk = NULL;
}
jfs_info("lmPostGC: tblk = 0x%p, flag = 0x%x", tblk,
tblk->flag);
if (!(tblk->xflag & COMMIT_FORCE))
/*
* Hand tblk over to lazy commit thread
*/
txLazyUnlock(tblk);
else {
/* state transition: COMMIT -> COMMITTED */
tblk->flag |= tblkGC_COMMITTED;
if (tblk->flag & tblkGC_READY)
log->gcrtc--;
LOGGC_WAKEUP(tblk);
}
/* was page full before pageout ?
* (and this is the last tblk bound with the page)
*/
if (tblk->flag & tblkGC_FREE)
lbmFree(bp);
/* did page become full after pageout ?
* (and this is the last tblk bound with the page)
*/
else if (tblk->flag & tblkGC_EOP) {
/* finalize the page */
lp = (struct logpage *) bp->l_ldata;
bp->l_ceor = bp->l_eor;
lp->h.eor = lp->t.eor = cpu_to_le16(bp->l_eor);
jfs_info("lmPostGC: calling lbmWrite");
lbmWrite(log, bp, lbmWRITE | lbmRELEASE | lbmFREE,
1);
}
}
/* are there any transactions who have entered lnGroupCommit()
* (whose COMMITs are after that of the last log page written.
* They are waiting for new group commit (above at (SLEEP 1))
* or lazy transactions are on a full (queued) log page,
* select the latest ready transaction as new group leader and
* wake her up to lead her group.
*/
if ((!list_empty(&log->cqueue)) &&
((log->gcrtc > 0) || (tblk->bp->l_wqnext != NULL) ||
test_bit(log_FLUSH, &log->flag) || jfs_tlocks_low))
/*
* Call lmGCwrite with new group leader
*/
lmGCwrite(log, 1);
/* no transaction are ready yet (transactions are only just
* queued (GC_QUEUE) and not entered for group commit yet).
* the first transaction entering group commit
* will elect herself as new group leader.
*/
else
log->cflag &= ~logGC_PAGEOUT;
//LOGGC_UNLOCK(log);
spin_unlock_irqrestore(&log->gclock, flags);
return;
}
/*
* NAME: lmLogSync()
*
* FUNCTION: write log SYNCPT record for specified log
* if new sync address is available
* (normally the case if sync() is executed by back-ground
* process).
* calculate new value of i_nextsync which determines when
* this code is called again.
*
* PARAMETERS: log - log structure
* hard_sync - 1 to force all metadata to be written
*
* RETURN: 0
*
* serialization: LOG_LOCK() held on entry/exit
*/
static int lmLogSync(struct jfs_log * log, int hard_sync)
{
int logsize;
int written; /* written since last syncpt */
int free; /* free space left available */
int delta; /* additional delta to write normally */
int more; /* additional write granted */
struct lrd lrd;
int lsn;
struct logsyncblk *lp;
unsigned long flags;
/* push dirty metapages out to disk */
if (hard_sync)
write_special_inodes(log, filemap_fdatawrite);
else
write_special_inodes(log, filemap_flush);
/*
* forward syncpt
*/
/* if last sync is same as last syncpt,
* invoke sync point forward processing to update sync.
*/
if (log->sync == log->syncpt) {
LOGSYNC_LOCK(log, flags);
if (list_empty(&log->synclist))
log->sync = log->lsn;
else {
lp = list_entry(log->synclist.next,
struct logsyncblk, synclist);
log->sync = lp->lsn;
}
LOGSYNC_UNLOCK(log, flags);
}
/* if sync is different from last syncpt,
* write a SYNCPT record with syncpt = sync.
* reset syncpt = sync
*/
if (log->sync != log->syncpt) {
lrd.logtid = 0;
lrd.backchain = 0;
lrd.type = cpu_to_le16(LOG_SYNCPT);
lrd.length = 0;
lrd.log.syncpt.sync = cpu_to_le32(log->sync);
lsn = lmWriteRecord(log, NULL, &lrd, NULL);
log->syncpt = log->sync;
} else
lsn = log->lsn;
/*
* setup next syncpt trigger (SWAG)
*/
logsize = log->logsize;
logdiff(written, lsn, log);
]
]
|
| 196/2 |
2026/05/12 00:34 |
llm |
fixes-finder |
0m
Model:
Tokens:
input: 84108
output: 21
thoughts: 29
Thoughts: Okay, let's dive into this. Here's how I'd approach summarizing the thought process, as if I were considering the `jfs_flush_journal` implementation:
**Analyzing the JFS Journal Flushing Mechanism**
Right, so I'm focusing on `jfs_flush_journal` within `fs/jfs/jfs_logmgr.c`. This is the core function for ensuring data integrity in the JFS filesystem, so understanding its nuances is critical. My primary concern, of course, is efficiency and correctness. I want to see how the implementation handles various scenarios β from normal write operations to potential errors or crashes. What are the key synchronization mechanisms used? How does it interact with the underlying block device? Is the implementation optimized for different hardware configurations? I'll be looking closely at the error handling β how does it manage situations where writes fail, or the journal becomes full? What's the recovery strategy? I want to assess the impact of this function on overall filesystem performance. Are there any potential bottlenecks I should be aware of? I also want to check for any obvious concurrency issues or potential race conditions. Essentially, I'm examining how this critical function ensures that the JFS journal is kept up to date and that data is committed to disk reliably. My analysis will focus on how the implementation achieves those goals, and if there are ways to improve or optimize the code.
|
| 197/2 |
2026/05/12 00:34 |
tool |
grepper |
0m
Args: map[Expression:void jfs_flush_journal]
Results: map[Output:fs/jfs/jfs_logmgr.c=1432=int lmLogClose(struct super_block *sb)
--
fs/jfs/jfs_logmgr.c-1505- */
fs/jfs/jfs_logmgr.c:1506:void jfs_flush_journal(struct jfs_log *log, int wait)
fs/jfs/jfs_logmgr.c-1507-{
--
fs/jfs/jfs_logmgr.h=503=extern int jfsIOWait(void *);
fs/jfs/jfs_logmgr.h:504:extern void jfs_flush_journal(struct jfs_log * log, int wait);
fs/jfs/jfs_logmgr.h-505-extern void jfs_syncpt(struct jfs_log *log, int hard_sync);
]
|
| 198/2 |
2026/05/12 00:34 |
llm |
fixes-finder |
0m
Model:
Tokens:
input: 84677
output: 47
thoughts: 27
Thoughts: Okay, here's my interpretation of what's going through my mind, as an expert familiar with filesystems and logging mechanisms, when approaching `jfs_flush_journal` in `fs/jfs/jfs_logmgr.c`:
**Diving into the JFS Journal Flush**
Right, `jfs_flush_journal`. That's a critical function in the JFS filesystem. It's in the `jfs_logmgr.c` file, which immediately tells me this is related to the journal management β the heart of JFS's crash recovery capabilities. I need to understand exactly how JFS ensures data consistency during write operations, especially when a system crash is possible.
My initial thoughts are already forming: I anticipate seeing calls related to writing journal records to disk, synchronizing the journal metadata, and potentially handling buffer invalidation to ensure the on-disk state matches the in-memory state as closely as possible. I'll be looking for things like:
* **Data Structure Interactions:** Specifically, how does it interact with the `jfs_log` struct? The `jfs_journal` struct? How does it handle journal buffers and descriptors?
* **Synchronization Primitives:** Are there mutexes, spinlocks, or other synchronization mechanisms used? I need to understand how concurrent access to the journal is handled, especially when multiple processes or threads might be modifying data. This is crucial for correctness.
* **Error Handling:** What happens if the write fails? Does it trigger a panic, retry, or some other mechanism to handle the error? I need to look for calls to error handling routines.
* **Block Allocation and I/O:** How does it deal with the physical I/O to the journal device? Does it use the block I/O layer directly, or is there a more abstracted interface? Are there any optimizations for sequential writes? I need to trace this I/O.
* **Journal Commit Process:** What are the steps for ensuring that the data is *actually* flushed and committed to disk? Does it use barriers, or is there a similar approach to ensuring the data is durable? I anticipate a need to identify the exact commit sequence.
I expect this function is key to overall performance, so I'm interested in any optimization techniques or trade-offs made within the flush process. I'll be looking for ways it balances throughput with the guarantee of data integrity. Let's see what the code actually reveals.
|
| 199/2 |
2026/05/12 00:35 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:fs/jfs/jfs_logmgr.c IncludeLines:true Name:jfs_flush_journal]
Results: map[SourceCode:1496: /*
1497: * NAME: jfs_flush_journal()
1498: *
1499: * FUNCTION: initiate write of any outstanding transactions to the journal
1500: * and optionally wait until they are all written to disk
1501: *
1502: * wait == 0 flush until latest txn is committed, don't wait
1503: * wait == 1 flush until latest txn is committed, wait
1504: * wait > 1 flush until all txn's are complete, wait
1505: */
1506: void jfs_flush_journal(struct jfs_log *log, int wait)
1507: {
1508: int i;
1509: struct tblock *target = NULL;
1510:
1511: /* jfs_write_inode may call us during read-only mount */
1512: if (!log)
1513: return;
1514:
1515: jfs_info("jfs_flush_journal: log:0x%p wait=%d", log, wait);
1516:
1517: LOGGC_LOCK(log);
1518:
1519: if (!list_empty(&log->cqueue)) {
1520: /*
1521: * This ensures that we will keep writing to the journal as long
1522: * as there are unwritten commit records
1523: */
1524: target = list_entry(log->cqueue.prev, struct tblock, cqueue);
1525:
1526: if (test_bit(log_FLUSH, &log->flag)) {
1527: /*
1528: * We're already flushing.
1529: * if flush_tblk is NULL, we are flushing everything,
1530: * so leave it that way. Otherwise, update it to the
1531: * latest transaction
1532: */
1533: if (log->flush_tblk)
1534: log->flush_tblk = target;
1535: } else {
1536: /* Only flush until latest transaction is committed */
1537: log->flush_tblk = target;
1538: set_bit(log_FLUSH, &log->flag);
1539:
1540: /*
1541: * Initiate I/O on outstanding transactions
1542: */
1543: if (!(log->cflag & logGC_PAGEOUT)) {
1544: log->cflag |= logGC_PAGEOUT;
1545: lmGCwrite(log, 0);
1546: }
1547: }
1548: }
1549: if ((wait > 1) || test_bit(log_SYNCBARRIER, &log->flag)) {
1550: /* Flush until all activity complete */
1551: set_bit(log_FLUSH, &log->flag);
1552: log->flush_tblk = NULL;
1553: }
1554:
1555: if (wait && target && !(target->flag & tblkGC_COMMITTED)) {
1556: DECLARE_WAITQUEUE(__wait, current);
1557:
1558: add_wait_queue(&target->gcwait, &__wait);
1559: set_current_state(TASK_UNINTERRUPTIBLE);
1560: LOGGC_UNLOCK(log);
1561: schedule();
1562: LOGGC_LOCK(log);
1563: remove_wait_queue(&target->gcwait, &__wait);
1564: }
1565: LOGGC_UNLOCK(log);
1566:
1567: if (wait < 2)
1568: return;
1569:
1570: write_special_inodes(log, filemap_fdatawrite);
1571:
1572: /*
1573: * If there was recent activity, we may need to wait
1574: * for the lazycommit thread to catch up
1575: */
1576: if ((!list_empty(&log->cqueue)) || !list_empty(&log->synclist)) {
1577: for (i = 0; i < 200; i++) { /* Too much? */
1578: msleep(250);
1579: write_special_inodes(log, filemap_fdatawrite);
1580: if (list_empty(&log->cqueue) &&
1581: list_empty(&log->synclist))
1582: break;
1583: }
1584: }
1585: assert(list_empty(&log->cqueue));
1586:
1587: #ifdef CONFIG_JFS_DEBUG
1588: if (!list_empty(&log->synclist)) {
1589: struct logsyncblk *lp;
1590:
1591: printk(KERN_ERR "jfs_flush_journal: synclist not empty\n");
1592: list_for_each_entry(lp, &log->synclist, synclist) {
1593: if (lp->xflag & COMMIT_PAGE) {
1594: struct metapage *mp = (struct metapage *)lp;
1595: print_hex_dump(KERN_ERR, "metapage: ",
1596: DUMP_PREFIX_ADDRESS, 16, 4,
1597: mp, sizeof(struct metapage), 0);
1598: print_hex_dump(KERN_ERR, "page: ",
1599: DUMP_PREFIX_ADDRESS, 16,
1600: sizeof(long), mp->folio,
1601: sizeof(struct page), 0);
1602: } else
1603: print_hex_dump(KERN_ERR, "tblock:",
1604: DUMP_PREFIX_ADDRESS, 16, 4,
1605: lp, sizeof(struct tblock), 0);
1606: }
1607: }
1608: #else
1609: WARN_ON(!list_empty(&log->synclist));
1610: #endif
1611: clear_bit(log_FLUSH, &log->flag);
1612: }
SourceFile:fs/jfs/jfs_logmgr.c]
|
| 200/2 |
2026/05/12 00:35 |
llm |
fixes-finder |
0m
Model:
Tokens:
input: 87077
output: 39
thoughts: 380
Thoughts: **Analyzing the JFS Journal Flush and Potential Race Condition**
Okay, so `jfs_flush_journal` is supposed to wait for `log->cqueue` and `log->synclist` to be empty, that's clear. But here's the kicker: it *doesn't* wait for `TxAnchor.unlock_queue` to be empty. And that `unlock_queue`, that's handled by `jfs_lazycommit`. Right, so `jfs_flush_journal` could return before `jfs_lazycommit` has finished processing the `unlock_queue`. That's it! That's the race condition described in the crash report. And if I'm reading this correctly, it's been lurking there, unaddressed, since the very beginning of the git history. Unbelievable!
Now, let's confirm my suspicions. I need to verify how `jfs_umount` calls `jfs_flush_journal`. Was it always using a flush level of `2` or `1`? Hmm, in `1c8007b0769d37aa5fcb343b383b0af89ade2f71`, it was changed from a flush level of `1` to `2`. Okay, so pre-`1c8007b0769d37aa5fcb343b383b0af89ade2f71` it was calling `jfs_flush_journal(log, 1)`. Wait, no, hold on, I'm getting mixed up here. In `1da177e4c3f41524e886b7f1b8a0c1fc7321cac2`, it *was* using `jfs_flush_journal(log, 2)`. I need to go back and double-check `jfs_umount` in that commit. Gotta be certain about this.
|
| 201/2 |
2026/05/12 00:35 |
tool |
git-show |
0m
Args: map[Commit:1da177e4c3f4:fs/jfs/jfs_umount.c]
Results: map[Output:/*
* Copyright (C) International Business Machines Corp., 2000-2004
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
* the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* jfs_umount.c
*
* note: file system in transition to aggregate/fileset:
* (ref. jfs_mount.c)
*
* file system unmount is interpreted as mount of the single/only
* fileset in the aggregate and, if unmount of the last fileset,
* as unmount of the aggerate;
*/
#include <linux/fs.h>
#include "jfs_incore.h"
#include "jfs_filsys.h"
#include "jfs_superblock.h"
#include "jfs_dmap.h"
#include "jfs_imap.h"
#include "jfs_metapage.h"
#include "jfs_debug.h"
/*
* NAME: jfs_umount(vfsp, flags, crp)
*
* FUNCTION: vfs_umount()
*
* PARAMETERS: vfsp - virtual file system pointer
* flags - unmount for shutdown
* crp - credential
*
* RETURN : EBUSY - device has open files
*/
int jfs_umount(struct super_block *sb)
{
struct address_space *bdev_mapping = sb->s_bdev->bd_inode->i_mapping;
struct jfs_sb_info *sbi = JFS_SBI(sb);
struct inode *ipbmap = sbi->ipbmap;
struct inode *ipimap = sbi->ipimap;
struct inode *ipaimap = sbi->ipaimap;
struct inode *ipaimap2 = sbi->ipaimap2;
struct jfs_log *log;
int rc = 0;
jfs_info("UnMount JFS: sb:0x%p", sb);
/*
* update superblock and close log
*
* if mounted read-write and log based recovery was enabled
*/
if ((log = sbi->log))
/*
* Wait for outstanding transactions to be written to log:
*/
jfs_flush_journal(log, 2);
/*
* close fileset inode allocation map (aka fileset inode)
*/
diUnmount(ipimap, 0);
diFreeSpecial(ipimap);
sbi->ipimap = NULL;
/*
* close secondary aggregate inode allocation map
*/
ipaimap2 = sbi->ipaimap2;
if (ipaimap2) {
diUnmount(ipaimap2, 0);
diFreeSpecial(ipaimap2);
sbi->ipaimap2 = NULL;
}
/*
* close aggregate inode allocation map
*/
ipaimap = sbi->ipaimap;
diUnmount(ipaimap, 0);
diFreeSpecial(ipaimap);
sbi->ipaimap = NULL;
/*
* close aggregate block allocation map
*/
dbUnmount(ipbmap, 0);
diFreeSpecial(ipbmap);
sbi->ipimap = NULL;
/*
* Make sure all metadata makes it to disk before we mark
* the superblock as clean
*/
filemap_fdatawrite(bdev_mapping);
filemap_fdatawait(bdev_mapping);
/*
* ensure all file system file pages are propagated to their
* home blocks on disk (and their in-memory buffer pages are
* invalidated) BEFORE updating file system superblock state
* (to signify file system is unmounted cleanly, and thus in
* consistent state) and log superblock active file system
* list (to signify skip logredo()).
*/
if (log) { /* log = NULL if read-only mount */
updateSuper(sb, FM_CLEAN);
/* Restore default gfp_mask for bdev */
mapping_set_gfp_mask(bdev_mapping, GFP_USER);
/*
* close log:
*
* remove file system from log active file system list.
*/
rc = lmLogClose(sb);
}
jfs_info("UnMount JFS Complete: rc = %d", rc);
return rc;
}
int jfs_umount_rw(struct super_block *sb)
{
struct address_space *bdev_mapping = sb->s_bdev->bd_inode->i_mapping;
struct jfs_sb_info *sbi = JFS_SBI(sb);
struct jfs_log *log = sbi->log;
if (!log)
return 0;
/*
* close log:
*
* remove file system from log active file system list.
*/
jfs_flush_journal(log, 2);
/*
* Make sure all metadata makes it to disk
*/
dbSync(sbi->ipbmap);
diSync(sbi->ipimap);
/*
* Note that we have to do this even if sync_blockdev() will
* do exactly the same a few instructions later: We can't
* mark the superblock clean before everything is flushed to
* disk.
*/
filemap_fdatawrite(bdev_mapping);
filemap_fdatawait(bdev_mapping);
updateSuper(sb, FM_CLEAN);
/* Restore default gfp_mask for bdev */
mapping_set_gfp_mask(bdev_mapping, GFP_USER);
return lmLogClose(sb);
}
]
|
| 202/2 |
2026/05/12 00:35 |
llm |
fixes-finder |
0m
Model:
Tokens:
input: 89511
output: 53
thoughts: 79
Thoughts: Okay, here's my interpretation of that thought process, assuming I'm deep in the weeds of kernel debugging:
**Tracing a Journaling Flush Change**
Right, so I'm digging into this issue, and the initial trace points to `1da177e4c3f41524e886b7f1b8a0c1fc7321cac2`. The original code, as far as I can see, was calling `jfs_flush_journal` with a level of `2`. Now, that's interesting. Why was a specific flush level chosen initially? And, more importantly, why the change? It seems someone subsequently modified this call to pass `1` as the flush level instead. This warrants further investigation. I need to pinpoint exactly *when* this change happened. I need the commit history of that particular line to understand the rationale behind this adjustment. Was this a performance optimization? A bug fix? Or something else entirely? Understanding the history is the key to understanding its effects. Let's get that commit history and see what we can find.
|
| 203/2 |
2026/05/12 00:35 |
tool |
git-log |
10m
Error: git log timed out. Please specify a tighter search scope (e.g. by providing a PathPrefix).
Args: map[CodeRegexp:jfs_flush_journal\(log, 1\) Count:100 SourcePath:fs/jfs/jfs_umount.c]
Results:
|
| 204/2 |
2026/05/12 00:45 |
llm |
fixes-finder |
0m
Model:
Tokens:
input: 89913
output: 53
thoughts: 48
Thoughts: Okay, here's my interpretation of that thought process, tailored for an expert audience:
**Analyzing Journal Flushing in JFS with Git**
Alright, I need to investigate the `jfs_flush_journal` function within the `jfs_umount.c` file. This likely involves understanding how the journal is flushed during unmounting. My initial approach is going to be using `git log`. I'll focus the search with `PathPrefix="fs/jfs/jfs_umount.c"` to pinpoint changes related specifically to that file and, most importantly, I will use `CodeRegexp="jfs_flush_journal\\(log, 1\\)"`. The regexp will allow me to narrow my search to commits that include the specific call `jfs_flush_journal(log, 1)`. I am assuming `log` is a journal structure and that the `1` implies some specific flush behaviour. This will likely give me a clear history of modifications to that *specific* call site, allowing me to trace how the journal flushing logic has evolved over time, identify potential regressions, or understand the intent behind changes related to this particular call.
|
| 205/2 |
2026/05/12 00:45 |
tool |
git-log |
0m
Args: map[CodeRegexp:jfs_flush_journal\(log, 1\) Count:100 PathPrefix:fs/jfs/jfs_umount.c]
Results: map[Output:1c8007b0769d jfs: flush journal completely before releasing metadata inodes
67e6682f18b3 JFS: Make sure special inode data is written after journal is flushed
]
|
| 206/2 |
2026/05/12 00:45 |
llm |
fixes-finder |
0m
Model:
Tokens:
input: 90322
output: 27
thoughts: 19
Thoughts: Okay, let's dive into this. Here's my take on those "thoughts":
**Analyzing the Hash: 67e6682f18b3**
Right, let's dissect `67e6682f18b3`. Initially, this looks like a standard hexadecimal hash, potentially an MD5, SHA-1, SHA-256 or similar. Given the length of it (32 characters), my immediate instinct is to treat it as an MD5 or a SHA-256 hash, though it's certainly not definitive without context. I should check the context to see if I can find what kind of hash this is, if it's even one at all. From here, I need to consider a few avenues of investigation.
First, I need to know how this hash was generated: what kind of data went into creating this hash? Is there any available documentation? A known process? Understanding the source data is crucial.
Second, if I can confirm the hash type and know the data, I can consider reverse engineering and checking common databases. Then I can begin running it through a variety of hash cracking techniques if needed. This could range from simple lookups against known rainbow tables to more advanced techniques depending on complexity.
Third, if the original data is unavailable, and the hashing method is unknown, I would begin brute-force attempts.
I have to explore and analyze this hash's entropy. What possible outputs would create this hash? How can I use known libraries or tools to compare and validate this data? Ultimately, my goal is to figure out what this hash represents, and what the original data was that created it.
|
| 207/2 |
2026/05/12 00:45 |
tool |
git-show |
0m
Args:
Results: map[Output:commit 67e6682f18b3bf812a994ae027ff87174a297ae8
Author: Dave Kleikamp <shaggy@linux.vnet.ibm.com>
Date: Wed Oct 10 11:11:24 2007 -0500
JFS: Make sure special inode data is written after journal is flushed
This patch makes sure that data that we tried to flush before the journal
was completely written actually gets pushed to disk.
To avoid duplicating code, moved common code to write_special_inodes().
Signed-off-by: Dave Kleikamp <shaggy@linux.vnet.ibm.com>
diff --git a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c
index 15a3974cdeeb..2370716d57ad 100644
--- a/fs/jfs/jfs_logmgr.c
+++ b/fs/jfs/jfs_logmgr.c
@@ -208,6 +208,17 @@ static struct lmStat {
} lmStat;
#endif
+static void write_special_inodes(struct jfs_log *log,
+ int (*writer)(struct address_space *))
+{
+ struct jfs_sb_info *sbi;
+
+ list_for_each_entry(sbi, &log->sb_list, log_list) {
+ writer(sbi->ipbmap->i_mapping);
+ writer(sbi->ipimap->i_mapping);
+ writer(sbi->direct_inode->i_mapping);
+ }
+}
/*
* NAME: lmLog()
@@ -935,22 +946,13 @@ static int lmLogSync(struct jfs_log * log, int hard_sync)
struct lrd lrd;
int lsn;
struct logsyncblk *lp;
- struct jfs_sb_info *sbi;
unsigned long flags;
/* push dirty metapages out to disk */
if (hard_sync)
- list_for_each_entry(sbi, &log->sb_list, log_list) {
- filemap_fdatawrite(sbi->ipbmap->i_mapping);
- filemap_fdatawrite(sbi->ipimap->i_mapping);
- filemap_fdatawrite(sbi->direct_inode->i_mapping);
- }
+ write_special_inodes(log, filemap_fdatawrite);
else
- list_for_each_entry(sbi, &log->sb_list, log_list) {
- filemap_flush(sbi->ipbmap->i_mapping);
- filemap_flush(sbi->ipimap->i_mapping);
- filemap_flush(sbi->direct_inode->i_mapping);
- }
+ write_special_inodes(log, filemap_flush);
/*
* forward syncpt
@@ -1536,7 +1538,6 @@ void jfs_flush_journal(struct jfs_log *log, int wait)
{
int i;
struct tblock *target = NULL;
- struct jfs_sb_info *sbi;
/* jfs_write_inode may call us during read-only mount */
if (!log)
@@ -1598,11 +1599,7 @@ void jfs_flush_journal(struct jfs_log *log, int wait)
if (wait < 2)
return;
- list_for_each_entry(sbi, &log->sb_list, log_list) {
- filemap_fdatawrite(sbi->ipbmap->i_mapping);
- filemap_fdatawrite(sbi->ipimap->i_mapping);
- filemap_fdatawrite(sbi->direct_inode->i_mapping);
- }
+ write_special_inodes(log, filemap_fdatawrite);
/*
* If there was recent activity, we may need to wait
@@ -1611,6 +1608,7 @@ void jfs_flush_journal(struct jfs_log *log, int wait)
if ((!list_empty(&log->cqueue)) || !list_empty(&log->synclist)) {
for (i = 0; i < 200; i++) { /* Too much? */
msleep(250);
+ write_special_inodes(log, filemap_fdatawrite);
if (list_empty(&log->cqueue) &&
list_empty(&log->synclist))
break;
diff --git a/fs/jfs/jfs_umount.c b/fs/jfs/jfs_umount.c
index 7971f37534a3..adcf92d3b603 100644
--- a/fs/jfs/jfs_umount.c
+++ b/fs/jfs/jfs_umount.c
@@ -68,7 +68,7 @@ int jfs_umount(struct super_block *sb)
/*
* Wait for outstanding transactions to be written to log:
*/
- jfs_flush_journal(log, 2);
+ jfs_flush_journal(log, 1);
/*
* close fileset inode allocation map (aka fileset inode)
@@ -146,7 +146,7 @@ int jfs_umount_rw(struct super_block *sb)
*
* remove file system from log active file system list.
*/
- jfs_flush_journal(log, 2);
+ jfs_flush_journal(log, 1);
/*
* Make sure all metadata makes it to disk
]
|
| 208/2 |
2026/05/12 00:45 |
llm |
fixes-finder |
0m
Model:
Tokens:
input: 92240
output: 46
thoughts: 431
Thoughts: **Analyzing a JFS Journaling Bug**
Okay, so I'm looking at this JFS code and immediately notice a couple of commits that are flipping a crucial parameter in `jfs_flush_journal`. Specifically, `67e6682f18b3bf812a994ae027ff87174a297ae8` changed it from `2` to `1` and then `1c8007b0769d37aa5fcb343b383b0af89ade2f71` changed it back. My initial thought is to figure out if that parameter change is the root of an issue.
Then I realized, the core problem isn't the *value* of that parameter, but what `jfs_flush_journal(log, 2)` *itself* is doing. It seems the function isn't properly waiting for `TxAnchor.unlock_queue` to empty, and that's the real problem. So, this bug is much older.
Let me see... That means this problem has existed since, at least, the initial commit, `1da177e4c3f41524e886b7f1b8a0c1fc7321cac2`. I need to confirm something: was `jfs_lazycommit` introduced around that time? Yes, it was part of the initial commit. This looks like the origin of the problem, but I need to be sure.
Let's check for other commits around that time or since, that may have either introduced the `jfs_lazycommit` feature, or modified `jfs_flush_journal` to not wait for `unlock_queue`.
Wait a minute... I remember `jfs_flush_journal` does wait for other queues, like `log->cqueue` and `log->synclist`. Did it *ever* wait for `unlock_queue`? That's the critical question.
I need to dig into the history of `jfs_flush_journal` in `fs/jfs/jfs_logmgr.c` and see if the waiting mechanism has always been the same, or if there was a point where `unlock_queue` was involved. That's where I'll find the root of this.
|
| 209/2 |
2026/05/12 00:45 |
tool |
git-log |
0m
Args: map[Count:100 SourcePath:fs/jfs/jfs_logmgr.c SymbolName:jfs_flush_journal]
Results: map[Output:ad6c19e5f932 jfs: Change metapage->page to metapage->folio
f139caf2e897 sched, cleanup, treewide: Remove set_current_state(TASK_RUNNING) after schedule()
67e6682f18b3 JFS: Make sure special inode data is written after journal is flushed
288e4d838d1e JFS: Update print_hex_dump() syntax
209e101bf408 JFS: use print_hex_dump() rather than private dump_mem() function
3cbb1c8e1a47 JFS: use __set_current_state()
63f83c9fcf40 JFS: White space cleanup
72e3148a6e98 JFS: Fix compiler warning in jfs_logmgr.c
7fab479bebb9 [PATCH] JFS: Support page sizes greater than 4K
1da177e4c3f4 Linux-2.6.12-rc2
]
|
| 210/2 |
2026/05/12 00:46 |
llm |
fixes-finder |
0m
Model:
Tokens:
input: 93499
output: 46
thoughts: 155
Thoughts: **Tracing the Bug in JFS Journal Flushing**
Okay, so I'm digging into this JFS journal flushing issue. My initial thought is that `jfs_flush_journal` *never* waited for `unlock_queue`. That seems pretty solid. So, the introduction of this bug must have coincided with either the introduction of `jfs_lazycommit` or, potentially, the introduction of `jfs_flush_journal` itself β which, looking at the history, predates the current Git structure.
Alright, if that's the case, and this bug is that fundamental, then that makes the initial Git commit, `1da177e4c3f41524e886b7f1b8a0c1fc7321cac2`, the likely culprit. However, before I leap to that conclusion, I need to verify that `jfs_lazycommit` didn't have its behavior tweaked at some later point, potentially masking the real problem. The obvious next step is to examine the commit history of `jfs_lazycommit` in `fs/jfs/jfs_txnmgr.c` to see if there are any changes that might have contributed to the issue. This file is the obvious place to look for that code. Let's start there.
|
| 211/2 |
2026/05/12 00:46 |
tool |
git-log |
0m
Args: map[Count:100 SourcePath:fs/jfs/jfs_txnmgr.c SymbolName:jfs_lazycommit]
Results: map[Output:a280c9ceeca7 jfs: Add missing set_freezable() for freezable kthread
b18db6de2ce2 jfs: Remove terminating newlines from jfs_info, jfs_warn, jfs_err uses
f139caf2e897 sched, cleanup, treewide: Remove set_current_state(TASK_RUNNING) after schedule()
a0acae0e886d freezer: unexport refrigerator() and update try_to_freeze() slightly
3cbb1c8e1a47 JFS: use __set_current_state()
91dbb4deb30e JFS: Use the kthread_ API
3e1d1d28d99d [PATCH] Cleanup patch for process freezing
1da177e4c3f4 Linux-2.6.12-rc2
]
|
| 212/2 |
2026/05/12 00:46 |
llm |
fixes-finder |
0m
Model:
Tokens:
input: 94200
output: 44
thoughts: 25
Thoughts: Okay, here's my take on those commits, from my perspective, keeping in mind my expertise:
**Examining the Commit History**
Alright, I'm going through this commit history, and frankly, nothing is screaming "bug introduction" at me. Seems like we're mostly dealing with some refactoring and cleanup operations here, nothing that should have caused a regression, at least not directly. I'm not seeing any red flags jump out from this.
But, you know me, I don't like to leave any stone unturned. Let me cast my eyes toward `txLazyCommit`. Just want to rule it out, given that it's a common area for unexpected issues. Always pays to double check. Let's see if there's any logic here that could be playing a role.
|
| 213/2 |
2026/05/12 00:47 |
tool |
git-log |
0m
Args: map[Count:100 SourcePath:fs/jfs/jfs_txnmgr.c SymbolName:txLazyCommit]
Results: map[Output:f720e3ba5586 JFS: Whitespace cleanup and remove some dead code
1da177e4c3f4 Linux-2.6.12-rc2
]
|
| 214/2 |
2026/05/12 00:47 |
llm |
fixes-finder |
0m
Model:
Tokens:
input: 94498
output: 44
thoughts: 8
Thoughts: Okay, here's my attempt at summarizing that thought process, keeping in mind I'm speaking to a fellow expert:
**Investigating `txLazyUnlock` Considerations**
Alright, so the initial thought that pops into my head is, "What about `txLazyUnlock`?" This immediately triggers a cascade of associated ideas. My mind starts running through the implications of using such a mechanism in this specific context. I'm likely weighing the potential benefits β perhaps improved throughput or reduced latency in certain scenarios β against the potential drawbacks, like increased complexity or the risk of introducing subtle vulnerabilities. I'm essentially probing for its suitability here. Iβm thinking, is this a viable path for optimization or a rabbit hole best avoided? What are the tradeoffs? Where does it fit within the architecture and what are the specific use cases in which it might apply, or, alternatively, be a disaster? Itβs a gut check, a quick mental scan of a particular techniqueβs relevance. The question implies Iβm probably exploring some optimization here, and my initial reaction is, "Let's see if this could be the key."
|
| 215/2 |
2026/05/12 00:47 |
tool |
git-log |
0m
Args: map[Count:100 SourcePath:fs/jfs/jfs_txnmgr.c SymbolName:txLazyUnlock]
Results: map[Output:1da177e4c3f4 Linux-2.6.12-rc2
]
|
| 216/2 |
2026/05/12 00:48 |
llm |
fixes-finder |
0m
Model:
Tokens:
input: 94818
output: 20
thoughts: 1400
Thoughts: **Bug Analysis: JFS Unmount Race Condition**
Okay, so I've got this crash report, and it looks like a race condition during JFS filesystem unmount. The core issue is that `jfs_umount` calls `jfs_flush_journal` to flush transactions, but `jfs_flush_journal` doesn't properly wait for the `TxAnchor.unlock_queue` to be processed by the `jfs_lazycommit` thread. Let's trace this back.
First thought, the code's been like this since the dawn of time, specifically, commit `1da177e4c3f41524e886b7f1b8a0c1fc7321cac2`. Let's confirm there aren't any sneaky introductions of the bug. I need to make sure this code is unchanged. Quick double-check: yep, `jfs_umount` *does* call `jfs_flush_journal(log, 2)` in that initial commit.
And looking at the code for `jfs_flush_journal` from back then, it's pretty clear: it flushes, then it checks `log->cqueue` and `log->synclist` to see if there's *recent* activity, but it doesn't touch `TxAnchor.unlock_queue`. The comment even mentions waiting for the lazycommit thread, but the implementation only covers *part* of the issue. The bug, the failure to fully flush, is *absolutely* present in `1da177e4c3f41524e886b7f1b8a0c1fc7321cac2`.
Now, let's look at the commit `1c8007b0769d37aa5fcb343b383b0af89ade2f71`. This one changes `jfs_flush_journal(log, 1)` back to `jfs_flush_journal(log, 2)`. If it was `1`, it wouldn't wait at all! That commit notes "jfs: flush journal completely before releasing metadata inodes". It sounds like it *should* fix this. But if it goes to `2`, it *does* wait for `cqueue` and `synclist`, but not `unlock_queue`. So, no, `1c8007b0769d37aa5fcb343b383b0af89ade2f71` didn't introduce the bug; it just didn't *fully* fix it. The root cause remains `1da177e4c3f41524e886b7f1b8a0c1fc7321cac2`.
Okay, back to fundamentals. The crash report points to the *initial* commit, `1da177e4c3f41524e886b7f1b8a0c1fc7321cac2`. If the bug's there from the start, we return `1da177e4c3f41524e886b7f1b8a0c1fc7321cac2`.
Hold on, before I sign off on that, what about those moving parts? Could `jfs_lazycommit` have been added *later*? No, I checked that; it's in the initial commit. And `TxAnchor.unlock_queue`? Let's verify that's also in the initial commit. Yes, it is.
So, yeah, that initial commit is it. The unmount race has been lurking since the beginning.
|
| 217/2 |
2026/05/12 00:48 |
tool |
grepper |
0m
Args: map[Expression:TxAnchor\.unlock_queue]
Results: map[Output:fs/jfs/jfs_txnmgr.c=225=int txInit(void)
--
fs/jfs/jfs_txnmgr.c-316- LAZY_LOCK_INIT();
fs/jfs/jfs_txnmgr.c:317: INIT_LIST_HEAD(&TxAnchor.unlock_queue);
fs/jfs/jfs_txnmgr.c-318-
--
fs/jfs/jfs_txnmgr.c=2700=int jfs_lazycommit(void *arg)
--
fs/jfs/jfs_txnmgr.c-2710- jfs_commit_thread_waking = 0; /* OK to wake another thread */
fs/jfs/jfs_txnmgr.c:2711: while (!list_empty(&TxAnchor.unlock_queue)) {
fs/jfs/jfs_txnmgr.c-2712- WorkDone = 0;
fs/jfs/jfs_txnmgr.c:2713: list_for_each_entry(tblk, &TxAnchor.unlock_queue,
fs/jfs/jfs_txnmgr.c-2714- cqueue) {
--
fs/jfs/jfs_txnmgr.c-2767-
fs/jfs/jfs_txnmgr.c:2768: if (!list_empty(&TxAnchor.unlock_queue))
fs/jfs/jfs_txnmgr.c-2769- jfs_err("jfs_lazycommit being killed w/pending transactions!");
--
fs/jfs/jfs_txnmgr.c=2775=void txLazyUnlock(struct tblock * tblk)
--
fs/jfs/jfs_txnmgr.c-2780-
fs/jfs/jfs_txnmgr.c:2781: list_add_tail(&tblk->cqueue, &TxAnchor.unlock_queue);
fs/jfs/jfs_txnmgr.c-2782- /*
--
fs/jfs/jfs_txnmgr.c=2959=int jfs_txanchor_proc_show(struct seq_file *m, void *v)
--
fs/jfs/jfs_txnmgr.c-2989- jfs_tlocks_low,
fs/jfs/jfs_txnmgr.c:2990: list_empty(&TxAnchor.unlock_queue) ? "" : "not ");
fs/jfs/jfs_txnmgr.c-2991- return 0;
]
|
| 218/2 |
2026/05/12 00:48 |
llm |
fixes-finder |
0m
Model:
Tokens:
input: 97740
output: 53
thoughts: 921
Thoughts: **Bug Origin: A Deep Dive into the JFS Flush Logic**
Okay, so I've pinned down the source of this issue. `TxAnchor.unlock_queue` not being properly flushed during unmount β that's been there since the very beginning, all the way back to commit `1da177e4c3f41524e886b7f1b8a0c1fc7321cac2`. I need to confirm this before I submit my findings.
Let me just do a quick sanity check to be absolutely sure. Could it possibly be the change in `1c8007b0769d37aa5fcb343b383b0af89ade2f71`? No, that commit actually *increased* the wait time, not decreased it. It looks like it changed `jfs_flush_journal(log, 1)` to `jfs_flush_journal(log, 2)`. Let me refresh my memory of the behavior of `jfs_flush_journal(log, 1)`:
```c
if (wait < 2)
return;
```
Right, it did *nothing* if `wait < 2`. Before that commit, it didn't wait for `cqueue` and `synclist`. So, if anything, the bug was even more severe *before* that change. Before `67e6682f18b3bf812a994ae027ff87174a297ae8` it used to wait ( `jfs_flush_journal(log, 2)`). So the bug where it did *not* wait for `cqueue` and `synclist` must have started with `67e6682f18b3bf812a994ae027ff87174a297ae8`. But, that's not our bug.
The actual bug we are fixing is that it doesn't wait for `TxAnchor.unlock_queue` to drain. And looking at the history, `jfs_flush_journal(log, 2)` *never* waited for `TxAnchor.unlock_queue`. Therefore, it's clear: the root of the problem is indeed in the original commit.
Let's circle back to that crash report again, to make absolutely sure we are on the same page. The report confirms that during umount, `jfs_flush_journal(log, 2)` is called, flushing the outstanding transactions, waiting for `cqueue` and `synclist` to be empty. However, it *does not wait* for the unlock queue (`TxAnchor.unlock_queue`) to be processed.
Given that `jfs_flush_journal` has never waited for `TxAnchor.unlock_queue` in the history, the bug must have been introduced with `1da177e4c3f41524e886b7f1b8a0c1fc7321cac2`. Okay, I'm confident.
Time to call `set-results` with `1da177e4c3f41524e886b7f1b8a0c1fc7321cac2`.
|
| 219/2 |
2026/05/12 00:48 |
tool |
set-results |
0m
Args: map[FixesHash:1da177e4c3f41524e886b7f1b8a0c1fc7321cac2]
Results: map[FixesHash:1da177e4c3f41524e886b7f1b8a0c1fc7321cac2]
|
| 220/1 |
2026/05/12 00:49 |
action |
format-fixes |
0m
Results: map[Fixes:map[Hash:1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 Title:Linux-2.6.12-rc2]]
|
| 221/1 |
2026/05/12 00:49 |
action |
get-maintainers |
0m
Results: map[Recipients:[map[Email:jfs-discussion@lists.sourceforge.net Name: To:true] map[Email:linux-kernel@vger.kernel.org Name: To:false] map[Email:shaggy@kernel.org Name:Dave Kleikamp To:true]]]
|
| 222/1 |
2026/05/12 00:49 |
action |
get-recent-commits |
0m
Results: map[RecentCommits:jfs: hold LOG_LOCK on umount to avoid null-ptr-deref
jfs: fix corrupted list in dbUpdatePMap
Coccinelle-based conversion to use ->i_state accessors
jfs: fix uninitialized waitqueue in transaction manager
jfs: Add missing set_freezable() for freezable kthread
jfs: define xtree root and page independently
FS: JFS: Check for read-only mounted filesystem in txBegin
jfs: Fix a typo in function jfs_umount
jfs: remove redundant assignments to ipaimap and ipaimap2
fs/jfs: Remove dead code
jfs: Remove trailing semicolon in macros
jfs: turn diLog(), dataLog() and txLog() into void functions
jfs: delete duplicated words + other fixes
treewide: Replace GPLv2 boilerplate/reference with SPDX - rule 156
jfs: fix bogus variable self-initialization
jfs: simplify procfs code
jfs: Simplify code
drop redundant ->owner initializations
jfs: Coalesce some formats
jfs: Remove terminating newlines from jfs_info, jfs_warn, jfs_err uses
]
|
| 223/1 |
2026/05/12 00:49 |
agent |
description-generator |
0m
Model:
Instruction:
You are an experienced Linux kernel developer tasked with writing a commit description for
a kernel bug fixing commit. The description should start with a one-line summary,
and then include description of the bug being fixed, and how it's fixed by the provided patch.
Your final reply should contain only the text of the commit description.
Phrase the one-line summary so that it is not longer than 72 characters.
IMPORTANT: Do not wrap lines manually (e.g., at 80 characters); we will reformat the text
automatically, so keep paragraphs as single lines without newlines.
Prefer calling several tools at the same time to save round-trips.
Prompt:
The crash that corresponds to the bug is:
... Log Wrap ... Log Wrap ... Log Wrap ...
==================================================================
BUG: KASAN: slab-use-after-free in lmLogSync+0x9bb/0xa50 fs/jfs/jfs_logmgr.c:1003
Write of size 4 at addr ffff88804dbfaa18 by task jfsCommit/122
CPU: 1 UID: 0 PID: 122 Comm: jfsCommit Not tainted syzkaller #1 PREEMPT(full)
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
Call Trace:
<TASK>
dump_stack_lvl+0xe8/0x150 lib/dump_stack.c:120
print_address_description+0x55/0x1e0 mm/kasan/report.c:378
print_report+0x58/0x70 mm/kasan/report.c:482
kasan_report+0x117/0x150 mm/kasan/report.c:595
lmLogSync+0x9bb/0xa50 fs/jfs/jfs_logmgr.c:1003
jfs_syncpt+0x7b/0x90 fs/jfs/jfs_logmgr.c:1039
txEnd+0x2e5/0x530 fs/jfs/jfs_txnmgr.c:551
txLazyCommit fs/jfs/jfs_txnmgr.c:2686 [inline]
jfs_lazycommit+0x5b8/0xaa0 fs/jfs/jfs_txnmgr.c:2735
kthread+0x388/0x470 kernel/kthread.c:436
ret_from_fork+0x514/0xb70 arch/x86/kernel/process.c:158
ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245
</TASK>
Allocated by task 6683:
kasan_save_stack mm/kasan/common.c:57 [inline]
kasan_save_track+0x3e/0x80 mm/kasan/common.c:78
poison_kmalloc_redzone mm/kasan/common.c:398 [inline]
__kasan_kmalloc+0x93/0xb0 mm/kasan/common.c:415
kasan_kmalloc include/linux/kasan.h:263 [inline]
__kmalloc_cache_noprof+0x31c/0x660 mm/slub.c:5419
kmalloc_noprof include/linux/slab.h:950 [inline]
kzalloc_noprof include/linux/slab.h:1188 [inline]
open_inline_log fs/jfs/jfs_logmgr.c:1157 [inline]
lmLogOpen+0x2d1/0xfa0 fs/jfs/jfs_logmgr.c:1067
jfs_mount_rw+0xee/0x670 fs/jfs/jfs_mount.c:257
jfs_fill_super+0x754/0xd80 fs/jfs/super.c:532
get_tree_bdev_flags+0x431/0x4f0 fs/super.c:1694
vfs_get_tree+0x92/0x2a0 fs/super.c:1754
fc_mount fs/namespace.c:1193 [inline]
do_new_mount_fc fs/namespace.c:3758 [inline]
do_new_mount+0x341/0xd30 fs/namespace.c:3834
do_mount fs/namespace.c:4167 [inline]
__do_sys_mount fs/namespace.c:4383 [inline]
__se_sys_mount+0x31d/0x420 fs/namespace.c:4360
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0x15f/0xf80 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x77/0x7f
Freed by task 6065:
kasan_save_stack mm/kasan/common.c:57 [inline]
kasan_save_track+0x3e/0x80 mm/kasan/common.c:78
kasan_save_free_info+0x46/0x50 mm/kasan/generic.c:584
poison_slab_object mm/kasan/common.c:253 [inline]
__kasan_slab_free+0x5c/0x80 mm/kasan/common.c:285
kasan_slab_free include/linux/kasan.h:235 [inline]
slab_free_hook mm/slub.c:2689 [inline]
slab_free mm/slub.c:6250 [inline]
kfree+0x1c5/0x640 mm/slub.c:6565
lmLogClose+0x297/0x520 fs/jfs/jfs_logmgr.c:-1
jfs_umount+0x2fb/0x3d0 fs/jfs/jfs_umount.c:124
jfs_put_super+0x8c/0x190 fs/jfs/super.c:194
generic_shutdown_super+0x13d/0x2d0 fs/super.c:646
kill_block_super+0x44/0x90 fs/super.c:1725
deactivate_locked_super+0xbc/0x130 fs/super.c:476
cleanup_mnt+0x437/0x4d0 fs/namespace.c:1312
task_work_run+0x1d9/0x270 kernel/task_work.c:233
resume_user_mode_work include/linux/resume_user_mode.h:50 [inline]
__exit_to_user_mode_loop kernel/entry/common.c:67 [inline]
exit_to_user_mode_loop+0xf3/0x4d0 kernel/entry/common.c:98
__exit_to_user_mode_prepare include/linux/irq-entry-common.h:207 [inline]
syscall_exit_to_user_mode_prepare include/linux/irq-entry-common.h:238 [inline]
syscall_exit_to_user_mode include/linux/entry-common.h:318 [inline]
do_syscall_64+0x33e/0xf80 arch/x86/entry/syscall_64.c:100
entry_SYSCALL_64_after_hwframe+0x77/0x7f
The buggy address belongs to the object at ffff88804dbfa800
which belongs to the cache kmalloc-1k of size 1024
The buggy address is located 536 bytes inside of
freed 1024-byte region [ffff88804dbfa800, ffff88804dbfac00)
The buggy address belongs to the physical page:
page: refcount:0 mapcount:0 mapping:0000000000000000 index:0xffff88804dbf9800 pfn:0x4dbf8
head: order:3 mapcount:0 entire_mapcount:0 nr_pages_mapped:0 pincount:0
flags: 0x4fff00000000240(workingset|head|node=1|zone=1|lastcpupid=0x7ff)
page_type: f5(slab)
raw: 04fff00000000240 ffff88801a841dc0 ffffea0001a6e610 ffffea000123f010
raw: ffff88804dbf9800 000000080010000f 00000000f5000000 0000000000000000
head: 04fff00000000240 ffff88801a841dc0 ffffea0001a6e610 ffffea000123f010
head: ffff88804dbf9800 000000080010000f 00000000f5000000 0000000000000000
head: 04fff00000000003 fffffffffffffe01 00000000ffffffff 00000000ffffffff
head: ffffffffffffffff 0000000000000000 00000000ffffffff 0000000000000008
page dumped because: kasan: bad access detected
page_owner tracks the page as allocated
page last allocated via order 3, migratetype Unmovable, gfp_mask 0xd20c0(__GFP_IO|__GFP_FS|__GFP_NOWARN|__GFP_NORETRY|__GFP_COMP|__GFP_NOMEMALLOC), pid 6080, tgid 6080 (syz-executor), ts 85500584456, free_ts 84013765231
set_page_owner include/linux/page_owner.h:32 [inline]
post_alloc_hook+0x231/0x280 mm/page_alloc.c:1858
prep_new_page mm/page_alloc.c:1866 [inline]
get_page_from_freelist+0x24ba/0x2540 mm/page_alloc.c:3946
__alloc_frozen_pages_noprof+0x18d/0x380 mm/page_alloc.c:5226
alloc_slab_page mm/slub.c:3278 [inline]
allocate_slab+0x77/0x660 mm/slub.c:3467
new_slab mm/slub.c:3525 [inline]
refill_objects+0x339/0x3d0 mm/slub.c:7255
refill_sheaf mm/slub.c:2816 [inline]
__pcs_replace_empty_main+0x321/0x720 mm/slub.c:4651
alloc_from_pcs mm/slub.c:4749 [inline]
slab_alloc_node mm/slub.c:4883 [inline]
__do_kmalloc_node mm/slub.c:5294 [inline]
__kmalloc_noprof+0x474/0x760 mm/slub.c:5307
kmalloc_noprof include/linux/slab.h:954 [inline]
kzalloc_noprof include/linux/slab.h:1188 [inline]
__alloc_workqueue+0x100/0x1c00 kernel/workqueue.c:5815
alloc_workqueue_va kernel/workqueue.c:5917 [inline]
alloc_workqueue_noprof+0xe3/0x210 kernel/workqueue.c:5933
tipc_crypto_start+0xd8/0x640 net/tipc/crypto.c:1472
tipc_init_net+0x213/0x330 net/tipc/core.c:72
ops_init+0x35c/0x5c0 net/core/net_namespace.c:137
setup_net+0x118/0x340 net/core/net_namespace.c:446
copy_net_ns+0x3e2/0x570 net/core/net_namespace.c:579
create_new_namespaces+0x3e7/0x6a0 kernel/nsproxy.c:132
unshare_nsproxy_namespaces+0x149/0x190 kernel/nsproxy.c:234
page last free pid 5978 tgid 5978 stack trace:
reset_page_owner include/linux/page_owner.h:25 [inline]
__free_pages_prepare mm/page_alloc.c:1402 [inline]
__free_frozen_pages+0xb84/0xcd0 mm/page_alloc.c:2943
__slab_free+0x274/0x2c0 mm/slub.c:5612
qlink_free mm/kasan/quarantine.c:163 [inline]
qlist_free_all+0x99/0x100 mm/kasan/quarantine.c:179
kasan_quarantine_reduce+0x148/0x160 mm/kasan/quarantine.c:286
__kasan_slab_alloc+0x22/0x80 mm/kasan/common.c:350
kasan_slab_alloc include/linux/kasan.h:253 [inline]
slab_post_alloc_hook mm/slub.c:4569 [inline]
slab_alloc_node mm/slub.c:4898 [inline]
kmem_cache_alloc_node_noprof+0x384/0x690 mm/slub.c:4950
__alloc_skb+0x1d0/0x7d0 net/core/skbuff.c:702
alloc_skb include/linux/skbuff.h:1383 [inline]
nlmsg_new include/net/netlink.h:1055 [inline]
netlink_ack+0x146/0xa50 net/netlink/af_netlink.c:2487
netlink_rcv_skb+0x2b6/0x4b0 net/netlink/af_netlink.c:2556
netlink_unicast_kernel net/netlink/af_netlink.c:1318 [inline]
netlink_unicast+0x75c/0x8e0 net/netlink/af_netlink.c:1344
netlink_sendmsg+0x813/0xb40 net/netlink/af_netlink.c:1894
sock_sendmsg_nosec net/socket.c:787 [inline]
__sock_sendmsg+0x167/0x1b0 net/socket.c:802
__sys_sendto+0x3c0/0x550 net/socket.c:2265
__do_sys_sendto net/socket.c:2272 [inline]
__se_sys_sendto net/socket.c:2268 [inline]
__x64_sys_sendto+0xde/0x100 net/socket.c:2268
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0x15f/0xf80 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x77/0x7f
Memory state around the buggy address:
ffff88804dbfa900: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
ffff88804dbfa980: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
>ffff88804dbfaa00: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
^
ffff88804dbfaa80: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
ffff88804dbfab00: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
==================================================================
The explanation of the root cause of the bug is:
An analysis of the crash reveals a race condition during the unmounting of a JFS filesystem, leading to a use-after-free in the `jfs_lazycommit` background thread.
### Root Cause
When a JFS filesystem is unmounted, `jfs_umount()` (and `jfs_umount_rw()`) calls `jfs_flush_journal(log, 2)` to flush all outstanding transactions to the disk.
`jfs_flush_journal()` waits until the commit queue (`log->cqueue`) and the sync list (`log->synclist`) are empty. However, it **does not wait** for the unlock queue (`TxAnchor.unlock_queue`) to be processed by the `jfs_lazycommit` thread.
The lifecycle of a lazy transaction is as follows:
1. Added to `log->cqueue` during `txCommit()`.
2. Moved from `log->cqueue` to `TxAnchor.unlock_queue` by `lmPostGC()` once the commit record hits the disk.
3. Removed from `TxAnchor.unlock_queue` and processed by the `jfs_lazycommit` thread via `txLazyCommit()`.
Because `jfs_flush_journal()` only waits for `log->cqueue` to drain, it can return while transactions are still sitting in `TxAnchor.unlock_queue` or are actively being processed by `jfs_lazycommit`.
After `jfs_flush_journal()` returns, `jfs_umount()` proceeds to tear down the filesystem: it frees the allocation maps (`sbi->ipimap`, `sbi->ipbmap`) and eventually calls `lmLogClose()`, which frees the `jfs_log` structure.
Meanwhile, the `jfs_lazycommit` thread wakes up, pops the transaction from `TxAnchor.unlock_queue`, and calls `txLazyCommit()`. This function accesses the now-freed allocation maps and the freed `log` structure (`log = JFS_SBI(tblk->sb)->log`), eventually calling `txEnd()` -> `jfs_syncpt()` -> `lmLogSync()`, which writes to `log->syncpt`, resulting in the KASAN slab-use-after-free crash.
### How to Fix
To fix this, we need to ensure that `jfs_lazycommit` has completely finished processing all transactions for the unmounting superblock before `jfs_umount()` proceeds to free the filesystem structures.
1. **Introduce a wait function in `fs/jfs/jfs_txnmgr.c`:**
Create a function `txLazyCommitWait(sb)` that waits until `TxAnchor.unlock_queue` contains no transactions for the given `sb`, and the `jfs_lazycommit` thread is not actively processing one (`sbi->commit_state & IN_LAZYCOMMIT` is cleared).
```c
/*
* Wait for lazycommit thread to finish processing all transactions
* for the given superblock.
*/
void txLazyCommitWait(struct super_block *sb)
{
struct jfs_sb_info *sbi = JFS_SBI(sb);
struct jfs_log *log = sbi->log;
unsigned long flags;
struct tblock *tblk;
int found;
if (!log)
return;
/*
* Synchronize with lmPostGC to ensure that all transactions
* removed from cqueue have been added to unlock_queue.
*/
spin_lock_irqsave(&log->gclock, flags);
spin_unlock_irqrestore(&log->gclock, flags);
do {
found = 0;
LAZY_LOCK(flags);
if (sbi->commit_state & IN_LAZYCOMMIT)
found = 1;
else {
list_for_each_entry(tblk, &TxAnchor.unlock_queue, cqueue) {
if (tblk->sb == sb) {
found = 1;
break;
}
}
}
LAZY_UNLOCK(flags);
if (found)
msleep(10);
} while (found);
}
```
*(Note: Briefly taking `log->gclock` is crucial here to close a tiny race window where `jfs_flush_journal` sees an empty `cqueue`, but `lmPostGC` is still holding `log->gclock` and hasn't yet added the transaction to `unlock_queue`)*.
2. **Export the function in `fs/jfs/jfs_txnmgr.h`:**
```c
extern void txLazyCommitWait(struct super_block *sb);
```
3. **Call the wait function during unmount in `fs/jfs/jfs_umount.c`:**
Invoke `txLazyCommitWait(sb)` immediately after `jfs_flush_journal(log, 2)` in both `jfs_umount()` and `jfs_umount_rw()`.
In `jfs_umount()`:
```c
- if ((log = sbi->log))
+ if ((log = sbi->log)) {
/*
* Wait for outstanding transactions to be written to log:
*/
jfs_flush_journal(log, 2);
+ txLazyCommitWait(sb);
+ }
```
In `jfs_umount_rw()`:
```c
/*
* Note that we have to do this even if dummy_log is used.
* This is because dummy_log is shared among all mounts.
*/
jfs_flush_journal(log, 2);
+ txLazyCommitWait(sb);
/*
* close log:
```
The diff of the bug fix is:
diff --git a/fs/jfs/jfs_txnmgr.c b/fs/jfs/jfs_txnmgr.c
index 083dbbb0c..823250c3c 100644
--- a/fs/jfs/jfs_txnmgr.c
+++ b/fs/jfs/jfs_txnmgr.c
@@ -37,6 +37,7 @@
#include <linux/moduleparam.h>
#include <linux/kthread.h>
#include <linux/seq_file.h>
+#include <linux/delay.h>
#include "jfs_incore.h"
#include "jfs_inode.h"
#include "jfs_filsys.h"
@@ -2772,6 +2773,49 @@ int jfs_lazycommit(void *arg)
return 0;
}
+/*
+ * Wait for lazycommit thread to finish processing all transactions
+ * for the given superblock.
+ */
+void txLazyCommitWait(struct super_block *sb)
+{
+ struct jfs_sb_info *sbi = JFS_SBI(sb);
+ struct jfs_log *log = sbi->log;
+ unsigned long flags;
+ struct tblock *tblk;
+ int found;
+
+ if (!log)
+ return;
+
+ /*
+ * Synchronize with lmPostGC to ensure that all transactions
+ * removed from cqueue have been added to unlock_queue.
+ */
+ spin_lock_irqsave(&log->gclock, flags);
+ spin_unlock_irqrestore(&log->gclock, flags);
+
+ do {
+ found = 0;
+ LAZY_LOCK(flags);
+ if (sbi->commit_state & IN_LAZYCOMMIT)
+ found = 1;
+ else {
+ list_for_each_entry(tblk, &TxAnchor.unlock_queue,
+ cqueue) {
+ if (tblk->sb == sb) {
+ found = 1;
+ break;
+ }
+ }
+ }
+ LAZY_UNLOCK(flags);
+
+ if (found)
+ msleep(10);
+ } while (found);
+}
+
void txLazyUnlock(struct tblock * tblk)
{
unsigned long flags;
diff --git a/fs/jfs/jfs_txnmgr.h b/fs/jfs/jfs_txnmgr.h
index ba71eb5ce..3b3272ded 100644
--- a/fs/jfs/jfs_txnmgr.h
+++ b/fs/jfs/jfs_txnmgr.h
@@ -295,4 +295,5 @@ extern void txResume(struct super_block *);
extern void txLazyUnlock(struct tblock *);
extern int jfs_lazycommit(void *);
extern int jfs_sync(void *);
+extern void txLazyCommitWait(struct super_block *sb);
#endif /* _H_JFS_TXNMGR */
diff --git a/fs/jfs/jfs_umount.c b/fs/jfs/jfs_umount.c
index 18569f1ea..1aca20b1d 100644
--- a/fs/jfs/jfs_umount.c
+++ b/fs/jfs/jfs_umount.c
@@ -21,6 +21,7 @@
#include "jfs_dmap.h"
#include "jfs_imap.h"
#include "jfs_logmgr.h"
+#include "jfs_txnmgr.h"
#include "jfs_metapage.h"
#include "jfs_debug.h"
@@ -52,11 +53,13 @@ int jfs_umount(struct super_block *sb)
*
* if mounted read-write and log based recovery was enabled
*/
- if ((log = sbi->log))
+ if ((log = sbi->log)) {
/*
* Wait for outstanding transactions to be written to log:
*/
jfs_flush_journal(log, 2);
+ txLazyCommitWait(sb);
+ }
/*
* Hold log lock so write_special_inodes (lmLogSync) cannot see
@@ -142,6 +145,7 @@ int jfs_umount_rw(struct super_block *sb)
* remove file system from log active file system list.
*/
jfs_flush_journal(log, 2);
+ txLazyCommitWait(sb);
/*
* Make sure all metadata makes it to disk
Additional description of the patch:
I have implemented the fix as suggested to resolve the race condition between the unmounting process and the `jfs_lazycommit` background thread.
### Changes Made:
1. **Added `txLazyCommitWait(sb)` in `fs/jfs/jfs_txnmgr.c`**:
- This function ensures that all transactions for a given superblock have been completely processed by the `jfs_lazycommit` thread.
- It first briefly acquires and releases `log->gclock`. This is a critical step to synchronize with `lmPostGC()`. It closes a tiny race window where `jfs_flush_journal()` might see an empty `cqueue` and return, while `lmPostGC()` has removed the transaction from `cqueue` but hasn't yet added it to `TxAnchor.unlock_queue`.
- It then loops, taking `LAZY_LOCK` to check if `sbi->commit_state & IN_LAZYCOMMIT` is set (meaning the thread is actively processing a transaction for this superblock) or if there are any pending transactions for this superblock in `TxAnchor.unlock_queue`. If either condition is met, it sleeps for 10ms and retries.
- I also added `#include <linux/delay.h>` to `fs/jfs/jfs_txnmgr.c` to support the `msleep(10)` call.
2. **Exported `txLazyCommitWait` in `fs/jfs/jfs_txnmgr.h`**:
- Added the function prototype `extern void txLazyCommitWait(struct super_block *sb);` so it can be called from other files.
3. **Invoked `txLazyCommitWait` during unmount in `fs/jfs/jfs_umount.c`**:
- Added `#include "jfs_txnmgr.h"` to the includes list.
- Called `txLazyCommitWait(sb)` immediately after `jfs_flush_journal(log, 2)` in both `jfs_umount()` and `jfs_umount_rw()`. This guarantees that by the time `jfs_umount()` proceeds to tear down the filesystem and free the `jfs_log` structure via `lmLogClose()`, the `jfs_lazycommit` thread has completely finished its work for this superblock and will not attempt to access the freed structures.
These changes effectively eliminate the use-after-free vulnerability by enforcing proper synchronization and lifecycle management during the filesystem unmount process.
Here are summaries of recent commits that touched the same files.
Format the summary line consistently with these, look how prefixes
are specified, letter capitalization, style, etc.
jfs: hold LOG_LOCK on umount to avoid null-ptr-deref
jfs: fix corrupted list in dbUpdatePMap
Coccinelle-based conversion to use ->i_state accessors
jfs: fix uninitialized waitqueue in transaction manager
jfs: Add missing set_freezable() for freezable kthread
jfs: define xtree root and page independently
FS: JFS: Check for read-only mounted filesystem in txBegin
jfs: Fix a typo in function jfs_umount
jfs: remove redundant assignments to ipaimap and ipaimap2
fs/jfs: Remove dead code
jfs: Remove trailing semicolon in macros
jfs: turn diLog(), dataLog() and txLog() into void functions
jfs: delete duplicated words + other fixes
treewide: Replace GPLv2 boilerplate/reference with SPDX - rule 156
jfs: fix bogus variable self-initialization
jfs: simplify procfs code
jfs: Simplify code
drop redundant ->owner initializations
jfs: Coalesce some formats
jfs: Remove terminating newlines from jfs_info, jfs_warn, jfs_err uses
Reply: jfs: fix use-after-free in jfs_lazycommit during unmount
An analysis of a KASAN slab-use-after-free crash reveals a race condition during the unmounting of a JFS filesystem. When a JFS filesystem is unmounted, jfs_umount() calls jfs_flush_journal() to flush all outstanding transactions to disk. jfs_flush_journal() waits until the commit queue and the sync list are empty, but it does not wait for the unlock queue to be processed by the jfs_lazycommit background thread.
Because jfs_flush_journal() only waits for the commit queue to drain, it can return while transactions are still sitting in the unlock queue or are actively being processed by jfs_lazycommit. After jfs_flush_journal() returns, jfs_umount() proceeds to tear down the filesystem, freeing the allocation maps and the jfs_log structure. Meanwhile, the jfs_lazycommit thread wakes up, pops the transaction from the unlock queue, and accesses the now-freed allocation maps and log structure, eventually causing a use-after-free crash in lmLogSync().
To fix this, introduce txLazyCommitWait() to ensure that jfs_lazycommit has completely finished processing all transactions for the unmounting superblock before jfs_umount() proceeds to free the filesystem structures. This function synchronizes with lmPostGC() to ensure all transactions removed from the commit queue have been added to the unlock queue, and then waits until the unlock queue is empty and the lazycommit thread is no longer active for the given superblock. Invoke this wait function immediately after jfs_flush_journal() in both jfs_umount() and jfs_umount_rw().
|
| 224/2 |
2026/05/12 00:49 |
llm |
description-generator |
0m
Model:
Tokens:
input: 11090
output: 367
thoughts: 1399
Thoughts: **Commit Description for JFS Use-After-Free Fix**
Okay, so I need to craft a commit message for this JFS patch. Based on recent commits, I'll start with the "jfs: " prefix. The summary line needs to be concise, under 72 characters, and accurately reflect the bug. I think "jfs: fix use-after-free in jfs_lazycommit during unmount" (58 chars) captures it nicely. Now, for the detailed description, I need to clearly explain the problem and the solution.
First, I'll explain the root cause. This KASAN report pointed to a use-after-free, specifically a slab-use-after-free, in JFS. It happens during unmount. The core issue is a race condition between `jfs_umount()` and the `jfs_lazycommit` thread. When unmounting, `jfs_umount()` calls `jfs_flush_journal()` to push all transactions to disk. However, `jfs_flush_journal()` only waits for the commit queue and the sync list to be empty. It *doesn't* wait for the unlock queue, which is processed by the `jfs_lazycommit` thread.
This means `jfs_flush_journal()` can return even when transactions are still pending in the unlock queue, or actively being worked on by `jfs_lazycommit`. So, `jfs_umount()` then proceeds to tear down the filesystem, freeing vital structures: allocation maps and the `jfs_log` structure. The problem is, the `jfs_lazycommit` thread wakes up, grabs a transaction from the unlock queue, and accesses these freed structures. This then leads to that dreaded use-after-free crash in `lmLogSync()`.
The solution is to introduce a new function, `txLazyCommitWait()`. This function makes sure the `jfs_lazycommit` thread is completely done processing all transactions for that unmounting superblock *before* `jfs_umount()` destroys things. The `txLazyCommitWait()` function synchronizes with `lmPostGC()` to ensure all the transactions from the commit queue are in the unlock queue. Then it waits until the unlock queue is empty, and the `jfs_lazycommit` thread isn't busy with the specific superblock. I'll call this `txLazyCommitWait()` immediately after `jfs_flush_journal()` in both `jfs_umount()` and `jfs_umount_rw()`. Hopefully, this will eliminate the race and the use-after-free. I think this will work.
|
| 225/1 |
2026/05/12 00:49 |
action |
format-patch-description |
0m
Results: map[PatchDescription:jfs: fix use-after-free in jfs_lazycommit during unmount
An analysis of a KASAN slab-use-after-free crash reveals a race
condition during the unmounting of a JFS filesystem. When a JFS
filesystem is unmounted, jfs_umount() calls jfs_flush_journal() to flush
all outstanding transactions to disk. jfs_flush_journal() waits until
the commit queue and the sync list are empty, but it does not wait for
the unlock queue to be processed by the jfs_lazycommit background
thread.
Because jfs_flush_journal() only waits for the commit queue to drain, it
can return while transactions are still sitting in the unlock queue or
are actively being processed by jfs_lazycommit. After
jfs_flush_journal() returns, jfs_umount() proceeds to tear down the
filesystem, freeing the allocation maps and the jfs_log structure.
Meanwhile, the jfs_lazycommit thread wakes up, pops the transaction from
the unlock queue, and accesses the now-freed allocation maps and log
structure, eventually causing a use-after-free crash in lmLogSync().
To fix this, introduce txLazyCommitWait() to ensure that jfs_lazycommit
has completely finished processing all transactions for the unmounting
superblock before jfs_umount() proceeds to free the filesystem
structures. This function synchronizes with lmPostGC() to ensure all
transactions removed from the commit queue have been added to the unlock
queue, and then waits until the unlock queue is empty and the lazycommit
thread is no longer active for the given superblock. Invoke this wait
function immediately after jfs_flush_journal() in both jfs_umount() and
jfs_umount_rw().]
|