diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-12-30 20:48:25 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-12-30 20:48:25 -0500 |
commit | 6a94cb73064c952255336cc57731904174b2c58f (patch) | |
tree | d19cc835db0a21e01909a92772868e1ad96f99ff /fs/xfs/linux-2.6/xfs_iops.c | |
parent | f57fa1d6a6b3414e853d3d17e339ac48816e4406 (diff) | |
parent | 0a8c5395f90f06d128247844b2515c8bf3f2826b (diff) |
Merge branch 'for-linus' of git://oss.sgi.com/xfs/xfs
* 'for-linus' of git://oss.sgi.com/xfs/xfs: (184 commits)
[XFS] Fix race in xfs_write() between direct and buffered I/O with DMAPI
[XFS] handle unaligned data in xfs_bmbt_disk_get_all
[XFS] avoid memory allocations in xfs_fs_vcmn_err
[XFS] Fix speculative allocation beyond eof
[XFS] Remove XFS_BUF_SHUT() and friends
[XFS] Use the incore inode size in xfs_file_readdir()
[XFS] set b_error from bio error in xfs_buf_bio_end_io
[XFS] use inode_change_ok for setattr permission checking
[XFS] add a FMODE flag to make XFS invisible I/O less hacky
[XFS] resync headers with libxfs
[XFS] simplify projid check in xfs_rename
[XFS] replace b_fspriv with b_mount
[XFS] Remove unused tracing code
[XFS] Remove unnecessary assertion
[XFS] Remove unused variable in ktrace_free()
[XFS] Check return value of xfs_buf_get_noaddr()
[XFS] Fix hang after disallowed rename across directory quota domains
[XFS] Fix compile with CONFIG_COMPAT enabled
move inode tracing out of xfs_vnode.
move vn_iowait / vn_iowake into xfs_aops.c
...
Diffstat (limited to 'fs/xfs/linux-2.6/xfs_iops.c')
-rw-r--r-- | fs/xfs/linux-2.6/xfs_iops.c | 122 |
1 files changed, 103 insertions, 19 deletions
diff --git a/fs/xfs/linux-2.6/xfs_iops.c b/fs/xfs/linux-2.6/xfs_iops.c index 095d271f3434..7aa53fefc67f 100644 --- a/fs/xfs/linux-2.6/xfs_iops.c +++ b/fs/xfs/linux-2.6/xfs_iops.c | |||
@@ -53,6 +53,7 @@ | |||
53 | #include <linux/namei.h> | 53 | #include <linux/namei.h> |
54 | #include <linux/security.h> | 54 | #include <linux/security.h> |
55 | #include <linux/falloc.h> | 55 | #include <linux/falloc.h> |
56 | #include <linux/fiemap.h> | ||
56 | 57 | ||
57 | /* | 58 | /* |
58 | * Bring the atime in the XFS inode uptodate. | 59 | * Bring the atime in the XFS inode uptodate. |
@@ -64,14 +65,14 @@ xfs_synchronize_atime( | |||
64 | { | 65 | { |
65 | struct inode *inode = VFS_I(ip); | 66 | struct inode *inode = VFS_I(ip); |
66 | 67 | ||
67 | if (inode) { | 68 | if (!(inode->i_state & I_CLEAR)) { |
68 | ip->i_d.di_atime.t_sec = (__int32_t)inode->i_atime.tv_sec; | 69 | ip->i_d.di_atime.t_sec = (__int32_t)inode->i_atime.tv_sec; |
69 | ip->i_d.di_atime.t_nsec = (__int32_t)inode->i_atime.tv_nsec; | 70 | ip->i_d.di_atime.t_nsec = (__int32_t)inode->i_atime.tv_nsec; |
70 | } | 71 | } |
71 | } | 72 | } |
72 | 73 | ||
73 | /* | 74 | /* |
74 | * If the linux inode exists, mark it dirty. | 75 | * If the linux inode is valid, mark it dirty. |
75 | * Used when commiting a dirty inode into a transaction so that | 76 | * Used when commiting a dirty inode into a transaction so that |
76 | * the inode will get written back by the linux code | 77 | * the inode will get written back by the linux code |
77 | */ | 78 | */ |
@@ -81,7 +82,7 @@ xfs_mark_inode_dirty_sync( | |||
81 | { | 82 | { |
82 | struct inode *inode = VFS_I(ip); | 83 | struct inode *inode = VFS_I(ip); |
83 | 84 | ||
84 | if (inode) | 85 | if (!(inode->i_state & (I_WILL_FREE|I_FREEING|I_CLEAR))) |
85 | mark_inode_dirty_sync(inode); | 86 | mark_inode_dirty_sync(inode); |
86 | } | 87 | } |
87 | 88 | ||
@@ -128,7 +129,7 @@ xfs_ichgtime( | |||
128 | if (sync_it) { | 129 | if (sync_it) { |
129 | SYNCHRONIZE(); | 130 | SYNCHRONIZE(); |
130 | ip->i_update_core = 1; | 131 | ip->i_update_core = 1; |
131 | mark_inode_dirty_sync(inode); | 132 | xfs_mark_inode_dirty_sync(ip); |
132 | } | 133 | } |
133 | } | 134 | } |
134 | 135 | ||
@@ -158,8 +159,6 @@ xfs_init_security( | |||
158 | } | 159 | } |
159 | 160 | ||
160 | error = xfs_attr_set(ip, name, value, length, ATTR_SECURE); | 161 | error = xfs_attr_set(ip, name, value, length, ATTR_SECURE); |
161 | if (!error) | ||
162 | xfs_iflags_set(ip, XFS_IMODIFIED); | ||
163 | 162 | ||
164 | kfree(name); | 163 | kfree(name); |
165 | kfree(value); | 164 | kfree(value); |
@@ -260,7 +259,6 @@ xfs_vn_mknod( | |||
260 | error = _ACL_INHERIT(inode, mode, default_acl); | 259 | error = _ACL_INHERIT(inode, mode, default_acl); |
261 | if (unlikely(error)) | 260 | if (unlikely(error)) |
262 | goto out_cleanup_inode; | 261 | goto out_cleanup_inode; |
263 | xfs_iflags_set(ip, XFS_IMODIFIED); | ||
264 | _ACL_FREE(default_acl); | 262 | _ACL_FREE(default_acl); |
265 | } | 263 | } |
266 | 264 | ||
@@ -366,21 +364,17 @@ xfs_vn_link( | |||
366 | struct inode *dir, | 364 | struct inode *dir, |
367 | struct dentry *dentry) | 365 | struct dentry *dentry) |
368 | { | 366 | { |
369 | struct inode *inode; /* inode of guy being linked to */ | 367 | struct inode *inode = old_dentry->d_inode; |
370 | struct xfs_name name; | 368 | struct xfs_name name; |
371 | int error; | 369 | int error; |
372 | 370 | ||
373 | inode = old_dentry->d_inode; | ||
374 | xfs_dentry_to_name(&name, dentry); | 371 | xfs_dentry_to_name(&name, dentry); |
375 | 372 | ||
376 | igrab(inode); | ||
377 | error = xfs_link(XFS_I(dir), XFS_I(inode), &name); | 373 | error = xfs_link(XFS_I(dir), XFS_I(inode), &name); |
378 | if (unlikely(error)) { | 374 | if (unlikely(error)) |
379 | iput(inode); | ||
380 | return -error; | 375 | return -error; |
381 | } | ||
382 | 376 | ||
383 | xfs_iflags_set(XFS_I(dir), XFS_IMODIFIED); | 377 | atomic_inc(&inode->i_count); |
384 | d_instantiate(dentry, inode); | 378 | d_instantiate(dentry, inode); |
385 | return 0; | 379 | return 0; |
386 | } | 380 | } |
@@ -601,7 +595,7 @@ xfs_vn_setattr( | |||
601 | struct dentry *dentry, | 595 | struct dentry *dentry, |
602 | struct iattr *iattr) | 596 | struct iattr *iattr) |
603 | { | 597 | { |
604 | return -xfs_setattr(XFS_I(dentry->d_inode), iattr, 0, NULL); | 598 | return -xfs_setattr(XFS_I(dentry->d_inode), iattr, 0); |
605 | } | 599 | } |
606 | 600 | ||
607 | /* | 601 | /* |
@@ -642,7 +636,7 @@ xfs_vn_fallocate( | |||
642 | 636 | ||
643 | xfs_ilock(ip, XFS_IOLOCK_EXCL); | 637 | xfs_ilock(ip, XFS_IOLOCK_EXCL); |
644 | error = xfs_change_file_space(ip, XFS_IOC_RESVSP, &bf, | 638 | error = xfs_change_file_space(ip, XFS_IOC_RESVSP, &bf, |
645 | 0, NULL, XFS_ATTR_NOLOCK); | 639 | 0, XFS_ATTR_NOLOCK); |
646 | if (!error && !(mode & FALLOC_FL_KEEP_SIZE) && | 640 | if (!error && !(mode & FALLOC_FL_KEEP_SIZE) && |
647 | offset + len > i_size_read(inode)) | 641 | offset + len > i_size_read(inode)) |
648 | new_size = offset + len; | 642 | new_size = offset + len; |
@@ -653,7 +647,7 @@ xfs_vn_fallocate( | |||
653 | 647 | ||
654 | iattr.ia_valid = ATTR_SIZE; | 648 | iattr.ia_valid = ATTR_SIZE; |
655 | iattr.ia_size = new_size; | 649 | iattr.ia_size = new_size; |
656 | error = xfs_setattr(ip, &iattr, XFS_ATTR_NOLOCK, NULL); | 650 | error = xfs_setattr(ip, &iattr, XFS_ATTR_NOLOCK); |
657 | } | 651 | } |
658 | 652 | ||
659 | xfs_iunlock(ip, XFS_IOLOCK_EXCL); | 653 | xfs_iunlock(ip, XFS_IOLOCK_EXCL); |
@@ -661,6 +655,88 @@ out_error: | |||
661 | return error; | 655 | return error; |
662 | } | 656 | } |
663 | 657 | ||
658 | #define XFS_FIEMAP_FLAGS (FIEMAP_FLAG_SYNC|FIEMAP_FLAG_XATTR) | ||
659 | |||
660 | /* | ||
661 | * Call fiemap helper to fill in user data. | ||
662 | * Returns positive errors to xfs_getbmap. | ||
663 | */ | ||
664 | STATIC int | ||
665 | xfs_fiemap_format( | ||
666 | void **arg, | ||
667 | struct getbmapx *bmv, | ||
668 | int *full) | ||
669 | { | ||
670 | int error; | ||
671 | struct fiemap_extent_info *fieinfo = *arg; | ||
672 | u32 fiemap_flags = 0; | ||
673 | u64 logical, physical, length; | ||
674 | |||
675 | /* Do nothing for a hole */ | ||
676 | if (bmv->bmv_block == -1LL) | ||
677 | return 0; | ||
678 | |||
679 | logical = BBTOB(bmv->bmv_offset); | ||
680 | physical = BBTOB(bmv->bmv_block); | ||
681 | length = BBTOB(bmv->bmv_length); | ||
682 | |||
683 | if (bmv->bmv_oflags & BMV_OF_PREALLOC) | ||
684 | fiemap_flags |= FIEMAP_EXTENT_UNWRITTEN; | ||
685 | else if (bmv->bmv_oflags & BMV_OF_DELALLOC) { | ||
686 | fiemap_flags |= FIEMAP_EXTENT_DELALLOC; | ||
687 | physical = 0; /* no block yet */ | ||
688 | } | ||
689 | if (bmv->bmv_oflags & BMV_OF_LAST) | ||
690 | fiemap_flags |= FIEMAP_EXTENT_LAST; | ||
691 | |||
692 | error = fiemap_fill_next_extent(fieinfo, logical, physical, | ||
693 | length, fiemap_flags); | ||
694 | if (error > 0) { | ||
695 | error = 0; | ||
696 | *full = 1; /* user array now full */ | ||
697 | } | ||
698 | |||
699 | return -error; | ||
700 | } | ||
701 | |||
702 | STATIC int | ||
703 | xfs_vn_fiemap( | ||
704 | struct inode *inode, | ||
705 | struct fiemap_extent_info *fieinfo, | ||
706 | u64 start, | ||
707 | u64 length) | ||
708 | { | ||
709 | xfs_inode_t *ip = XFS_I(inode); | ||
710 | struct getbmapx bm; | ||
711 | int error; | ||
712 | |||
713 | error = fiemap_check_flags(fieinfo, XFS_FIEMAP_FLAGS); | ||
714 | if (error) | ||
715 | return error; | ||
716 | |||
717 | /* Set up bmap header for xfs internal routine */ | ||
718 | bm.bmv_offset = BTOBB(start); | ||
719 | /* Special case for whole file */ | ||
720 | if (length == FIEMAP_MAX_OFFSET) | ||
721 | bm.bmv_length = -1LL; | ||
722 | else | ||
723 | bm.bmv_length = BTOBB(length); | ||
724 | |||
725 | /* our formatter will tell xfs_getbmap when to stop. */ | ||
726 | bm.bmv_count = MAXEXTNUM; | ||
727 | bm.bmv_iflags = BMV_IF_PREALLOC; | ||
728 | if (fieinfo->fi_flags & FIEMAP_FLAG_XATTR) | ||
729 | bm.bmv_iflags |= BMV_IF_ATTRFORK; | ||
730 | if (!(fieinfo->fi_flags & FIEMAP_FLAG_SYNC)) | ||
731 | bm.bmv_iflags |= BMV_IF_DELALLOC; | ||
732 | |||
733 | error = xfs_getbmap(ip, &bm, xfs_fiemap_format, fieinfo); | ||
734 | if (error) | ||
735 | return -error; | ||
736 | |||
737 | return 0; | ||
738 | } | ||
739 | |||
664 | static const struct inode_operations xfs_inode_operations = { | 740 | static const struct inode_operations xfs_inode_operations = { |
665 | .permission = xfs_vn_permission, | 741 | .permission = xfs_vn_permission, |
666 | .truncate = xfs_vn_truncate, | 742 | .truncate = xfs_vn_truncate, |
@@ -671,6 +747,7 @@ static const struct inode_operations xfs_inode_operations = { | |||
671 | .removexattr = generic_removexattr, | 747 | .removexattr = generic_removexattr, |
672 | .listxattr = xfs_vn_listxattr, | 748 | .listxattr = xfs_vn_listxattr, |
673 | .fallocate = xfs_vn_fallocate, | 749 | .fallocate = xfs_vn_fallocate, |
750 | .fiemap = xfs_vn_fiemap, | ||
674 | }; | 751 | }; |
675 | 752 | ||
676 | static const struct inode_operations xfs_dir_inode_operations = { | 753 | static const struct inode_operations xfs_dir_inode_operations = { |
@@ -766,12 +843,20 @@ xfs_diflags_to_iflags( | |||
766 | * When reading existing inodes from disk this is called directly | 843 | * When reading existing inodes from disk this is called directly |
767 | * from xfs_iget, when creating a new inode it is called from | 844 | * from xfs_iget, when creating a new inode it is called from |
768 | * xfs_ialloc after setting up the inode. | 845 | * xfs_ialloc after setting up the inode. |
846 | * | ||
847 | * We are always called with an uninitialised linux inode here. | ||
848 | * We need to initialise the necessary fields and take a reference | ||
849 | * on it. | ||
769 | */ | 850 | */ |
770 | void | 851 | void |
771 | xfs_setup_inode( | 852 | xfs_setup_inode( |
772 | struct xfs_inode *ip) | 853 | struct xfs_inode *ip) |
773 | { | 854 | { |
774 | struct inode *inode = ip->i_vnode; | 855 | struct inode *inode = &ip->i_vnode; |
856 | |||
857 | inode->i_ino = ip->i_ino; | ||
858 | inode->i_state = I_NEW|I_LOCK; | ||
859 | inode_add_to_lists(ip->i_mount->m_super, inode); | ||
775 | 860 | ||
776 | inode->i_mode = ip->i_d.di_mode; | 861 | inode->i_mode = ip->i_d.di_mode; |
777 | inode->i_nlink = ip->i_d.di_nlink; | 862 | inode->i_nlink = ip->i_d.di_nlink; |
@@ -799,7 +884,6 @@ xfs_setup_inode( | |||
799 | inode->i_ctime.tv_sec = ip->i_d.di_ctime.t_sec; | 884 | inode->i_ctime.tv_sec = ip->i_d.di_ctime.t_sec; |
800 | inode->i_ctime.tv_nsec = ip->i_d.di_ctime.t_nsec; | 885 | inode->i_ctime.tv_nsec = ip->i_d.di_ctime.t_nsec; |
801 | xfs_diflags_to_iflags(inode, ip); | 886 | xfs_diflags_to_iflags(inode, ip); |
802 | xfs_iflags_clear(ip, XFS_IMODIFIED); | ||
803 | 887 | ||
804 | switch (inode->i_mode & S_IFMT) { | 888 | switch (inode->i_mode & S_IFMT) { |
805 | case S_IFREG: | 889 | case S_IFREG: |