Commit 3aa8e204 authored by Dave Kleikamp's avatar Dave Kleikamp

Merge jfs@jfs.bkbits.net:linux-2.5

into kleikamp.austin.ibm.com:/home/shaggy/bk/jfs-2.5
parents 14fc589b b275001f
...@@ -2830,6 +2830,86 @@ void dtInitRoot(tid_t tid, struct inode *ip, u32 idotdot) ...@@ -2830,6 +2830,86 @@ void dtInitRoot(tid_t tid, struct inode *ip, u32 idotdot)
return; return;
} }
/*
* add_missing_indices()
*
* function: Fix dtree page in which one or more entries has an invalid index.
* fsck.jfs should really fix this, but it currently does not.
* Called from jfs_readdir when bad index is detected.
*/
static void add_missing_indices(struct inode *inode, s64 bn)
{
struct ldtentry *d;
struct dt_lock *dtlck;
int i;
uint index;
struct lv *lv;
struct metapage *mp;
dtpage_t *p;
int rc;
s8 *stbl;
tid_t tid;
struct tlock *tlck;
tid = txBegin(inode->i_sb, 0);
DT_GETPAGE(inode, bn, mp, PSIZE, p, rc);
if (rc) {
printk(KERN_ERR "DT_GETPAGE failed!\n");
goto end;
}
BT_MARK_DIRTY(mp, inode);
ASSERT(p->header.flag & BT_LEAF);
tlck = txLock(tid, inode, mp, tlckDTREE | tlckENTRY);
dtlck = (struct dt_lock *) &tlck->lock;
stbl = DT_GETSTBL(p);
for (i = 0; i < p->header.nextindex; i++) {
d = (struct ldtentry *) &p->slot[stbl[i]];
index = le32_to_cpu(d->index);
if ((index < 2) || (index >= JFS_IP(inode)->next_index)) {
d->index = cpu_to_le32(add_index(tid, inode, bn, i));
if (dtlck->index >= dtlck->maxcnt)
dtlck = (struct dt_lock *) txLinelock(dtlck);
lv = dtlck->lv;
lv->offset = stbl[i];
lv->length = 1;
dtlck->index++;
}
}
DT_PUTPAGE(mp);
(void) txCommit(tid, 1, &inode, 0);
end:
txEnd(tid);
}
/*
* Buffer to hold directory entry info while traversing a dtree page
* before being fed to the filldir function
*/
struct jfs_dirent {
loff_t position;
int ino;
u16 name_len;
char name[0];
};
/*
* function to determine next variable-sized jfs_dirent in buffer
*/
inline struct jfs_dirent *next_jfs_dirent(struct jfs_dirent *dirent)
{
return (struct jfs_dirent *)
((char *)dirent +
((sizeof (struct jfs_dirent) + dirent->name_len + 1 +
sizeof (loff_t) - 1) &
~(sizeof (loff_t) - 1)));
}
/* /*
* jfs_readdir() * jfs_readdir()
* *
...@@ -2846,11 +2926,12 @@ int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir) ...@@ -2846,11 +2926,12 @@ int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
struct inode *ip = filp->f_dentry->d_inode; struct inode *ip = filp->f_dentry->d_inode;
struct nls_table *codepage = JFS_SBI(ip->i_sb)->nls_tab; struct nls_table *codepage = JFS_SBI(ip->i_sb)->nls_tab;
int rc = 0; int rc = 0;
loff_t dtpos; /* legacy OS/2 style position */
struct dtoffset { struct dtoffset {
s16 pn; s16 pn;
s16 index; s16 index;
s32 unused; s32 unused;
} *dtoffset = (struct dtoffset *) &filp->f_pos; } *dtoffset = (struct dtoffset *) &dtpos;
s64 bn; s64 bn;
struct metapage *mp; struct metapage *mp;
dtpage_t *p; dtpage_t *p;
...@@ -2860,12 +2941,17 @@ int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir) ...@@ -2860,12 +2941,17 @@ int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
int i, next; int i, next;
struct ldtentry *d; struct ldtentry *d;
struct dtslot *t; struct dtslot *t;
int d_namleft, d_namlen, len, outlen; int d_namleft, len, outlen;
char *d_name, *name_ptr; unsigned long dirent_buf;
char *name_ptr;
int dtlhdrdatalen; int dtlhdrdatalen;
u32 dir_index; u32 dir_index;
int do_index = 0; int do_index = 0;
uint loop_count = 0; uint loop_count = 0;
struct jfs_dirent *jfs_dirent;
int jfs_dirents;
int overflow, fix_page, page_fixed = 0;
static int unique_pos = 2; /* If we can't fix broken index */
if (filp->f_pos == DIREND) if (filp->f_pos == DIREND)
return 0; return 0;
...@@ -2885,7 +2971,9 @@ int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir) ...@@ -2885,7 +2971,9 @@ int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
if (dir_index > 1) { if (dir_index > 1) {
struct dir_table_slot dirtab_slot; struct dir_table_slot dirtab_slot;
if (dtEmpty(ip)) { if (dtEmpty(ip) ||
(dir_index >= JFS_IP(ip)->next_index)) {
/* Stale position. Directory has shrunk */
filp->f_pos = DIREND; filp->f_pos = DIREND;
return 0; return 0;
} }
...@@ -2963,13 +3051,15 @@ int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir) ...@@ -2963,13 +3051,15 @@ int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
*/ */
dtlhdrdatalen = DTLHDRDATALEN_LEGACY; dtlhdrdatalen = DTLHDRDATALEN_LEGACY;
if (filp->f_pos == 0) { dtpos = filp->f_pos;
if (dtpos == 0) {
/* build "." entry */ /* build "." entry */
if (filldir(dirent, ".", 1, filp->f_pos, ip->i_ino, if (filldir(dirent, ".", 1, filp->f_pos, ip->i_ino,
DT_DIR)) DT_DIR))
return 0; return 0;
dtoffset->index = 1; dtoffset->index = 1;
filp->f_pos = dtpos;
} }
if (dtoffset->pn == 0) { if (dtoffset->pn == 0) {
...@@ -2985,6 +3075,7 @@ int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir) ...@@ -2985,6 +3075,7 @@ int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
} }
dtoffset->pn = 1; dtoffset->pn = 1;
dtoffset->index = 0; dtoffset->index = 0;
filp->f_pos = dtpos;
} }
if (dtEmpty(ip)) { if (dtEmpty(ip)) {
...@@ -3009,32 +3100,72 @@ int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir) ...@@ -3009,32 +3100,72 @@ int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
} }
} }
d_name = kmalloc((JFS_NAME_MAX + 1) * sizeof(wchar_t), GFP_NOFS); dirent_buf = __get_free_page(GFP_KERNEL);
if (d_name == NULL) { if (dirent_buf == 0) {
DT_PUTPAGE(mp); DT_PUTPAGE(mp);
jERROR(1, ("jfs_readdir: kmalloc failed!\n")); jERROR(1, ("jfs_readdir: __get_free_page failed!\n"));
filp->f_pos = DIREND; filp->f_pos = DIREND;
return 0; return -ENOMEM;
} }
while (1) { while (1) {
jfs_dirent = (struct jfs_dirent *) dirent_buf;
jfs_dirents = 0;
overflow = fix_page = 0;
stbl = DT_GETSTBL(p); stbl = DT_GETSTBL(p);
for (i = index; i < p->header.nextindex; i++) { for (i = index; i < p->header.nextindex; i++) {
d = (struct ldtentry *) & p->slot[stbl[i]]; d = (struct ldtentry *) & p->slot[stbl[i]];
if (((long) jfs_dirent + d->namlen + 1) >
(dirent_buf + PSIZE)) {
/* DBCS codepages could overrun dirent_buf */
index = i;
overflow = 1;
break;
}
d_namleft = d->namlen; d_namleft = d->namlen;
name_ptr = d_name; name_ptr = jfs_dirent->name;
jfs_dirent->ino = le32_to_cpu(d->inumber);
if (do_index) { if (do_index) {
filp->f_pos = le32_to_cpu(d->index);
len = min(d_namleft, DTLHDRDATALEN); len = min(d_namleft, DTLHDRDATALEN);
} else jfs_dirent->position = le32_to_cpu(d->index);
/*
* d->index should always be valid, but it
* isn't. fsck.jfs doesn't create the
* directory index for the lost+found
* directory. Rather than let it go,
* we can try to fix it.
*/
if ((jfs_dirent->position < 2) ||
(jfs_dirent->position >=
JFS_IP(ip)->next_index)) {
if (!page_fixed && !isReadOnly(ip)) {
fix_page = 1;
/*
* setting overflow and setting
* index to i will cause the
* same page to be processed
* again starting here
*/
overflow = 1;
index = i;
break;
}
jfs_dirent->position = unique_pos++;
}
} else {
jfs_dirent->position = dtpos;
len = min(d_namleft, DTLHDRDATALEN_LEGACY); len = min(d_namleft, DTLHDRDATALEN_LEGACY);
}
/* copy the name of head/only segment */ /* copy the name of head/only segment */
outlen = jfs_strfromUCS_le(name_ptr, d->name, len, outlen = jfs_strfromUCS_le(name_ptr, d->name, len,
codepage); codepage);
d_namlen = outlen; jfs_dirent->name_len = outlen;
/* copy name in the additional segment(s) */ /* copy name in the additional segment(s) */
next = d->next; next = d->next;
...@@ -3053,56 +3184,66 @@ int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir) ...@@ -3053,56 +3184,66 @@ int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
len = min(d_namleft, DTSLOTDATALEN); len = min(d_namleft, DTSLOTDATALEN);
outlen = jfs_strfromUCS_le(name_ptr, t->name, outlen = jfs_strfromUCS_le(name_ptr, t->name,
len, codepage); len, codepage);
d_namlen+= outlen; jfs_dirent->name_len += outlen;
next = t->next; next = t->next;
} }
if (filldir(dirent, d_name, d_namlen, filp->f_pos, jfs_dirents++;
le32_to_cpu(d->inumber), DT_UNKNOWN)) jfs_dirent = next_jfs_dirent(jfs_dirent);
goto out;
skip_one: skip_one:
if (!do_index) if (!do_index)
dtoffset->index++; dtoffset->index++;
} }
/* if (!overflow) {
* get next leaf page /* Point to next leaf page */
*/ if (p->header.flag & BT_ROOT)
bn = 0;
else {
bn = le64_to_cpu(p->header.next);
index = 0;
/* update offset (pn:index) for new page */
if (!do_index) {
dtoffset->pn++;
dtoffset->index = 0;
}
}
page_fixed = 0;
}
if (p->header.flag & BT_ROOT) { /* unpin previous leaf page */
filp->f_pos = DIREND; DT_PUTPAGE(mp);
break;
jfs_dirent = (struct jfs_dirent *) dirent_buf;
while (jfs_dirents--) {
filp->f_pos = jfs_dirent->position;
if (filldir(dirent, jfs_dirent->name,
jfs_dirent->name_len, filp->f_pos,
jfs_dirent->ino, DT_UNKNOWN))
goto out;
jfs_dirent = next_jfs_dirent(jfs_dirent);
} }
bn = le64_to_cpu(p->header.next); if (fix_page) {
if (bn == 0) { add_missing_indices(ip, bn);
page_fixed = 1;
}
if (!overflow && (bn == 0)) {
filp->f_pos = DIREND; filp->f_pos = DIREND;
break; break;
} }
/* unpin previous leaf page */
DT_PUTPAGE(mp);
/* get next leaf page */
DT_GETPAGE(ip, bn, mp, PSIZE, p, rc); DT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
if (rc) { if (rc) {
kfree(d_name); free_page(dirent_buf);
return -rc; return -rc;
} }
/* update offset (pn:index) for new page */
index = 0;
if (!do_index) {
dtoffset->pn++;
dtoffset->index = 0;
}
} }
out: out:
kfree(d_name); free_page(dirent_buf);
DT_PUTPAGE(mp);
return rc; return rc;
} }
......
...@@ -365,11 +365,7 @@ int diRead(struct inode *ip) ...@@ -365,11 +365,7 @@ int diRead(struct inode *ip)
if ((lengthPXD(&iagp->inoext[extno]) != imap->im_nbperiext) || if ((lengthPXD(&iagp->inoext[extno]) != imap->im_nbperiext) ||
(addressPXD(&iagp->inoext[extno]) == 0)) { (addressPXD(&iagp->inoext[extno]) == 0)) {
jERROR(1, ("diRead: Bad inoext: 0x%lx, 0x%lx\n",
(ulong) addressPXD(&iagp->inoext[extno]),
(ulong) lengthPXD(&iagp->inoext[extno])));
release_metapage(mp); release_metapage(mp);
updateSuper(ip->i_sb, FM_DIRTY);
return ESTALE; return ESTALE;
} }
...@@ -416,12 +412,9 @@ int diRead(struct inode *ip) ...@@ -416,12 +412,9 @@ int diRead(struct inode *ip)
jERROR(1, ("diRead: i_ino != di_number\n")); jERROR(1, ("diRead: i_ino != di_number\n"));
updateSuper(ip->i_sb, FM_DIRTY); updateSuper(ip->i_sb, FM_DIRTY);
rc = EIO; rc = EIO;
} else if (le32_to_cpu(dp->di_nlink) == 0) { } else if (le32_to_cpu(dp->di_nlink) == 0)
jERROR(1,
("diRead: di_nlink is zero. ino=%ld\n", ip->i_ino));
updateSuper(ip->i_sb, FM_DIRTY);
rc = ESTALE; rc = ESTALE;
} else else
/* copy the disk inode to the in-memory inode */ /* copy the disk inode to the in-memory inode */
rc = copy_from_dinode(dp, ip); rc = copy_from_dinode(dp, ip);
......
...@@ -1552,7 +1552,12 @@ static int lmLogFileSystem(struct jfs_log * log, char *uuid, int activate) ...@@ -1552,7 +1552,12 @@ static int lmLogFileSystem(struct jfs_log * log, char *uuid, int activate)
memcpy(logsuper->active[i].uuid, NULL_UUID, 16); memcpy(logsuper->active[i].uuid, NULL_UUID, 16);
break; break;
} }
assert(i < MAX_ACTIVE); if (i == MAX_ACTIVE) {
jERROR(1,("Somebody stomped on the journal!\n"));
lbmFree(bpsuper);
return EIO;
}
} }
/* /*
......
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