Commit e65af39e authored by Dave Kleikamp's avatar Dave Kleikamp

Add support for external JFS journal

Submitted by Christoph Hellwig & Dave Kleikamp
parent db468b69
......@@ -123,7 +123,7 @@ struct jfs_sb_info {
short nbperpage; /* 2: blocks per page */
short l2nbperpage; /* 2: log2 blocks per page */
short l2niperblk; /* 2: log2 inodes per page */
short reserved; /* 2: log2 inodes per page */
kdev_t logdev; /* 2: external log device */
pxd_t logpxd; /* 8: pxd describing log */
pxd_t ait2; /* 8: pxd describing AIT copy */
/* Formerly in ipimap */
......
......@@ -159,7 +159,6 @@ do { \
/*
* external references
*/
extern void vPut(struct inode *ip);
extern void txLazyUnlock(tblock_t * tblk);
extern int jfs_thread_stopped(void);
extern struct task_struct *jfsIOtask;
......@@ -172,6 +171,7 @@ static int lmWriteRecord(log_t * log, tblock_t * tblk, lrd_t * lrd,
tlock_t * tlck);
static int lmNextPage(log_t * log);
static int lmLogFileSystem(log_t * log, kdev_t fsdev, int activate);
static int lmLogInit(log_t * log);
static int lmLogShutdown(log_t * log);
......@@ -1057,46 +1057,36 @@ int lmLogSync(log_t * log, int nosyncwait)
int lmLogOpen(struct super_block *sb, log_t ** logptr)
{
int rc;
kdev_t logdev; /* dev_t of log device */
struct block_device *bdev;
log_t *log;
logdev = sb->s_dev;
if (!(log = kmalloc(sizeof(log_t), GFP_KERNEL)))
return ENOMEM;
memset(log, 0, sizeof(log_t));
#ifdef _STILL_TO_PORT
/*
* open the inode representing the log device (aka log inode)
*/
if (logdev != fsdev)
if (!(JFS_SBI(sb)->mntflag & JFS_INLINELOG))
goto externalLog;
#endif /* _STILL_TO_PORT */
/*
* in-line log in host file system
*
* file system to log have 1-to-1 relationship;
*/
// inlineLog:
*logptr = log = kmalloc(sizeof(log_t), GFP_KERNEL);
if (log == 0)
return ENOMEM;
memset(log, 0, sizeof(log_t));
log->sb = sb; /* This should be a list */
log->flag = JFS_INLINELOG;
log->dev = logdev;
log->dev = sb->s_dev;
log->base = addressPXD(&JFS_SBI(sb)->logpxd);
log->size = lengthPXD(&JFS_SBI(sb)->logpxd) >>
(L2LOGPSIZE - sb->s_blocksize_bits);
log->l2bsize = sb->s_blocksize_bits;
ASSERT(L2LOGPSIZE >= sb->s_blocksize_bits);
/*
* initialize log.
*/
if ((rc = lmLogInit(log)))
goto errout10;
#ifdef _STILL_TO_PORT
goto out;
/*
......@@ -1105,103 +1095,47 @@ int lmLogOpen(struct super_block *sb, log_t ** logptr)
* file systems to log may have n-to-1 relationship;
*/
externalLog:
/*
* open log inode
*
* log inode is reserved inode of (dev_t = log device,
* fileset number = 0, i_number = 0), which acquire
* one i_count for each open by file system.
*
* hand craft dummy vfs to force iget() the special case of
* an in-memory inode allocation without on-disk inode
*/
memset(&dummyvfs, 0, sizeof(struct vfs));
dummyvfs.filesetvfs.vfs_data = NULL;
dummyvfs.dummyvfs.dev = logdev;
dummyvfs.dummyvfs.ipmnt = NULL;
ICACHE_LOCK();
rc = iget((struct vfs *) &dummyvfs, 0, (inode_t **) & log, 0);
ICACHE_UNLOCK();
if (rc)
return rc;
log->flag = 0;
log->dev = logdev;
log->base = 0;
log->size = 0;
/*
* serialize open/close between multiple file systems
* bound with the log;
*/
ip = (inode_t *) log;
IWRITE_LOCK(ip);
/*
* subsequent open: add file system to log active file system list
*/
#ifdef _JFS_OS2
if (log->strat2p)
#endif /* _JFS_OS2 */
{
if (rc = lmLogFileSystem(log, fsdev, 1))
goto errout10;
IWRITE_UNLOCK(ip);
*iplog = ip;
jFYI(1, ("lmLogOpen: exit(0)\n"));
return 0;
if (!(bdev = bdget(kdev_t_to_nr(JFS_SBI(sb)->logdev)))) {
rc = ENODEV;
goto errout10;
}
/* decouple log inode from dummy vfs */
vPut(ip);
/*
* first open:
*/
#ifdef _JFS_OS2
/*
* establish access to the single/shared (already open) log device
*/
logdevfp = (void *) logStrat2;
log->strat2p = logStrat2;
log->strat3p = logStrat3;
log->l2pbsize = 9; /* todo: when OS/2 have multiple external log */
#endif /* _JFS_OS2 */
if ((rc = blkdev_get(bdev, FMODE_READ|FMODE_WRITE, 0, BDEV_FS))) {
rc = -rc;
goto errout10;
}
log->sb = sb; /* This should be a list */
log->dev = JFS_SBI(sb)->logdev;
log->bdev = bdev;
/*
* initialize log:
*/
if (rc = lmLogInit(log))
if ((rc = lmLogInit(log)))
goto errout20;
/*
* add file system to log active file system list
*/
if (rc = lmLogFileSystem(log, fsdev, 1))
if ((rc = lmLogFileSystem(log, sb->s_dev, 1)))
goto errout30;
/*
* insert log device into log device list
*/
out:
#endif /* _STILL_TO_PORT */
jFYI(1, ("lmLogOpen: exit(0)\n"));
*logptr = log;
return 0;
/*
* unwind on error
*/
#ifdef _STILL_TO_PORT
errout30: /* unwind lbmLogInit() */
lbmLogShutdown(log);
errout20: /* close external log device */
blkdev_put(bdev, BDEV_FS);
#endif /* _STILL_TO_PORT */
errout10: /* free log inode */
errout10: /* free log descriptor */
kfree(log);
jFYI(1, ("lmLogOpen: exit(%d)\n", rc));
......@@ -1253,6 +1187,10 @@ static int lmLogInit(log_t * log)
/*
* validate log superblock
*/
if (!(log->flag & JFS_INLINELOG))
log->l2bsize = 12; /* XXX kludge alert XXX */
if ((rc = lbmRead(log, 1, &bpsuper)))
goto errout10;
......@@ -1282,6 +1220,7 @@ static int lmLogInit(log_t * log)
log, (unsigned long long) log->base, log->size));
} else {
log->size = le32_to_cpu(logsuper->size);
log->l2bsize = le32_to_cpu(logsuper->l2bsize);
jFYI(0,
("lmLogInit: external log:0x%p base:0x%Lx size:0x%x\n",
log, (unsigned long long) log->base, log->size));
......@@ -1376,6 +1315,7 @@ static int lmLogInit(log_t * log)
logsuper->state = cpu_to_le32(LOGMOUNT);
log->serial = le32_to_cpu(logsuper->serial) + 1;
logsuper->serial = cpu_to_le32(log->serial);
logsuper->device = cpu_to_le32(kdev_t_to_nr(log->dev));
lbmDirectWrite(log, bpsuper, lbmWRITE | lbmRELEASE | lbmSYNC);
if ((rc = lbmIOWait(bpsuper, lbmFREE)))
goto errout30;
......@@ -1419,47 +1359,24 @@ int lmLogClose(struct super_block *sb, log_t * log)
jFYI(1, ("lmLogClose: log:0x%p\n", log));
if (!(log->flag & JFS_INLINELOG))
goto externalLog;
/*
* in-line log in host file system
*/
// inlineLog:
#ifdef _STILL_TO_PORT
if (log->flag & JFS_INLINELOG) {
rc = lmLogShutdown(log);
goto out1;
}
rc = lmLogShutdown(log);
goto out;
/*
* external log as separate logical volume
*/
externalLog:
/* serialize open/close between multiple file systems
* associated with the log
*/
IWRITE_LOCK(iplog);
/*
* remove file system from log active file system list
*/
rc = lmLogFileSystem(log, fsdev, 0);
if (iplog->i_count > 1)
goto out2;
/*
* last close: shut down log
*/
rc = ((rc1 = lmLogShutdown(log)) && rc == 0) ? rc1 : rc;
out1:
#else /* _STILL_TO_PORT */
lmLogFileSystem(log, sb->s_dev, 0);
rc = lmLogShutdown(log);
#endif /* _STILL_TO_PORT */
// out2:
blkdev_put(log->bdev, BDEV_FS);
out:
jFYI(0, ("lmLogClose: exit(%d)\n", rc));
return rc;
}
......@@ -1561,7 +1478,6 @@ static int lmLogShutdown(log_t * log)
}
#ifdef _STILL_TO_PORT
/*
* NAME: lmLogFileSystem()
*
......@@ -1569,7 +1485,7 @@ static int lmLogShutdown(log_t * log)
* file system into/from log active file system list.
*
* PARAMETE: log - pointer to logs inode.
* fsdev - dev_t of filesystem.
* fsdev - kdev_t of filesystem.
* serial - pointer to returned log serial number
* activate - insert/remove device from active list.
*
......@@ -1578,10 +1494,11 @@ static int lmLogShutdown(log_t * log)
*
* serialization: IWRITE_LOCK(log inode) held on entry/exit
*/
static int lmLogFileSystem(log_t * log, dev_t fsdev, int activate)
static int lmLogFileSystem(log_t * log, kdev_t fsdev, int activate)
{
int rc = 0;
int bit, word;
int i;
u32 dev_le = cpu_to_le32(kdev_t_to_nr(fsdev));
logsuper_t *logsuper;
lbuf_t *bpsuper;
......@@ -1592,15 +1509,25 @@ static int lmLogFileSystem(log_t * log, dev_t fsdev, int activate)
return rc;
logsuper = (logsuper_t *) bpsuper->l_ldata;
bit = minor(fsdev);
word = bit / 32;
bit -= 32 * word;
if (activate)
logsuper->active[word] |=
cpu_to_le32((LEFTMOSTONE >> bit));
else
logsuper->active[word] &=
cpu_to_le32((~(LEFTMOSTONE >> bit)));
if (activate) {
for (i = 0; i < MAX_ACTIVE; i++)
if (logsuper->active[i] == 0) {
logsuper->active[i] = dev_le;
break;
}
if (i == MAX_ACTIVE) {
jERROR(1,("Too many file systems sharing journal!\n"));
lbmFree(bpsuper);
return EMFILE; /* Is there a better rc? */
}
} else {
for (i = 0; i < MAX_ACTIVE; i++)
if (logsuper->active[i] == dev_le) {
logsuper->active[i] = 0;
break;
}
assert(i < MAX_ACTIVE);
}
/*
* synchronous write log superblock:
......@@ -1618,7 +1545,6 @@ static int lmLogFileSystem(log_t * log, dev_t fsdev, int activate)
return rc;
}
#endif /* _STILL_TO_PORT */
/*
......
......@@ -60,6 +60,8 @@
#define LOGMAGIC 0x87654321
#define LOGVERSION 1
#define MAX_ACTIVE 512 /* Max active file systems sharing log */
typedef struct {
u32 magic; /* 4: log lv identifier */
s32 version; /* 4: version number */
......@@ -72,8 +74,8 @@ typedef struct {
u32 state; /* 4: state - see below */
s32 end; /* 4: addr of last log record set by logredo */
u32 active[8]; /* 32: active file systems bit vector */
s32 rsrvd[LOGPSIZE / 4 - 17];
u32 device; /* 4: save device in case location changes */
u32 active[MAX_ACTIVE]; /* 2048: active file systems list */
} logsuper_t;
/* log flag: commit option (see jfs_filsys.h) */
......@@ -200,7 +202,7 @@ typedef struct lrd {
s32 backchain; /* 4: ptr to prev record of same transaction */
u16 type; /* 2: record type */
s16 length; /* 2: length of data in record (in byte) */
s32 aggregate; /* 4: file system lv/aggregate */
u32 aggregate; /* 4: file system lv/aggregate */
/* (16) */
/*
......@@ -367,7 +369,7 @@ typedef struct jfs_log {
* the log between fs's
*/
kdev_t dev; /* 4: log lv number */
struct file *devfp; /* 4: log device file */
struct block_device *bdev; /* 4: log lv pointer */
s32 serial; /* 4: log mount serial number */
s64 base; /* @8: log extent address (inline log ) */
......
......@@ -283,24 +283,6 @@ int jfs_mount_rw(struct super_block *sb, int remount)
return rc;
}
}
#ifdef _STILL_TO_PORT
/*
* get log device associated with the fs being mounted;
*/
if (ipmnt->i_mntflag & JFS_INLINELOG) {
vfsp->vfs_logVPB = vfsp->vfs_hVPB;
vfsp->vfs_logvpfs = vfsp->vfs_vpfsi;
} else if (vfsp->vfs_logvpfs == NULL) {
/*
* XXX: there's only one external log per system;
*/
jERROR(1, ("jfs_mount: Mount Failure! No Log Device.\n"));
goto errout30;
}
logdev = vfsp->vfs_logvpfs->vpi_unit;
ipmnt->i_logdev = logdev;
#endif /* _STILL_TO_PORT */
/*
* open/initialize log
......@@ -360,7 +342,7 @@ static int chkSuper(struct super_block *sb)
*/
/* validate fs signature */
if (strncmp(j_sb->s_magic, JFS_MAGIC, 4) ||
j_sb->s_version != cpu_to_le32(JFS_VERSION)) {
j_sb->s_version > cpu_to_le32(JFS_VERSION)) {
//rc = EFORMAT;
rc = EINVAL;
goto out;
......@@ -398,10 +380,6 @@ static int chkSuper(struct super_block *sb)
j_sb->s_flag |= cpu_to_le32(JFS_BAD_SAIT);
}
/* in release 1, the flag MUST reflect inline log, and group commit */
if ((j_sb->s_flag & cpu_to_le32(JFS_INLINELOG)) !=
cpu_to_le32(JFS_INLINELOG))
j_sb->s_flag |= cpu_to_le32(JFS_INLINELOG);
if ((j_sb->s_flag & cpu_to_le32(JFS_GROUPCOMMIT)) !=
cpu_to_le32(JFS_GROUPCOMMIT))
j_sb->s_flag |= cpu_to_le32(JFS_GROUPCOMMIT);
......@@ -437,6 +415,8 @@ static int chkSuper(struct super_block *sb)
sbi->l2niperblk = sbi->l2bsize - L2DISIZE;
if (sbi->mntflag & JFS_INLINELOG)
sbi->logpxd = j_sb->s_logpxd;
else
sbi->logdev = to_kdev_t(le32_to_cpu(j_sb->s_logdev));
sbi->ait2 = j_sb->s_ait2;
out:
......@@ -476,6 +456,10 @@ int updateSuper(struct super_block *sb, uint state)
j_sb->s_logdev =
cpu_to_le32(kdev_t_to_nr(JFS_SBI(sb)->log->dev));
j_sb->s_logserial = cpu_to_le32(JFS_SBI(sb)->log->serial);
/* record our own device number in case the location
* changes after a reboot
*/
j_sb->s_device = cpu_to_le32(kdev_t_to_nr(sb->s_dev));
} else if (state == FM_CLEAN) {
/*
* If this volume is shared with OS/2, OS/2 will need to
......
......@@ -25,9 +25,9 @@
/*
* make the magic number something a human could read
*/
#define JFS_MAGIC "JFS1" /* Magic word: Version 1 */
#define JFS_MAGIC "JFS1" /* Magic word */
#define JFS_VERSION 1 /* Version number: Version 1 */
#define JFS_VERSION 2 /* Version number: Version 2 */
#define LV_NAME_SIZE 11 /* MUST BE 11 for OS/2 boot sector */
......@@ -103,38 +103,10 @@ struct jfs_superblock {
pxd_t s_xlogpxd; /* 8: extendfs logpxd */
/* - 128 byte boundary - */
/*
* DFS VFS support (preliminary)
*/
char s_attach; /* 1: VFS: flag: set when aggregate is attached
u32 s_device; /* Store device in case location changes
* between reboots
*/
u8 rsrvd4[7]; /* 7: reserved - set to 0 */
u64 totalUsable; /* 8: VFS: total of 1K blocks which are
* available to "normal" (non-root) users.
*/
u64 minFree; /* 8: VFS: # of 1K blocks held in reserve for
* exclusive use of root. This value can be 0,
* and if it is then totalUsable will be equal
* to # of blocks in aggregate. I believe this
* means that minFree + totalUsable = # blocks.
* In that case, we don't need to store both
* totalUsable and minFree since we can compute
* one from the other. I would guess minFree
* would be the one we should store, and
* totalUsable would be the one we should
* compute. (Just a guess...)
*/
u64 realFree; /* 8: VFS: # of free 1K blocks can be used by
* "normal" users. It may be this is something
* we should compute when asked for instead of
* storing in the superblock. I don't know how
* often this information is needed.
*/
/*
* graffiti area
*/
};
extern int readSuper(struct super_block *, struct metapage **);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment