diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/ocfs2/namei.c | 56 |
1 files changed, 37 insertions, 19 deletions
diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c index 7e9da946c777..5bd5f9948a2f 100644 --- a/fs/ocfs2/namei.c +++ b/fs/ocfs2/namei.c | |||
@@ -104,13 +104,6 @@ static int ocfs2_fill_new_dir(struct ocfs2_super *osb, | |||
104 | struct buffer_head *fe_bh, | 104 | struct buffer_head *fe_bh, |
105 | struct ocfs2_alloc_context *data_ac); | 105 | struct ocfs2_alloc_context *data_ac); |
106 | 106 | ||
107 | static int ocfs2_double_lock(struct ocfs2_super *osb, | ||
108 | struct ocfs2_journal_handle *handle, | ||
109 | struct buffer_head **bh1, | ||
110 | struct inode *inode1, | ||
111 | struct buffer_head **bh2, | ||
112 | struct inode *inode2); | ||
113 | |||
114 | static int ocfs2_prepare_orphan_dir(struct ocfs2_super *osb, | 107 | static int ocfs2_prepare_orphan_dir(struct ocfs2_super *osb, |
115 | struct inode **ret_orphan_dir, | 108 | struct inode **ret_orphan_dir, |
116 | struct inode *inode, | 109 | struct inode *inode, |
@@ -992,7 +985,6 @@ leave: | |||
992 | * if they have the same id, then the 1st one is the only one locked. | 985 | * if they have the same id, then the 1st one is the only one locked. |
993 | */ | 986 | */ |
994 | static int ocfs2_double_lock(struct ocfs2_super *osb, | 987 | static int ocfs2_double_lock(struct ocfs2_super *osb, |
995 | struct ocfs2_journal_handle *handle, | ||
996 | struct buffer_head **bh1, | 988 | struct buffer_head **bh1, |
997 | struct inode *inode1, | 989 | struct inode *inode1, |
998 | struct buffer_head **bh2, | 990 | struct buffer_head **bh2, |
@@ -1008,8 +1000,6 @@ static int ocfs2_double_lock(struct ocfs2_super *osb, | |||
1008 | (unsigned long long)oi1->ip_blkno, | 1000 | (unsigned long long)oi1->ip_blkno, |
1009 | (unsigned long long)oi2->ip_blkno); | 1001 | (unsigned long long)oi2->ip_blkno); |
1010 | 1002 | ||
1011 | BUG_ON(!handle); | ||
1012 | |||
1013 | if (*bh1) | 1003 | if (*bh1) |
1014 | *bh1 = NULL; | 1004 | *bh1 = NULL; |
1015 | if (*bh2) | 1005 | if (*bh2) |
@@ -1029,25 +1019,41 @@ static int ocfs2_double_lock(struct ocfs2_super *osb, | |||
1029 | inode1 = tmpinode; | 1019 | inode1 = tmpinode; |
1030 | } | 1020 | } |
1031 | /* lock id2 */ | 1021 | /* lock id2 */ |
1032 | status = ocfs2_meta_lock(inode2, handle, bh2, 1); | 1022 | status = ocfs2_meta_lock(inode2, NULL, bh2, 1); |
1033 | if (status < 0) { | 1023 | if (status < 0) { |
1034 | if (status != -ENOENT) | 1024 | if (status != -ENOENT) |
1035 | mlog_errno(status); | 1025 | mlog_errno(status); |
1036 | goto bail; | 1026 | goto bail; |
1037 | } | 1027 | } |
1038 | } | 1028 | } |
1029 | |||
1039 | /* lock id1 */ | 1030 | /* lock id1 */ |
1040 | status = ocfs2_meta_lock(inode1, handle, bh1, 1); | 1031 | status = ocfs2_meta_lock(inode1, NULL, bh1, 1); |
1041 | if (status < 0) { | 1032 | if (status < 0) { |
1033 | /* | ||
1034 | * An error return must mean that no cluster locks | ||
1035 | * were held on function exit. | ||
1036 | */ | ||
1037 | if (oi1->ip_blkno != oi2->ip_blkno) | ||
1038 | ocfs2_meta_unlock(inode2, 1); | ||
1039 | |||
1042 | if (status != -ENOENT) | 1040 | if (status != -ENOENT) |
1043 | mlog_errno(status); | 1041 | mlog_errno(status); |
1044 | goto bail; | ||
1045 | } | 1042 | } |
1043 | |||
1046 | bail: | 1044 | bail: |
1047 | mlog_exit(status); | 1045 | mlog_exit(status); |
1048 | return status; | 1046 | return status; |
1049 | } | 1047 | } |
1050 | 1048 | ||
1049 | static void ocfs2_double_unlock(struct inode *inode1, struct inode *inode2) | ||
1050 | { | ||
1051 | ocfs2_meta_unlock(inode1, 1); | ||
1052 | |||
1053 | if (inode1 != inode2) | ||
1054 | ocfs2_meta_unlock(inode2, 1); | ||
1055 | } | ||
1056 | |||
1051 | #define PARENT_INO(buffer) \ | 1057 | #define PARENT_INO(buffer) \ |
1052 | ((struct ocfs2_dir_entry *) \ | 1058 | ((struct ocfs2_dir_entry *) \ |
1053 | ((char *)buffer + \ | 1059 | ((char *)buffer + \ |
@@ -1058,7 +1064,8 @@ static int ocfs2_rename(struct inode *old_dir, | |||
1058 | struct inode *new_dir, | 1064 | struct inode *new_dir, |
1059 | struct dentry *new_dentry) | 1065 | struct dentry *new_dentry) |
1060 | { | 1066 | { |
1061 | int status = 0, rename_lock = 0; | 1067 | int status = 0, rename_lock = 0, parents_locked = 0; |
1068 | int old_child_locked = 0, new_child_locked = 0; | ||
1062 | struct inode *old_inode = old_dentry->d_inode; | 1069 | struct inode *old_inode = old_dentry->d_inode; |
1063 | struct inode *new_inode = new_dentry->d_inode; | 1070 | struct inode *new_inode = new_dentry->d_inode; |
1064 | struct inode *orphan_dir = NULL; | 1071 | struct inode *orphan_dir = NULL; |
@@ -1122,13 +1129,13 @@ static int ocfs2_rename(struct inode *old_dir, | |||
1122 | } | 1129 | } |
1123 | 1130 | ||
1124 | /* if old and new are the same, this'll just do one lock. */ | 1131 | /* if old and new are the same, this'll just do one lock. */ |
1125 | status = ocfs2_double_lock(osb, handle, | 1132 | status = ocfs2_double_lock(osb, &old_dir_bh, old_dir, |
1126 | &old_dir_bh, old_dir, | 1133 | &new_dir_bh, new_dir); |
1127 | &new_dir_bh, new_dir); | ||
1128 | if (status < 0) { | 1134 | if (status < 0) { |
1129 | mlog_errno(status); | 1135 | mlog_errno(status); |
1130 | goto bail; | 1136 | goto bail; |
1131 | } | 1137 | } |
1138 | parents_locked = 1; | ||
1132 | 1139 | ||
1133 | /* make sure both dirs have bhs | 1140 | /* make sure both dirs have bhs |
1134 | * get an extra ref on old_dir_bh if old==new */ | 1141 | * get an extra ref on old_dir_bh if old==new */ |
@@ -1149,12 +1156,13 @@ static int ocfs2_rename(struct inode *old_dir, | |||
1149 | * the vote thread on other nodes won't have to concurrently | 1156 | * the vote thread on other nodes won't have to concurrently |
1150 | * downconvert the inode and the dentry locks. | 1157 | * downconvert the inode and the dentry locks. |
1151 | */ | 1158 | */ |
1152 | status = ocfs2_meta_lock(old_inode, handle, NULL, 1); | 1159 | status = ocfs2_meta_lock(old_inode, NULL, NULL, 1); |
1153 | if (status < 0) { | 1160 | if (status < 0) { |
1154 | if (status != -ENOENT) | 1161 | if (status != -ENOENT) |
1155 | mlog_errno(status); | 1162 | mlog_errno(status); |
1156 | goto bail; | 1163 | goto bail; |
1157 | } | 1164 | } |
1165 | old_child_locked = 1; | ||
1158 | 1166 | ||
1159 | status = ocfs2_remote_dentry_delete(old_dentry); | 1167 | status = ocfs2_remote_dentry_delete(old_dentry); |
1160 | if (status < 0) { | 1168 | if (status < 0) { |
@@ -1240,12 +1248,13 @@ static int ocfs2_rename(struct inode *old_dir, | |||
1240 | goto bail; | 1248 | goto bail; |
1241 | } | 1249 | } |
1242 | 1250 | ||
1243 | status = ocfs2_meta_lock(new_inode, handle, &newfe_bh, 1); | 1251 | status = ocfs2_meta_lock(new_inode, NULL, &newfe_bh, 1); |
1244 | if (status < 0) { | 1252 | if (status < 0) { |
1245 | if (status != -ENOENT) | 1253 | if (status != -ENOENT) |
1246 | mlog_errno(status); | 1254 | mlog_errno(status); |
1247 | goto bail; | 1255 | goto bail; |
1248 | } | 1256 | } |
1257 | new_child_locked = 1; | ||
1249 | 1258 | ||
1250 | status = ocfs2_remote_dentry_delete(new_dentry); | 1259 | status = ocfs2_remote_dentry_delete(new_dentry); |
1251 | if (status < 0) { | 1260 | if (status < 0) { |
@@ -1435,6 +1444,15 @@ bail: | |||
1435 | if (handle) | 1444 | if (handle) |
1436 | ocfs2_commit_trans(handle); | 1445 | ocfs2_commit_trans(handle); |
1437 | 1446 | ||
1447 | if (parents_locked) | ||
1448 | ocfs2_double_unlock(old_dir, new_dir); | ||
1449 | |||
1450 | if (old_child_locked) | ||
1451 | ocfs2_meta_unlock(old_inode, 1); | ||
1452 | |||
1453 | if (new_child_locked) | ||
1454 | ocfs2_meta_unlock(new_inode, 1); | ||
1455 | |||
1438 | if (orphan_dir) { | 1456 | if (orphan_dir) { |
1439 | /* This was locked for us in ocfs2_prepare_orphan_dir() */ | 1457 | /* This was locked for us in ocfs2_prepare_orphan_dir() */ |
1440 | ocfs2_meta_unlock(orphan_dir, 1); | 1458 | ocfs2_meta_unlock(orphan_dir, 1); |