Merge branch 'for-linus' of git://oss.sgi.com:8090/xfs/xfs-2.6

* 'for-linus' of git://oss.sgi.com:8090/xfs/xfs-2.6:
  [XFS] Fix xfs_ichgtime()s broken usage of I_SYNC
  [XFS] Make xfsbufd threads freezable
  [XFS] revert to double-buffering readdir
  [XFS] Fix broken inode cluster setup.
  [XFS] Clear XBF_READ_AHEAD flag on I/O completion.
  [XFS] Fixed a few bugs in xfs_buf_associate_memory()
  [XFS] 971064 Various fixups for xfs_bulkstat().
  [XFS] Fix dbflush panic in xfs_qm_sync.
This commit is contained in:
Linus Torvalds 2007-12-10 10:18:27 -08:00
commit 41f81e88e0
8 changed files with 185 additions and 49 deletions

View File

@ -725,15 +725,15 @@ xfs_buf_associate_memory(
{
int rval;
int i = 0;
size_t ptr;
size_t end, end_cur;
off_t offset;
unsigned long pageaddr;
unsigned long offset;
size_t buflen;
int page_count;
page_count = PAGE_CACHE_ALIGN(len) >> PAGE_CACHE_SHIFT;
offset = (off_t) mem - ((off_t)mem & PAGE_CACHE_MASK);
if (offset && (len > PAGE_CACHE_SIZE))
page_count++;
pageaddr = (unsigned long)mem & PAGE_CACHE_MASK;
offset = (unsigned long)mem - pageaddr;
buflen = PAGE_CACHE_ALIGN(len + offset);
page_count = buflen >> PAGE_CACHE_SHIFT;
/* Free any previous set of page pointers */
if (bp->b_pages)
@ -747,22 +747,15 @@ xfs_buf_associate_memory(
return rval;
bp->b_offset = offset;
ptr = (size_t) mem & PAGE_CACHE_MASK;
end = PAGE_CACHE_ALIGN((size_t) mem + len);
end_cur = end;
/* set up first page */
bp->b_pages[0] = mem_to_page(mem);
ptr += PAGE_CACHE_SIZE;
bp->b_page_count = ++i;
while (ptr < end) {
bp->b_pages[i] = mem_to_page((void *)ptr);
bp->b_page_count = ++i;
ptr += PAGE_CACHE_SIZE;
for (i = 0; i < bp->b_page_count; i++) {
bp->b_pages[i] = mem_to_page((void *)pageaddr);
pageaddr += PAGE_CACHE_SIZE;
}
bp->b_locked = 0;
bp->b_count_desired = bp->b_buffer_length = len;
bp->b_count_desired = len;
bp->b_buffer_length = buflen;
bp->b_flags |= XBF_MAPPED;
return 0;
@ -1032,7 +1025,7 @@ xfs_buf_ioend(
xfs_buf_t *bp,
int schedule)
{
bp->b_flags &= ~(XBF_READ | XBF_WRITE);
bp->b_flags &= ~(XBF_READ | XBF_WRITE | XBF_READ_AHEAD);
if (bp->b_error == 0)
bp->b_flags |= XBF_DONE;
@ -1750,6 +1743,8 @@ xfsbufd(
current->flags |= PF_MEMALLOC;
set_freezable();
do {
if (unlikely(freezing(current))) {
set_bit(XBT_FORCE_SLEEP, &target->bt_flags);

View File

@ -218,6 +218,15 @@ xfs_vm_fault(
}
#endif /* CONFIG_XFS_DMAPI */
/*
* Unfortunately we can't just use the clean and simple readdir implementation
* below, because nfs might call back into ->lookup from the filldir callback
* and that will deadlock the low-level btree code.
*
* Hopefully we'll find a better workaround that allows to use the optimal
* version at least for local readdirs for 2.6.25.
*/
#if 0
STATIC int
xfs_file_readdir(
struct file *filp,
@ -249,6 +258,121 @@ xfs_file_readdir(
return -error;
return 0;
}
#else
struct hack_dirent {
int namlen;
loff_t offset;
u64 ino;
unsigned int d_type;
char name[];
};
struct hack_callback {
char *dirent;
size_t len;
size_t used;
};
STATIC int
xfs_hack_filldir(
void *__buf,
const char *name,
int namlen,
loff_t offset,
u64 ino,
unsigned int d_type)
{
struct hack_callback *buf = __buf;
struct hack_dirent *de = (struct hack_dirent *)(buf->dirent + buf->used);
if (buf->used + sizeof(struct hack_dirent) + namlen > buf->len)
return -EINVAL;
de->namlen = namlen;
de->offset = offset;
de->ino = ino;
de->d_type = d_type;
memcpy(de->name, name, namlen);
buf->used += sizeof(struct hack_dirent) + namlen;
return 0;
}
STATIC int
xfs_file_readdir(
struct file *filp,
void *dirent,
filldir_t filldir)
{
struct inode *inode = filp->f_path.dentry->d_inode;
xfs_inode_t *ip = XFS_I(inode);
struct hack_callback buf;
struct hack_dirent *de;
int error;
loff_t size;
int eof = 0;
xfs_off_t start_offset, curr_offset, offset;
/*
* Try fairly hard to get memory
*/
buf.len = PAGE_CACHE_SIZE;
do {
buf.dirent = kmalloc(buf.len, GFP_KERNEL);
if (buf.dirent)
break;
buf.len >>= 1;
} while (buf.len >= 1024);
if (!buf.dirent)
return -ENOMEM;
curr_offset = filp->f_pos;
if (curr_offset == 0x7fffffff)
offset = 0xffffffff;
else
offset = filp->f_pos;
while (!eof) {
int reclen;
start_offset = offset;
buf.used = 0;
error = -xfs_readdir(ip, &buf, buf.len, &offset,
xfs_hack_filldir);
if (error || offset == start_offset) {
size = 0;
break;
}
size = buf.used;
de = (struct hack_dirent *)buf.dirent;
while (size > 0) {
if (filldir(dirent, de->name, de->namlen,
curr_offset & 0x7fffffff,
de->ino, de->d_type)) {
goto done;
}
reclen = sizeof(struct hack_dirent) + de->namlen;
size -= reclen;
curr_offset = de->offset /* & 0x7fffffff */;
de = (struct hack_dirent *)((char *)de + reclen);
}
}
done:
if (!error) {
if (size == 0)
filp->f_pos = offset & 0x7fffffff;
else if (de)
filp->f_pos = curr_offset;
}
kfree(buf.dirent);
return error;
}
#endif
STATIC int
xfs_file_mmap(

View File

@ -1047,24 +1047,20 @@ xfs_ioc_bulkstat(
if ((count = bulkreq.icount) <= 0)
return -XFS_ERROR(EINVAL);
if (bulkreq.ubuffer == NULL)
return -XFS_ERROR(EINVAL);
if (cmd == XFS_IOC_FSINUMBERS)
error = xfs_inumbers(mp, &inlast, &count,
bulkreq.ubuffer, xfs_inumbers_fmt);
else if (cmd == XFS_IOC_FSBULKSTAT_SINGLE)
error = xfs_bulkstat_single(mp, &inlast,
bulkreq.ubuffer, &done);
else { /* XFS_IOC_FSBULKSTAT */
if (count == 1 && inlast != 0) {
inlast++;
error = xfs_bulkstat_single(mp, &inlast,
bulkreq.ubuffer, &done);
} else {
error = xfs_bulkstat(mp, &inlast, &count,
(bulkstat_one_pf)xfs_bulkstat_one, NULL,
sizeof(xfs_bstat_t), bulkreq.ubuffer,
BULKSTAT_FG_QUICK, &done);
}
}
else /* XFS_IOC_FSBULKSTAT */
error = xfs_bulkstat(mp, &inlast, &count,
(bulkstat_one_pf)xfs_bulkstat_one, NULL,
sizeof(xfs_bstat_t), bulkreq.ubuffer,
BULKSTAT_FG_QUICK, &done);
if (error)
return -error;

View File

@ -291,6 +291,9 @@ xfs_ioc_bulkstat_compat(
if ((count = bulkreq.icount) <= 0)
return -XFS_ERROR(EINVAL);
if (bulkreq.ubuffer == NULL)
return -XFS_ERROR(EINVAL);
if (cmd == XFS_IOC_FSINUMBERS)
error = xfs_inumbers(mp, &inlast, &count,
bulkreq.ubuffer, xfs_inumbers_fmt_compat);

View File

@ -117,7 +117,7 @@ xfs_ichgtime(
*/
SYNCHRONIZE();
ip->i_update_core = 1;
if (!(inode->i_state & I_SYNC))
if (!(inode->i_state & I_NEW))
mark_inode_dirty_sync(inode);
}
@ -169,7 +169,7 @@ xfs_ichgtime_fast(
*/
SYNCHRONIZE();
ip->i_update_core = 1;
if (!(inode->i_state & I_SYNC))
if (!(inode->i_state & I_NEW))
mark_inode_dirty_sync(inode);
}

View File

@ -1008,6 +1008,9 @@ xfs_qm_sync(
boolean_t nowait;
int error;
if (! XFS_IS_QUOTA_ON(mp))
return 0;
restarts = 0;
/*
* We won't block unless we are asked to.

View File

@ -267,7 +267,7 @@ xfs_iget_core(
icl = NULL;
if (radix_tree_gang_lookup(&pag->pag_ici_root, (void**)&iq,
first_index, 1)) {
if ((iq->i_ino & mask) == first_index)
if ((XFS_INO_TO_AGINO(mp, iq->i_ino) & mask) == first_index)
icl = iq->i_cluster;
}

View File

@ -316,6 +316,8 @@ xfs_bulkstat_use_dinode(
return 1;
}
#define XFS_BULKSTAT_UBLEFT(ubleft) ((ubleft) >= statstruct_size)
/*
* Return stat information in bulk (by-inode) for the filesystem.
*/
@ -353,7 +355,7 @@ xfs_bulkstat(
xfs_inobt_rec_incore_t *irbp; /* current irec buffer pointer */
xfs_inobt_rec_incore_t *irbuf; /* start of irec buffer */
xfs_inobt_rec_incore_t *irbufend; /* end of good irec buffer entries */
xfs_ino_t lastino=0; /* last inode number returned */
xfs_ino_t lastino; /* last inode number returned */
int nbcluster; /* # of blocks in a cluster */
int nicluster; /* # of inodes in a cluster */
int nimask; /* mask for inode clusters */
@ -373,6 +375,7 @@ xfs_bulkstat(
* Get the last inode value, see if there's nothing to do.
*/
ino = (xfs_ino_t)*lastinop;
lastino = ino;
dip = NULL;
agno = XFS_INO_TO_AGNO(mp, ino);
agino = XFS_INO_TO_AGINO(mp, ino);
@ -382,6 +385,9 @@ xfs_bulkstat(
*ubcountp = 0;
return 0;
}
if (!ubcountp || *ubcountp <= 0) {
return EINVAL;
}
ubcount = *ubcountp; /* statstruct's */
ubleft = ubcount * statstruct_size; /* bytes */
*ubcountp = ubelem = 0;
@ -402,7 +408,8 @@ xfs_bulkstat(
* inode returned; 0 means start of the allocation group.
*/
rval = 0;
while (ubleft >= statstruct_size && agno < mp->m_sb.sb_agcount) {
while (XFS_BULKSTAT_UBLEFT(ubleft) && agno < mp->m_sb.sb_agcount) {
cond_resched();
bp = NULL;
down_read(&mp->m_peraglock);
error = xfs_ialloc_read_agi(mp, NULL, agno, &agbp);
@ -499,6 +506,7 @@ xfs_bulkstat(
break;
error = xfs_inobt_lookup_ge(cur, agino, 0, 0,
&tmp);
cond_resched();
}
/*
* If ran off the end of the ag either with an error,
@ -542,6 +550,7 @@ xfs_bulkstat(
*/
agino = gino + XFS_INODES_PER_CHUNK;
error = xfs_inobt_increment(cur, 0, &tmp);
cond_resched();
}
/*
* Drop the btree buffers and the agi buffer.
@ -555,12 +564,12 @@ xfs_bulkstat(
*/
irbufend = irbp;
for (irbp = irbuf;
irbp < irbufend && ubleft >= statstruct_size; irbp++) {
irbp < irbufend && XFS_BULKSTAT_UBLEFT(ubleft); irbp++) {
/*
* Now process this chunk of inodes.
*/
for (agino = irbp->ir_startino, chunkidx = clustidx = 0;
ubleft > 0 &&
XFS_BULKSTAT_UBLEFT(ubleft) &&
irbp->ir_freecount < XFS_INODES_PER_CHUNK;
chunkidx++, clustidx++, agino++) {
ASSERT(chunkidx < XFS_INODES_PER_CHUNK);
@ -663,15 +672,13 @@ xfs_bulkstat(
ubleft, private_data,
bno, &ubused, dip, &fmterror);
if (fmterror == BULKSTAT_RV_NOTHING) {
if (error == EFAULT) {
ubleft = 0;
rval = error;
break;
}
else if (error == ENOMEM)
if (error && error != ENOENT &&
error != EINVAL) {
ubleft = 0;
else
lastino = ino;
rval = error;
break;
}
lastino = ino;
continue;
}
if (fmterror == BULKSTAT_RV_GIVEUP) {
@ -686,6 +693,8 @@ xfs_bulkstat(
ubelem++;
lastino = ino;
}
cond_resched();
}
if (bp)
@ -694,11 +703,12 @@ xfs_bulkstat(
/*
* Set up for the next loop iteration.
*/
if (ubleft > 0) {
if (XFS_BULKSTAT_UBLEFT(ubleft)) {
if (end_of_ag) {
agno++;
agino = 0;
}
} else
agino = XFS_INO_TO_AGINO(mp, lastino);
} else
break;
}
@ -707,6 +717,11 @@ xfs_bulkstat(
*/
kmem_free(irbuf, irbsize);
*ubcountp = ubelem;
/*
* Found some inodes, return them now and return the error next time.
*/
if (ubelem)
rval = 0;
if (agno >= mp->m_sb.sb_agcount) {
/*
* If we ran out of filesystem, mark lastino as off