diff options
author | Christoph Hellwig <hch@infradead.org> | 2010-02-15 04:44:48 -0500 |
---|---|---|
committer | Alex Elder <aelder@sgi.com> | 2010-03-01 17:34:38 -0500 |
commit | fd3200bef7d66ed3924f72c79a465fb7ff85478a (patch) | |
tree | f10c210269fc59854dd8f8b247b63454d772a574 /fs | |
parent | 00258e36b2d33b1b5cef7b489e06c5e0a9df58b5 (diff) |
xfs: remove wrapper for the fsync file operation
Currently the fsync file operation is divided into a low-level
routine doing all the work and one that implements the Linux file
operation and does minimal argument wrapping. This is a leftover
from the days of the vnode operations layer and can be removed to
simplify the code a bit, as well as preparing for the implementation
of an optimized fdatasync which needs to look at the Linux inode
state.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Alex Elder <aelder@sgi.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/xfs/linux-2.6/xfs_file.c | 140 | ||||
-rw-r--r-- | fs/xfs/xfs_vnodeops.c | 107 | ||||
-rw-r--r-- | fs/xfs/xfs_vnodeops.h | 1 |
3 files changed, 117 insertions, 131 deletions
diff --git a/fs/xfs/linux-2.6/xfs_file.c b/fs/xfs/linux-2.6/xfs_file.c index 1eb561a10e26..6c283b7be8ab 100644 --- a/fs/xfs/linux-2.6/xfs_file.c +++ b/fs/xfs/linux-2.6/xfs_file.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include "xfs_dir2_sf.h" | 35 | #include "xfs_dir2_sf.h" |
36 | #include "xfs_dinode.h" | 36 | #include "xfs_dinode.h" |
37 | #include "xfs_inode.h" | 37 | #include "xfs_inode.h" |
38 | #include "xfs_inode_item.h" | ||
38 | #include "xfs_bmap.h" | 39 | #include "xfs_bmap.h" |
39 | #include "xfs_error.h" | 40 | #include "xfs_error.h" |
40 | #include "xfs_rw.h" | 41 | #include "xfs_rw.h" |
@@ -96,6 +97,120 @@ xfs_iozero( | |||
96 | return (-status); | 97 | return (-status); |
97 | } | 98 | } |
98 | 99 | ||
100 | /* | ||
101 | * We ignore the datasync flag here because a datasync is effectively | ||
102 | * identical to an fsync. That is, datasync implies that we need to write | ||
103 | * only the metadata needed to be able to access the data that is written | ||
104 | * if we crash after the call completes. Hence if we are writing beyond | ||
105 | * EOF we have to log the inode size change as well, which makes it a | ||
106 | * full fsync. If we don't write beyond EOF, the inode core will be | ||
107 | * clean in memory and so we don't need to log the inode, just like | ||
108 | * fsync. | ||
109 | */ | ||
110 | STATIC int | ||
111 | xfs_file_fsync( | ||
112 | struct file *file, | ||
113 | struct dentry *dentry, | ||
114 | int datasync) | ||
115 | { | ||
116 | struct xfs_inode *ip = XFS_I(dentry->d_inode); | ||
117 | struct xfs_trans *tp; | ||
118 | int error = 0; | ||
119 | int log_flushed = 0; | ||
120 | |||
121 | xfs_itrace_entry(ip); | ||
122 | |||
123 | if (XFS_FORCED_SHUTDOWN(ip->i_mount)) | ||
124 | return -XFS_ERROR(EIO); | ||
125 | |||
126 | xfs_iflags_clear(ip, XFS_ITRUNCATED); | ||
127 | |||
128 | /* | ||
129 | * We always need to make sure that the required inode state is safe on | ||
130 | * disk. The inode might be clean but we still might need to force the | ||
131 | * log because of committed transactions that haven't hit the disk yet. | ||
132 | * Likewise, there could be unflushed non-transactional changes to the | ||
133 | * inode core that have to go to disk and this requires us to issue | ||
134 | * a synchronous transaction to capture these changes correctly. | ||
135 | * | ||
136 | * This code relies on the assumption that if the i_update_core field | ||
137 | * of the inode is clear and the inode is unpinned then it is clean | ||
138 | * and no action is required. | ||
139 | */ | ||
140 | xfs_ilock(ip, XFS_ILOCK_SHARED); | ||
141 | |||
142 | if (ip->i_update_core) { | ||
143 | /* | ||
144 | * Kick off a transaction to log the inode core to get the | ||
145 | * updates. The sync transaction will also force the log. | ||
146 | */ | ||
147 | xfs_iunlock(ip, XFS_ILOCK_SHARED); | ||
148 | tp = xfs_trans_alloc(ip->i_mount, XFS_TRANS_FSYNC_TS); | ||
149 | error = xfs_trans_reserve(tp, 0, | ||
150 | XFS_FSYNC_TS_LOG_RES(ip->i_mount), 0, 0, 0); | ||
151 | if (error) { | ||
152 | xfs_trans_cancel(tp, 0); | ||
153 | return -error; | ||
154 | } | ||
155 | xfs_ilock(ip, XFS_ILOCK_EXCL); | ||
156 | |||
157 | /* | ||
158 | * Note - it's possible that we might have pushed ourselves out | ||
159 | * of the way during trans_reserve which would flush the inode. | ||
160 | * But there's no guarantee that the inode buffer has actually | ||
161 | * gone out yet (it's delwri). Plus the buffer could be pinned | ||
162 | * anyway if it's part of an inode in another recent | ||
163 | * transaction. So we play it safe and fire off the | ||
164 | * transaction anyway. | ||
165 | */ | ||
166 | xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); | ||
167 | xfs_trans_ihold(tp, ip); | ||
168 | xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); | ||
169 | xfs_trans_set_sync(tp); | ||
170 | error = _xfs_trans_commit(tp, 0, &log_flushed); | ||
171 | |||
172 | xfs_iunlock(ip, XFS_ILOCK_EXCL); | ||
173 | } else { | ||
174 | /* | ||
175 | * Timestamps/size haven't changed since last inode flush or | ||
176 | * inode transaction commit. That means either nothing got | ||
177 | * written or a transaction committed which caught the updates. | ||
178 | * If the latter happened and the transaction hasn't hit the | ||
179 | * disk yet, the inode will be still be pinned. If it is, | ||
180 | * force the log. | ||
181 | */ | ||
182 | xfs_iunlock(ip, XFS_ILOCK_SHARED); | ||
183 | if (xfs_ipincount(ip)) { | ||
184 | if (ip->i_itemp->ili_last_lsn) { | ||
185 | error = _xfs_log_force_lsn(ip->i_mount, | ||
186 | ip->i_itemp->ili_last_lsn, | ||
187 | XFS_LOG_SYNC, &log_flushed); | ||
188 | } else { | ||
189 | error = _xfs_log_force(ip->i_mount, | ||
190 | XFS_LOG_SYNC, &log_flushed); | ||
191 | } | ||
192 | } | ||
193 | } | ||
194 | |||
195 | if (ip->i_mount->m_flags & XFS_MOUNT_BARRIER) { | ||
196 | /* | ||
197 | * If the log write didn't issue an ordered tag we need | ||
198 | * to flush the disk cache for the data device now. | ||
199 | */ | ||
200 | if (!log_flushed) | ||
201 | xfs_blkdev_issue_flush(ip->i_mount->m_ddev_targp); | ||
202 | |||
203 | /* | ||
204 | * If this inode is on the RT dev we need to flush that | ||
205 | * cache as well. | ||
206 | */ | ||
207 | if (XFS_IS_REALTIME_INODE(ip)) | ||
208 | xfs_blkdev_issue_flush(ip->i_mount->m_rtdev_targp); | ||
209 | } | ||
210 | |||
211 | return -error; | ||
212 | } | ||
213 | |||
99 | STATIC ssize_t | 214 | STATIC ssize_t |
100 | xfs_file_aio_read( | 215 | xfs_file_aio_read( |
101 | struct kiocb *iocb, | 216 | struct kiocb *iocb, |
@@ -755,7 +870,8 @@ write_retry: | |||
755 | mutex_lock(&inode->i_mutex); | 870 | mutex_lock(&inode->i_mutex); |
756 | xfs_ilock(ip, iolock); | 871 | xfs_ilock(ip, iolock); |
757 | 872 | ||
758 | error2 = xfs_fsync(ip); | 873 | error2 = -xfs_file_fsync(file, file->f_path.dentry, |
874 | (file->f_flags & __O_SYNC) ? 0 : 1); | ||
759 | if (!error) | 875 | if (!error) |
760 | error = error2; | 876 | error = error2; |
761 | } | 877 | } |
@@ -826,28 +942,6 @@ xfs_file_release( | |||
826 | return -xfs_release(XFS_I(inode)); | 942 | return -xfs_release(XFS_I(inode)); |
827 | } | 943 | } |
828 | 944 | ||
829 | /* | ||
830 | * We ignore the datasync flag here because a datasync is effectively | ||
831 | * identical to an fsync. That is, datasync implies that we need to write | ||
832 | * only the metadata needed to be able to access the data that is written | ||
833 | * if we crash after the call completes. Hence if we are writing beyond | ||
834 | * EOF we have to log the inode size change as well, which makes it a | ||
835 | * full fsync. If we don't write beyond EOF, the inode core will be | ||
836 | * clean in memory and so we don't need to log the inode, just like | ||
837 | * fsync. | ||
838 | */ | ||
839 | STATIC int | ||
840 | xfs_file_fsync( | ||
841 | struct file *file, | ||
842 | struct dentry *dentry, | ||
843 | int datasync) | ||
844 | { | ||
845 | struct xfs_inode *ip = XFS_I(dentry->d_inode); | ||
846 | |||
847 | xfs_iflags_clear(ip, XFS_ITRUNCATED); | ||
848 | return -xfs_fsync(ip); | ||
849 | } | ||
850 | |||
851 | STATIC int | 945 | STATIC int |
852 | xfs_file_readdir( | 946 | xfs_file_readdir( |
853 | struct file *filp, | 947 | struct file *filp, |
diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c index ddd2c5d1b854..9d376be0ea38 100644 --- a/fs/xfs/xfs_vnodeops.c +++ b/fs/xfs/xfs_vnodeops.c | |||
@@ -584,113 +584,6 @@ xfs_readlink( | |||
584 | } | 584 | } |
585 | 585 | ||
586 | /* | 586 | /* |
587 | * xfs_fsync | ||
588 | * | ||
589 | * This is called to sync the inode and its data out to disk. We need to hold | ||
590 | * the I/O lock while flushing the data, and the inode lock while flushing the | ||
591 | * inode. The inode lock CANNOT be held while flushing the data, so acquire | ||
592 | * after we're done with that. | ||
593 | */ | ||
594 | int | ||
595 | xfs_fsync( | ||
596 | xfs_inode_t *ip) | ||
597 | { | ||
598 | xfs_trans_t *tp; | ||
599 | int error = 0; | ||
600 | int log_flushed = 0; | ||
601 | |||
602 | xfs_itrace_entry(ip); | ||
603 | |||
604 | if (XFS_FORCED_SHUTDOWN(ip->i_mount)) | ||
605 | return XFS_ERROR(EIO); | ||
606 | |||
607 | /* | ||
608 | * We always need to make sure that the required inode state is safe on | ||
609 | * disk. The inode might be clean but we still might need to force the | ||
610 | * log because of committed transactions that haven't hit the disk yet. | ||
611 | * Likewise, there could be unflushed non-transactional changes to the | ||
612 | * inode core that have to go to disk and this requires us to issue | ||
613 | * a synchronous transaction to capture these changes correctly. | ||
614 | * | ||
615 | * This code relies on the assumption that if the update_* fields | ||
616 | * of the inode are clear and the inode is unpinned then it is clean | ||
617 | * and no action is required. | ||
618 | */ | ||
619 | xfs_ilock(ip, XFS_ILOCK_SHARED); | ||
620 | |||
621 | if (!ip->i_update_core) { | ||
622 | /* | ||
623 | * Timestamps/size haven't changed since last inode flush or | ||
624 | * inode transaction commit. That means either nothing got | ||
625 | * written or a transaction committed which caught the updates. | ||
626 | * If the latter happened and the transaction hasn't hit the | ||
627 | * disk yet, the inode will be still be pinned. If it is, | ||
628 | * force the log. | ||
629 | */ | ||
630 | xfs_iunlock(ip, XFS_ILOCK_SHARED); | ||
631 | if (xfs_ipincount(ip)) { | ||
632 | if (ip->i_itemp->ili_last_lsn) { | ||
633 | error = _xfs_log_force_lsn(ip->i_mount, | ||
634 | ip->i_itemp->ili_last_lsn, | ||
635 | XFS_LOG_SYNC, &log_flushed); | ||
636 | } else { | ||
637 | error = _xfs_log_force(ip->i_mount, | ||
638 | XFS_LOG_SYNC, &log_flushed); | ||
639 | } | ||
640 | } | ||
641 | } else { | ||
642 | /* | ||
643 | * Kick off a transaction to log the inode core to get the | ||
644 | * updates. The sync transaction will also force the log. | ||
645 | */ | ||
646 | xfs_iunlock(ip, XFS_ILOCK_SHARED); | ||
647 | tp = xfs_trans_alloc(ip->i_mount, XFS_TRANS_FSYNC_TS); | ||
648 | error = xfs_trans_reserve(tp, 0, | ||
649 | XFS_FSYNC_TS_LOG_RES(ip->i_mount), 0, 0, 0); | ||
650 | if (error) { | ||
651 | xfs_trans_cancel(tp, 0); | ||
652 | return error; | ||
653 | } | ||
654 | xfs_ilock(ip, XFS_ILOCK_EXCL); | ||
655 | |||
656 | /* | ||
657 | * Note - it's possible that we might have pushed ourselves out | ||
658 | * of the way during trans_reserve which would flush the inode. | ||
659 | * But there's no guarantee that the inode buffer has actually | ||
660 | * gone out yet (it's delwri). Plus the buffer could be pinned | ||
661 | * anyway if it's part of an inode in another recent | ||
662 | * transaction. So we play it safe and fire off the | ||
663 | * transaction anyway. | ||
664 | */ | ||
665 | xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); | ||
666 | xfs_trans_ihold(tp, ip); | ||
667 | xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); | ||
668 | xfs_trans_set_sync(tp); | ||
669 | error = _xfs_trans_commit(tp, 0, &log_flushed); | ||
670 | |||
671 | xfs_iunlock(ip, XFS_ILOCK_EXCL); | ||
672 | } | ||
673 | |||
674 | if (ip->i_mount->m_flags & XFS_MOUNT_BARRIER) { | ||
675 | /* | ||
676 | * If the log write didn't issue an ordered tag we need | ||
677 | * to flush the disk cache for the data device now. | ||
678 | */ | ||
679 | if (!log_flushed) | ||
680 | xfs_blkdev_issue_flush(ip->i_mount->m_ddev_targp); | ||
681 | |||
682 | /* | ||
683 | * If this inode is on the RT dev we need to flush that | ||
684 | * cache as well. | ||
685 | */ | ||
686 | if (XFS_IS_REALTIME_INODE(ip)) | ||
687 | xfs_blkdev_issue_flush(ip->i_mount->m_rtdev_targp); | ||
688 | } | ||
689 | |||
690 | return error; | ||
691 | } | ||
692 | |||
693 | /* | ||
694 | * Flags for xfs_free_eofblocks | 587 | * Flags for xfs_free_eofblocks |
695 | */ | 588 | */ |
696 | #define XFS_FREE_EOF_TRYLOCK (1<<0) | 589 | #define XFS_FREE_EOF_TRYLOCK (1<<0) |
diff --git a/fs/xfs/xfs_vnodeops.h b/fs/xfs/xfs_vnodeops.h index ee33e11d9872..36f3858736f6 100644 --- a/fs/xfs/xfs_vnodeops.h +++ b/fs/xfs/xfs_vnodeops.h | |||
@@ -21,7 +21,6 @@ int xfs_setattr(struct xfs_inode *ip, struct iattr *vap, int flags); | |||
21 | #define XFS_ATTR_NOACL 0x08 /* Don't call xfs_acl_chmod */ | 21 | #define XFS_ATTR_NOACL 0x08 /* Don't call xfs_acl_chmod */ |
22 | 22 | ||
23 | int xfs_readlink(struct xfs_inode *ip, char *link); | 23 | int xfs_readlink(struct xfs_inode *ip, char *link); |
24 | int xfs_fsync(struct xfs_inode *ip); | ||
25 | int xfs_release(struct xfs_inode *ip); | 24 | int xfs_release(struct xfs_inode *ip); |
26 | int xfs_inactive(struct xfs_inode *ip); | 25 | int xfs_inactive(struct xfs_inode *ip); |
27 | int xfs_lookup(struct xfs_inode *dp, struct xfs_name *name, | 26 | int xfs_lookup(struct xfs_inode *dp, struct xfs_name *name, |