Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 294625
b: refs/heads/master
c: 8a9c998
h: refs/heads/master
i:
  294623: fcdac82
v: v3
  • Loading branch information
Christoph Hellwig authored and Ben Myers committed Mar 13, 2012
1 parent b4d87b0 commit f03a3f5
Show file tree
Hide file tree
Showing 14 changed files with 66 additions and 322 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 281627df3eb55e1b729b9bb06fff5ff112929646
refs/heads/master: 8a9c9980f24f6d86e0ec0150ed35fba45d0c9f88
83 changes: 14 additions & 69 deletions trunk/fs/xfs/xfs_file.c
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,6 @@ xfs_file_fsync(
struct inode *inode = file->f_mapping->host;
struct xfs_inode *ip = XFS_I(inode);
struct xfs_mount *mp = ip->i_mount;
struct xfs_trans *tp;
int error = 0;
int log_flushed = 0;
xfs_lsn_t lsn = 0;
Expand Down Expand Up @@ -194,75 +193,15 @@ xfs_file_fsync(
}

/*
* We always need to make sure that the required inode state is safe on
* disk. The inode might be clean but we still might need to force the
* log because of committed transactions that haven't hit the disk yet.
* Likewise, there could be unflushed non-transactional changes to the
* inode core that have to go to disk and this requires us to issue
* a synchronous transaction to capture these changes correctly.
*
* This code relies on the assumption that if the i_update_core field
* of the inode is clear and the inode is unpinned then it is clean
* and no action is required.
* All metadata updates are logged, which means that we just have
* to flush the log up to the latest LSN that touched the inode.
*/
xfs_ilock(ip, XFS_ILOCK_SHARED);

/*
* First check if the VFS inode is marked dirty. All the dirtying
* of non-transactional updates do not go through mark_inode_dirty*,
* which allows us to distinguish between pure timestamp updates
* and i_size updates which need to be caught for fdatasync.
* After that also check for the dirty state in the XFS inode, which
* might gets cleared when the inode gets written out via the AIL
* or xfs_iflush_cluster.
*/
if (((inode->i_state & I_DIRTY_DATASYNC) ||
((inode->i_state & I_DIRTY_SYNC) && !datasync)) &&
ip->i_update_core) {
/*
* Kick off a transaction to log the inode core to get the
* updates. The sync transaction will also force the log.
*/
xfs_iunlock(ip, XFS_ILOCK_SHARED);
tp = xfs_trans_alloc(mp, XFS_TRANS_FSYNC_TS);
error = xfs_trans_reserve(tp, 0,
XFS_FSYNC_TS_LOG_RES(mp), 0, 0, 0);
if (error) {
xfs_trans_cancel(tp, 0);
return -error;
}
xfs_ilock(ip, XFS_ILOCK_EXCL);

/*
* Note - it's possible that we might have pushed ourselves out
* of the way during trans_reserve which would flush the inode.
* But there's no guarantee that the inode buffer has actually
* gone out yet (it's delwri). Plus the buffer could be pinned
* anyway if it's part of an inode in another recent
* transaction. So we play it safe and fire off the
* transaction anyway.
*/
xfs_trans_ijoin(tp, ip, 0);
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
error = xfs_trans_commit(tp, 0);

if (xfs_ipincount(ip))
lsn = ip->i_itemp->ili_last_lsn;
xfs_iunlock(ip, XFS_ILOCK_EXCL);
} else {
/*
* Timestamps/size haven't changed since last inode flush or
* inode transaction commit. That means either nothing got
* written or a transaction committed which caught the updates.
* If the latter happened and the transaction hasn't hit the
* disk yet, the inode will be still be pinned. If it is,
* force the log.
*/
if (xfs_ipincount(ip))
lsn = ip->i_itemp->ili_last_lsn;
xfs_iunlock(ip, XFS_ILOCK_SHARED);
}
xfs_iunlock(ip, XFS_ILOCK_SHARED);

if (!error && lsn)
if (lsn)
error = _xfs_log_force_lsn(mp, lsn, XFS_LOG_SYNC, &log_flushed);

/*
Expand Down Expand Up @@ -659,9 +598,6 @@ xfs_file_aio_write_checks(
return error;
}

if (likely(!(file->f_mode & FMODE_NOCMTIME)))
file_update_time(file);

/*
* If the offset is beyond the size of the file, we need to zero any
* blocks that fall between the existing EOF and the start of this
Expand All @@ -684,6 +620,15 @@ xfs_file_aio_write_checks(
if (error)
return error;

/*
* Updating the timestamps will grab the ilock again from
* xfs_fs_dirty_inode, so we have to call it after dropping the
* lock above. Eventually we should look into a way to avoid
* the pointless lock roundtrip.
*/
if (likely(!(file->f_mode & FMODE_NOCMTIME)))
file_update_time(file);

/*
* If we're writing the file then make sure to clear the setuid and
* setgid bits if the process is not being run by root. This keeps
Expand Down
1 change: 0 additions & 1 deletion trunk/fs/xfs/xfs_iget.c
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,6 @@ xfs_inode_alloc(
ip->i_afp = NULL;
memset(&ip->i_df, 0, sizeof(xfs_ifork_t));
ip->i_flags = 0;
ip->i_update_core = 0;
ip->i_delayed_blks = 0;
memset(&ip->i_d, 0, sizeof(xfs_icdinode_t));

Expand Down
25 changes: 1 addition & 24 deletions trunk/fs/xfs/xfs_inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -1656,7 +1656,6 @@ xfs_ifree_cluster(
iip = ip->i_itemp;
if (!iip || xfs_inode_clean(ip)) {
ASSERT(ip != free_ip);
ip->i_update_core = 0;
xfs_ifunlock(ip);
xfs_iunlock(ip, XFS_ILOCK_EXCL);
continue;
Expand Down Expand Up @@ -2451,7 +2450,6 @@ xfs_iflush(
* to disk, because the log record didn't make it to disk!
*/
if (XFS_FORCED_SHUTDOWN(mp)) {
ip->i_update_core = 0;
if (iip)
iip->ili_format.ilf_fields = 0;
xfs_ifunlock(ip);
Expand Down Expand Up @@ -2533,26 +2531,6 @@ xfs_iflush_int(
/* set *dip = inode's place in the buffer */
dip = (xfs_dinode_t *)xfs_buf_offset(bp, ip->i_imap.im_boffset);

/*
* Clear i_update_core before copying out the data.
* This is for coordination with our timestamp updates
* that don't hold the inode lock. They will always
* update the timestamps BEFORE setting i_update_core,
* so if we clear i_update_core after they set it we
* are guaranteed to see their updates to the timestamps.
* I believe that this depends on strongly ordered memory
* semantics, but we have that. We use the SYNCHRONIZE
* macro to make sure that the compiler does not reorder
* the i_update_core access below the data copy below.
*/
ip->i_update_core = 0;
SYNCHRONIZE();

/*
* Make sure to get the latest timestamps from the Linux inode.
*/
xfs_synchronize_times(ip);

if (XFS_TEST_ERROR(dip->di_magic != cpu_to_be16(XFS_DINODE_MAGIC),
mp, XFS_ERRTAG_IFLUSH_1, XFS_RANDOM_IFLUSH_1)) {
xfs_alert_tag(mp, XFS_PTAG_IFLUSH,
Expand Down Expand Up @@ -2711,8 +2689,7 @@ xfs_iflush_int(
} else {
/*
* We're flushing an inode which is not in the AIL and has
* not been logged but has i_update_core set. For this
* case we can use a B_DELWRI flush and immediately drop
* not been logged. For this case we can immediately drop
* the inode flush lock because we can avoid the whole
* AIL state thing. It's OK to drop the flush lock now,
* because we've already locked the buffer and to do anything
Expand Down
5 changes: 0 additions & 5 deletions trunk/fs/xfs/xfs_inode.h
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,6 @@ typedef struct xfs_inode {
spinlock_t i_flags_lock; /* inode i_flags lock */
/* Miscellaneous state. */
unsigned long i_flags; /* see defined flags below */
unsigned char i_update_core; /* timestamps/size is dirty */
unsigned int i_delayed_blks; /* count of delay alloc blks */

xfs_icdinode_t i_d; /* most of ondisk inode */
Expand Down Expand Up @@ -534,10 +533,6 @@ void xfs_promote_inode(struct xfs_inode *);
void xfs_lock_inodes(xfs_inode_t **, int, uint);
void xfs_lock_two_inodes(xfs_inode_t *, xfs_inode_t *, uint);

void xfs_synchronize_times(xfs_inode_t *);
void xfs_mark_inode_dirty(xfs_inode_t *);
void xfs_mark_inode_dirty_sync(xfs_inode_t *);

#define IHOLD(ip) \
do { \
ASSERT(atomic_read(&VFS_I(ip)->i_count) > 0) ; \
Expand Down
36 changes: 0 additions & 36 deletions trunk/fs/xfs/xfs_inode_item.c
Original file line number Diff line number Diff line change
Expand Up @@ -254,42 +254,6 @@ xfs_inode_item_format(
vecp++;
nvecs = 1;

/*
* Clear i_update_core if the timestamps (or any other
* non-transactional modification) need flushing/logging
* and we're about to log them with the rest of the core.
*
* This is the same logic as xfs_iflush() but this code can't
* run at the same time as xfs_iflush because we're in commit
* processing here and so we have the inode lock held in
* exclusive mode. Although it doesn't really matter
* for the timestamps if both routines were to grab the
* timestamps or not. That would be ok.
*
* We clear i_update_core before copying out the data.
* This is for coordination with our timestamp updates
* that don't hold the inode lock. They will always
* update the timestamps BEFORE setting i_update_core,
* so if we clear i_update_core after they set it we
* are guaranteed to see their updates to the timestamps
* either here. Likewise, if they set it after we clear it
* here, we'll see it either on the next commit of this
* inode or the next time the inode gets flushed via
* xfs_iflush(). This depends on strongly ordered memory
* semantics, but we have that. We use the SYNCHRONIZE
* macro to make sure that the compiler does not reorder
* the i_update_core access below the data copy below.
*/
if (ip->i_update_core) {
ip->i_update_core = 0;
SYNCHRONIZE();
}

/*
* Make sure to get the latest timestamps from the Linux inode.
*/
xfs_synchronize_times(ip);

vecp->i_addr = &ip->i_d;
vecp->i_len = sizeof(struct xfs_icdinode);
vecp->i_type = XLOG_REG_TYPE_ICORE;
Expand Down
5 changes: 2 additions & 3 deletions trunk/fs/xfs/xfs_inode_item.h
Original file line number Diff line number Diff line change
Expand Up @@ -148,9 +148,8 @@ typedef struct xfs_inode_log_item {

static inline int xfs_inode_clean(xfs_inode_t *ip)
{
return (!ip->i_itemp ||
!(ip->i_itemp->ili_format.ilf_fields & XFS_ILOG_ALL)) &&
!ip->i_update_core;
return !ip->i_itemp ||
!(ip->i_itemp->ili_format.ilf_fields & XFS_ILOG_ALL);
}

extern void xfs_inode_item_init(struct xfs_inode *, struct xfs_mount *);
Expand Down
58 changes: 0 additions & 58 deletions trunk/fs/xfs/xfs_iops.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,59 +50,6 @@
#include <linux/fiemap.h>
#include <linux/slab.h>

/*
* Bring the timestamps in the XFS inode uptodate.
*
* Used before writing the inode to disk.
*/
void
xfs_synchronize_times(
xfs_inode_t *ip)
{
struct inode *inode = VFS_I(ip);

ip->i_d.di_atime.t_sec = (__int32_t)inode->i_atime.tv_sec;
ip->i_d.di_atime.t_nsec = (__int32_t)inode->i_atime.tv_nsec;
ip->i_d.di_ctime.t_sec = (__int32_t)inode->i_ctime.tv_sec;
ip->i_d.di_ctime.t_nsec = (__int32_t)inode->i_ctime.tv_nsec;
ip->i_d.di_mtime.t_sec = (__int32_t)inode->i_mtime.tv_sec;
ip->i_d.di_mtime.t_nsec = (__int32_t)inode->i_mtime.tv_nsec;
}

/*
* If the linux inode is valid, mark it dirty, else mark the dirty state
* in the XFS inode to make sure we pick it up when reclaiming the inode.
*/
void
xfs_mark_inode_dirty_sync(
xfs_inode_t *ip)
{
struct inode *inode = VFS_I(ip);

if (!(inode->i_state & (I_WILL_FREE|I_FREEING)))
mark_inode_dirty_sync(inode);
else {
barrier();
ip->i_update_core = 1;
}
}

void
xfs_mark_inode_dirty(
xfs_inode_t *ip)
{
struct inode *inode = VFS_I(ip);

if (!(inode->i_state & (I_WILL_FREE|I_FREEING)))
mark_inode_dirty(inode);
else {
barrier();
ip->i_update_core = 1;
}

}


int xfs_initxattrs(struct inode *inode, const struct xattr *xattr_array,
void *fs_info)
{
Expand Down Expand Up @@ -678,19 +625,16 @@ xfs_setattr_nonsize(
inode->i_atime = iattr->ia_atime;
ip->i_d.di_atime.t_sec = iattr->ia_atime.tv_sec;
ip->i_d.di_atime.t_nsec = iattr->ia_atime.tv_nsec;
ip->i_update_core = 1;
}
if (mask & ATTR_CTIME) {
inode->i_ctime = iattr->ia_ctime;
ip->i_d.di_ctime.t_sec = iattr->ia_ctime.tv_sec;
ip->i_d.di_ctime.t_nsec = iattr->ia_ctime.tv_nsec;
ip->i_update_core = 1;
}
if (mask & ATTR_MTIME) {
inode->i_mtime = iattr->ia_mtime;
ip->i_d.di_mtime.t_sec = iattr->ia_mtime.tv_sec;
ip->i_d.di_mtime.t_nsec = iattr->ia_mtime.tv_nsec;
ip->i_update_core = 1;
}

xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
Expand Down Expand Up @@ -918,13 +862,11 @@ xfs_setattr_size(
inode->i_ctime = iattr->ia_ctime;
ip->i_d.di_ctime.t_sec = iattr->ia_ctime.tv_sec;
ip->i_d.di_ctime.t_nsec = iattr->ia_ctime.tv_nsec;
ip->i_update_core = 1;
}
if (mask & ATTR_MTIME) {
inode->i_mtime = iattr->ia_mtime;
ip->i_d.di_mtime.t_sec = iattr->ia_mtime.tv_sec;
ip->i_d.di_mtime.t_nsec = iattr->ia_mtime.tv_nsec;
ip->i_update_core = 1;
}

xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
Expand Down
21 changes: 6 additions & 15 deletions trunk/fs/xfs/xfs_itable.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ xfs_bulkstat_one_int(
{
struct xfs_icdinode *dic; /* dinode core info pointer */
struct xfs_inode *ip; /* incore inode pointer */
struct inode *inode;
struct xfs_bstat *buf; /* return buffer */
int error = 0; /* error value */

Expand All @@ -86,7 +85,6 @@ xfs_bulkstat_one_int(
ASSERT(ip->i_imap.im_blkno != 0);

dic = &ip->i_d;
inode = VFS_I(ip);

/* xfs_iget returns the following without needing
* further change.
Expand All @@ -99,19 +97,12 @@ xfs_bulkstat_one_int(
buf->bs_uid = dic->di_uid;
buf->bs_gid = dic->di_gid;
buf->bs_size = dic->di_size;

/*
* We need to read the timestamps from the Linux inode because
* the VFS keeps writing directly into the inode structure instead
* of telling us about the updates.
*/
buf->bs_atime.tv_sec = inode->i_atime.tv_sec;
buf->bs_atime.tv_nsec = inode->i_atime.tv_nsec;
buf->bs_mtime.tv_sec = inode->i_mtime.tv_sec;
buf->bs_mtime.tv_nsec = inode->i_mtime.tv_nsec;
buf->bs_ctime.tv_sec = inode->i_ctime.tv_sec;
buf->bs_ctime.tv_nsec = inode->i_ctime.tv_nsec;

buf->bs_atime.tv_sec = dic->di_atime.t_sec;
buf->bs_atime.tv_nsec = dic->di_atime.t_nsec;
buf->bs_mtime.tv_sec = dic->di_mtime.t_sec;
buf->bs_mtime.tv_nsec = dic->di_mtime.t_nsec;
buf->bs_ctime.tv_sec = dic->di_ctime.t_sec;
buf->bs_ctime.tv_nsec = dic->di_ctime.t_nsec;
buf->bs_xflags = xfs_ip2xflags(ip);
buf->bs_extsize = dic->di_extsize << mp->m_sb.sb_blocklog;
buf->bs_extents = dic->di_nextents;
Expand Down
Loading

0 comments on commit f03a3f5

Please sign in to comment.