|
|
| version 1.536, 2007/08/24 16:18:10 | version 1.537, 2007/09/10 15:51:42 |
|---|---|
| Line 981 xfs_sync_inodes( | Line 981 xfs_sync_inodes( |
| int *bypassed) | int *bypassed) |
| { | { |
| xfs_inode_t *ip = NULL; | xfs_inode_t *ip = NULL; |
| xfs_inode_t *ip_next; | |
| xfs_buf_t *bp; | |
| bhv_vnode_t *vp = NULL; | bhv_vnode_t *vp = NULL; |
| int error; | int error; |
| int last_error; | int last_error; |
| Line 992 xfs_sync_inodes( | Line 990 xfs_sync_inodes( |
| boolean_t mount_locked; | boolean_t mount_locked; |
| boolean_t vnode_refed; | boolean_t vnode_refed; |
| int preempt; | int preempt; |
| xfs_dinode_t *dip; | |
| xfs_iptr_t *ipointer; | xfs_iptr_t *ipointer; |
| #ifdef DEBUG | #ifdef DEBUG |
| boolean_t ipointer_in = B_FALSE; | boolean_t ipointer_in = B_FALSE; |
| Line 1045 xfs_sync_inodes( | Line 1042 xfs_sync_inodes( |
| #define XFS_PREEMPT_MASK 0x7f | #define XFS_PREEMPT_MASK 0x7f |
| ASSERT(!(flags & SYNC_BDFLUSH)); | |
| if (bypassed) | if (bypassed) |
| *bypassed = 0; | *bypassed = 0; |
| if (mp->m_flags & XFS_MOUNT_RDONLY) | if (mp->m_flags & XFS_MOUNT_RDONLY) |
| Line 1057 xfs_sync_inodes( | Line 1056 xfs_sync_inodes( |
| ipointer = (xfs_iptr_t *)kmem_zalloc(sizeof(xfs_iptr_t), KM_SLEEP); | ipointer = (xfs_iptr_t *)kmem_zalloc(sizeof(xfs_iptr_t), KM_SLEEP); |
| fflag = XFS_B_ASYNC; /* default is don't wait */ | fflag = XFS_B_ASYNC; /* default is don't wait */ |
| if (flags & (SYNC_BDFLUSH | SYNC_DELWRI)) | if (flags & SYNC_DELWRI) |
| fflag = XFS_B_DELWRI; | fflag = XFS_B_DELWRI; |
| if (flags & SYNC_WAIT) | if (flags & SYNC_WAIT) |
| fflag = 0; /* synchronous overrides all */ | fflag = 0; /* synchronous overrides all */ |
| Line 1147 xfs_sync_inodes( | Line 1146 xfs_sync_inodes( |
| } | } |
| /* | /* |
| * If this is just vfs_sync() or pflushd() calling | |
| * then we can skip inodes for which it looks like | |
| * there is nothing to do. Since we don't have the | |
| * inode locked this is racy, but these are periodic | |
| * calls so it doesn't matter. For the others we want | |
| * to know for sure, so we at least try to lock them. | |
| */ | |
| if (flags & SYNC_BDFLUSH) { | |
| if (((ip->i_itemp == NULL) || | |
| !(ip->i_itemp->ili_format.ilf_fields & | |
| XFS_ILOG_ALL)) && | |
| (ip->i_update_core == 0)) { | |
| ip = ip->i_mnext; | |
| continue; | |
| } | |
| } | |
| /* | |
| * Try to lock without sleeping. We're out of order with | * Try to lock without sleeping. We're out of order with |
| * the inode list lock here, so if we fail we need to drop | * the inode list lock here, so if we fail we need to drop |
| * the mount lock and try again. If we're called from | * the mount lock and try again. If we're called from |
| Line 1181 xfs_sync_inodes( | Line 1162 xfs_sync_inodes( |
| * it. | * it. |
| */ | */ |
| if (xfs_ilock_nowait(ip, lock_flags) == 0) { | if (xfs_ilock_nowait(ip, lock_flags) == 0) { |
| if ((flags & SYNC_BDFLUSH) || (vp == NULL)) { | if (vp == NULL) { |
| ip = ip->i_mnext; | ip = ip->i_mnext; |
| continue; | continue; |
| } | } |
| Line 1242 xfs_sync_inodes( | Line 1223 xfs_sync_inodes( |
| xfs_ilock(ip, XFS_ILOCK_SHARED); | xfs_ilock(ip, XFS_ILOCK_SHARED); |
| } | } |
| if (flags & SYNC_BDFLUSH) { | if ((flags & SYNC_ATTR) && |
| if ((flags & SYNC_ATTR) && | (ip->i_update_core || |
| ((ip->i_update_core) || | (ip->i_itemp && ip->i_itemp->ili_format.ilf_fields))) { |
| ((ip->i_itemp != NULL) && | if (mount_locked) |
| (ip->i_itemp->ili_format.ilf_fields != 0)))) { | IPOINTER_INSERT(ip, mp); |
| /* Insert marker and drop lock if not already | |
| * done. | |
| */ | |
| if (mount_locked) { | |
| IPOINTER_INSERT(ip, mp); | |
| } | |
| /* | |
| * We don't want the periodic flushing of the | |
| * inodes by vfs_sync() to interfere with | |
| * I/O to the file, especially read I/O | |
| * where it is only the access time stamp | |
| * that is being flushed out. To prevent | |
| * long periods where we have both inode | |
| * locks held shared here while reading the | |
| * inode's buffer in from disk, we drop the | |
| * inode lock while reading in the inode | |
| * buffer. We have to release the buffer | |
| * and reacquire the inode lock so that they | |
| * are acquired in the proper order (inode | |
| * locks first). The buffer will go at the | |
| * end of the lru chain, though, so we can | |
| * expect it to still be there when we go | |
| * for it again in xfs_iflush(). | |
| */ | |
| if ((xfs_ipincount(ip) == 0) && | |
| xfs_iflock_nowait(ip)) { | |
| xfs_ifunlock(ip); | |
| xfs_iunlock(ip, XFS_ILOCK_SHARED); | |
| error = xfs_itobp(mp, NULL, ip, | |
| &dip, &bp, 0, 0); | |
| if (!error) { | |
| xfs_buf_relse(bp); | |
| } else { | |
| /* Bailing out, remove the | |
| * marker and free it. | |
| */ | |
| XFS_MOUNT_ILOCK(mp); | |
| IPOINTER_REMOVE(ip, mp); | |
| XFS_MOUNT_IUNLOCK(mp); | |
| ASSERT(!(lock_flags & | |
| XFS_IOLOCK_SHARED)); | |
| kmem_free(ipointer, | |
| sizeof(xfs_iptr_t)); | |
| return (0); | |
| } | |
| /* | |
| * Since we dropped the inode lock, | |
| * the inode may have been reclaimed. | |
| * Therefore, we reacquire the mount | |
| * lock and check to see if we were the | |
| * inode reclaimed. If this happened | |
| * then the ipointer marker will no | |
| * longer point back at us. In this | |
| * case, move ip along to the inode | |
| * after the marker, remove the marker | |
| * and continue. | |
| */ | |
| XFS_MOUNT_ILOCK(mp); | |
| mount_locked = B_TRUE; | |
| if (ip != ipointer->ip_mprev) { | |
| IPOINTER_REMOVE(ip, mp); | |
| ASSERT(!vnode_refed); | |
| ASSERT(!(lock_flags & | |
| XFS_IOLOCK_SHARED)); | |
| continue; | |
| } | |
| ASSERT(ip->i_mount == mp); | |
| if (xfs_ilock_nowait(ip, | |
| XFS_ILOCK_SHARED) == 0) { | |
| ASSERT(ip->i_mount == mp); | |
| /* | |
| * We failed to reacquire | |
| * the inode lock without | |
| * sleeping, so just skip | |
| * the inode for now. We | |
| * clear the ILOCK bit from | |
| * the lock_flags so that we | |
| * won't try to drop a lock | |
| * we don't hold below. | |
| */ | |
| lock_flags &= ~XFS_ILOCK_SHARED; | |
| IPOINTER_REMOVE(ip_next, mp); | |
| } else if ((xfs_ipincount(ip) == 0) && | |
| xfs_iflock_nowait(ip)) { | |
| ASSERT(ip->i_mount == mp); | |
| /* | |
| * Since this is vfs_sync() | |
| * calling we only flush the | |
| * inode out if we can lock | |
| * it without sleeping and | |
| * it is not pinned. Drop | |
| * the mount lock here so | |
| * that we don't hold it for | |
| * too long. We already have | |
| * a marker in the list here. | |
| */ | |
| XFS_MOUNT_IUNLOCK(mp); | |
| mount_locked = B_FALSE; | |
| error = xfs_iflush(ip, | |
| XFS_IFLUSH_DELWRI); | |
| } else { | |
| ASSERT(ip->i_mount == mp); | |
| IPOINTER_REMOVE(ip_next, mp); | |
| } | |
| } | |
| } | |
| } else { | if (flags & SYNC_WAIT) { |
| if ((flags & SYNC_ATTR) && | xfs_iflock(ip); |
| ((ip->i_update_core) || | error = xfs_iflush(ip, XFS_IFLUSH_SYNC); |
| ((ip->i_itemp != NULL) && | |
| (ip->i_itemp->ili_format.ilf_fields != 0)))) { | |
| if (mount_locked) { | |
| IPOINTER_INSERT(ip, mp); | |
| } | |
| if (flags & SYNC_WAIT) { | /* |
| xfs_iflock(ip); | * If we can't acquire the flush lock, then the inode |
| error = xfs_iflush(ip, | * is already being flushed so don't bother waiting. |
| XFS_IFLUSH_SYNC); | * |
| } else { | * If we can lock it then do a delwri flush so we can |
| /* | * combine multiple inode flushes in each disk write. |
| * If we can't acquire the flush | */ |
| * lock, then the inode is already | } else if (xfs_iflock_nowait(ip)) { |
| * being flushed so don't bother | error = xfs_iflush(ip, XFS_IFLUSH_DELWRI); |
| * waiting. If we can lock it then | } else if (bypassed) { |
| * do a delwri flush so we can | (*bypassed)++; |
| * combine multiple inode flushes | |
| * in each disk write. | |
| */ | |
| if (xfs_iflock_nowait(ip)) { | |
| error = xfs_iflush(ip, | |
| XFS_IFLUSH_DELWRI); | |
| } | |
| else if (bypassed) | |
| (*bypassed)++; | |
| } | |
| } | } |
| } | } |