diff options
Diffstat (limited to 'fs/ocfs2/namei.c')
-rw-r--r-- | fs/ocfs2/namei.c | 145 |
1 files changed, 132 insertions, 13 deletions
diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c index 2060fc398445..8add6f1030d7 100644 --- a/fs/ocfs2/namei.c +++ b/fs/ocfs2/namei.c | |||
@@ -205,6 +205,21 @@ static struct inode *ocfs2_get_init_inode(struct inode *dir, umode_t mode) | |||
205 | return inode; | 205 | return inode; |
206 | } | 206 | } |
207 | 207 | ||
208 | static void ocfs2_cleanup_add_entry_failure(struct ocfs2_super *osb, | ||
209 | struct dentry *dentry, struct inode *inode) | ||
210 | { | ||
211 | struct ocfs2_dentry_lock *dl = dentry->d_fsdata; | ||
212 | |||
213 | ocfs2_simple_drop_lockres(osb, &dl->dl_lockres); | ||
214 | ocfs2_lock_res_free(&dl->dl_lockres); | ||
215 | BUG_ON(dl->dl_count != 1); | ||
216 | spin_lock(&dentry_attach_lock); | ||
217 | dentry->d_fsdata = NULL; | ||
218 | spin_unlock(&dentry_attach_lock); | ||
219 | kfree(dl); | ||
220 | iput(inode); | ||
221 | } | ||
222 | |||
208 | static int ocfs2_mknod(struct inode *dir, | 223 | static int ocfs2_mknod(struct inode *dir, |
209 | struct dentry *dentry, | 224 | struct dentry *dentry, |
210 | umode_t mode, | 225 | umode_t mode, |
@@ -231,6 +246,7 @@ static int ocfs2_mknod(struct inode *dir, | |||
231 | sigset_t oldset; | 246 | sigset_t oldset; |
232 | int did_block_signals = 0; | 247 | int did_block_signals = 0; |
233 | struct posix_acl *default_acl = NULL, *acl = NULL; | 248 | struct posix_acl *default_acl = NULL, *acl = NULL; |
249 | struct ocfs2_dentry_lock *dl = NULL; | ||
234 | 250 | ||
235 | trace_ocfs2_mknod(dir, dentry, dentry->d_name.len, dentry->d_name.name, | 251 | trace_ocfs2_mknod(dir, dentry, dentry->d_name.len, dentry->d_name.name, |
236 | (unsigned long long)OCFS2_I(dir)->ip_blkno, | 252 | (unsigned long long)OCFS2_I(dir)->ip_blkno, |
@@ -423,6 +439,8 @@ static int ocfs2_mknod(struct inode *dir, | |||
423 | goto leave; | 439 | goto leave; |
424 | } | 440 | } |
425 | 441 | ||
442 | dl = dentry->d_fsdata; | ||
443 | |||
426 | status = ocfs2_add_entry(handle, dentry, inode, | 444 | status = ocfs2_add_entry(handle, dentry, inode, |
427 | OCFS2_I(inode)->ip_blkno, parent_fe_bh, | 445 | OCFS2_I(inode)->ip_blkno, parent_fe_bh, |
428 | &lookup); | 446 | &lookup); |
@@ -469,6 +487,9 @@ leave: | |||
469 | * ocfs2_delete_inode will mutex_lock again. | 487 | * ocfs2_delete_inode will mutex_lock again. |
470 | */ | 488 | */ |
471 | if ((status < 0) && inode) { | 489 | if ((status < 0) && inode) { |
490 | if (dl) | ||
491 | ocfs2_cleanup_add_entry_failure(osb, dentry, inode); | ||
492 | |||
472 | OCFS2_I(inode)->ip_flags |= OCFS2_INODE_SKIP_ORPHAN_DIR; | 493 | OCFS2_I(inode)->ip_flags |= OCFS2_INODE_SKIP_ORPHAN_DIR; |
473 | clear_nlink(inode); | 494 | clear_nlink(inode); |
474 | iput(inode); | 495 | iput(inode); |
@@ -991,6 +1012,65 @@ leave: | |||
991 | return status; | 1012 | return status; |
992 | } | 1013 | } |
993 | 1014 | ||
1015 | static int ocfs2_check_if_ancestor(struct ocfs2_super *osb, | ||
1016 | u64 src_inode_no, u64 dest_inode_no) | ||
1017 | { | ||
1018 | int ret = 0, i = 0; | ||
1019 | u64 parent_inode_no = 0; | ||
1020 | u64 child_inode_no = src_inode_no; | ||
1021 | struct inode *child_inode; | ||
1022 | |||
1023 | #define MAX_LOOKUP_TIMES 32 | ||
1024 | while (1) { | ||
1025 | child_inode = ocfs2_iget(osb, child_inode_no, 0, 0); | ||
1026 | if (IS_ERR(child_inode)) { | ||
1027 | ret = PTR_ERR(child_inode); | ||
1028 | break; | ||
1029 | } | ||
1030 | |||
1031 | ret = ocfs2_inode_lock(child_inode, NULL, 0); | ||
1032 | if (ret < 0) { | ||
1033 | iput(child_inode); | ||
1034 | if (ret != -ENOENT) | ||
1035 | mlog_errno(ret); | ||
1036 | break; | ||
1037 | } | ||
1038 | |||
1039 | ret = ocfs2_lookup_ino_from_name(child_inode, "..", 2, | ||
1040 | &parent_inode_no); | ||
1041 | ocfs2_inode_unlock(child_inode, 0); | ||
1042 | iput(child_inode); | ||
1043 | if (ret < 0) { | ||
1044 | ret = -ENOENT; | ||
1045 | break; | ||
1046 | } | ||
1047 | |||
1048 | if (parent_inode_no == dest_inode_no) { | ||
1049 | ret = 1; | ||
1050 | break; | ||
1051 | } | ||
1052 | |||
1053 | if (parent_inode_no == osb->root_inode->i_ino) { | ||
1054 | ret = 0; | ||
1055 | break; | ||
1056 | } | ||
1057 | |||
1058 | child_inode_no = parent_inode_no; | ||
1059 | |||
1060 | if (++i >= MAX_LOOKUP_TIMES) { | ||
1061 | mlog(ML_NOTICE, "max lookup times reached, filesystem " | ||
1062 | "may have nested directories, " | ||
1063 | "src inode: %llu, dest inode: %llu.\n", | ||
1064 | (unsigned long long)src_inode_no, | ||
1065 | (unsigned long long)dest_inode_no); | ||
1066 | ret = 0; | ||
1067 | break; | ||
1068 | } | ||
1069 | } | ||
1070 | |||
1071 | return ret; | ||
1072 | } | ||
1073 | |||
994 | /* | 1074 | /* |
995 | * The only place this should be used is rename! | 1075 | * The only place this should be used is rename! |
996 | * if they have the same id, then the 1st one is the only one locked. | 1076 | * if they have the same id, then the 1st one is the only one locked. |
@@ -1002,6 +1082,7 @@ static int ocfs2_double_lock(struct ocfs2_super *osb, | |||
1002 | struct inode *inode2) | 1082 | struct inode *inode2) |
1003 | { | 1083 | { |
1004 | int status; | 1084 | int status; |
1085 | int inode1_is_ancestor, inode2_is_ancestor; | ||
1005 | struct ocfs2_inode_info *oi1 = OCFS2_I(inode1); | 1086 | struct ocfs2_inode_info *oi1 = OCFS2_I(inode1); |
1006 | struct ocfs2_inode_info *oi2 = OCFS2_I(inode2); | 1087 | struct ocfs2_inode_info *oi2 = OCFS2_I(inode2); |
1007 | struct buffer_head **tmpbh; | 1088 | struct buffer_head **tmpbh; |
@@ -1015,9 +1096,26 @@ static int ocfs2_double_lock(struct ocfs2_super *osb, | |||
1015 | if (*bh2) | 1096 | if (*bh2) |
1016 | *bh2 = NULL; | 1097 | *bh2 = NULL; |
1017 | 1098 | ||
1018 | /* we always want to lock the one with the lower lockid first. */ | 1099 | /* we always want to lock the one with the lower lockid first. |
1100 | * and if they are nested, we lock ancestor first */ | ||
1019 | if (oi1->ip_blkno != oi2->ip_blkno) { | 1101 | if (oi1->ip_blkno != oi2->ip_blkno) { |
1020 | if (oi1->ip_blkno < oi2->ip_blkno) { | 1102 | inode1_is_ancestor = ocfs2_check_if_ancestor(osb, oi2->ip_blkno, |
1103 | oi1->ip_blkno); | ||
1104 | if (inode1_is_ancestor < 0) { | ||
1105 | status = inode1_is_ancestor; | ||
1106 | goto bail; | ||
1107 | } | ||
1108 | |||
1109 | inode2_is_ancestor = ocfs2_check_if_ancestor(osb, oi1->ip_blkno, | ||
1110 | oi2->ip_blkno); | ||
1111 | if (inode2_is_ancestor < 0) { | ||
1112 | status = inode2_is_ancestor; | ||
1113 | goto bail; | ||
1114 | } | ||
1115 | |||
1116 | if ((inode1_is_ancestor == 1) || | ||
1117 | (oi1->ip_blkno < oi2->ip_blkno && | ||
1118 | inode2_is_ancestor == 0)) { | ||
1021 | /* switch id1 and id2 around */ | 1119 | /* switch id1 and id2 around */ |
1022 | tmpbh = bh2; | 1120 | tmpbh = bh2; |
1023 | bh2 = bh1; | 1121 | bh2 = bh1; |
@@ -1098,6 +1196,7 @@ static int ocfs2_rename(struct inode *old_dir, | |||
1098 | struct ocfs2_dir_lookup_result old_entry_lookup = { NULL, }; | 1196 | struct ocfs2_dir_lookup_result old_entry_lookup = { NULL, }; |
1099 | struct ocfs2_dir_lookup_result orphan_insert = { NULL, }; | 1197 | struct ocfs2_dir_lookup_result orphan_insert = { NULL, }; |
1100 | struct ocfs2_dir_lookup_result target_insert = { NULL, }; | 1198 | struct ocfs2_dir_lookup_result target_insert = { NULL, }; |
1199 | bool should_add_orphan = false; | ||
1101 | 1200 | ||
1102 | /* At some point it might be nice to break this function up a | 1201 | /* At some point it might be nice to break this function up a |
1103 | * bit. */ | 1202 | * bit. */ |
@@ -1134,6 +1233,21 @@ static int ocfs2_rename(struct inode *old_dir, | |||
1134 | goto bail; | 1233 | goto bail; |
1135 | } | 1234 | } |
1136 | rename_lock = 1; | 1235 | rename_lock = 1; |
1236 | |||
1237 | /* here we cannot guarantee the inodes haven't just been | ||
1238 | * changed, so check if they are nested again */ | ||
1239 | status = ocfs2_check_if_ancestor(osb, new_dir->i_ino, | ||
1240 | old_inode->i_ino); | ||
1241 | if (status < 0) { | ||
1242 | mlog_errno(status); | ||
1243 | goto bail; | ||
1244 | } else if (status == 1) { | ||
1245 | status = -EPERM; | ||
1246 | trace_ocfs2_rename_not_permitted( | ||
1247 | (unsigned long long)old_inode->i_ino, | ||
1248 | (unsigned long long)new_dir->i_ino); | ||
1249 | goto bail; | ||
1250 | } | ||
1137 | } | 1251 | } |
1138 | 1252 | ||
1139 | /* if old and new are the same, this'll just do one lock. */ | 1253 | /* if old and new are the same, this'll just do one lock. */ |
@@ -1304,6 +1418,7 @@ static int ocfs2_rename(struct inode *old_dir, | |||
1304 | mlog_errno(status); | 1418 | mlog_errno(status); |
1305 | goto bail; | 1419 | goto bail; |
1306 | } | 1420 | } |
1421 | should_add_orphan = true; | ||
1307 | } | 1422 | } |
1308 | } else { | 1423 | } else { |
1309 | BUG_ON(new_dentry->d_parent->d_inode != new_dir); | 1424 | BUG_ON(new_dentry->d_parent->d_inode != new_dir); |
@@ -1348,17 +1463,6 @@ static int ocfs2_rename(struct inode *old_dir, | |||
1348 | goto bail; | 1463 | goto bail; |
1349 | } | 1464 | } |
1350 | 1465 | ||
1351 | if (S_ISDIR(new_inode->i_mode) || | ||
1352 | (ocfs2_read_links_count(newfe) == 1)) { | ||
1353 | status = ocfs2_orphan_add(osb, handle, new_inode, | ||
1354 | newfe_bh, orphan_name, | ||
1355 | &orphan_insert, orphan_dir); | ||
1356 | if (status < 0) { | ||
1357 | mlog_errno(status); | ||
1358 | goto bail; | ||
1359 | } | ||
1360 | } | ||
1361 | |||
1362 | /* change the dirent to point to the correct inode */ | 1466 | /* change the dirent to point to the correct inode */ |
1363 | status = ocfs2_update_entry(new_dir, handle, &target_lookup_res, | 1467 | status = ocfs2_update_entry(new_dir, handle, &target_lookup_res, |
1364 | old_inode); | 1468 | old_inode); |
@@ -1373,6 +1477,15 @@ static int ocfs2_rename(struct inode *old_dir, | |||
1373 | else | 1477 | else |
1374 | ocfs2_add_links_count(newfe, -1); | 1478 | ocfs2_add_links_count(newfe, -1); |
1375 | ocfs2_journal_dirty(handle, newfe_bh); | 1479 | ocfs2_journal_dirty(handle, newfe_bh); |
1480 | if (should_add_orphan) { | ||
1481 | status = ocfs2_orphan_add(osb, handle, new_inode, | ||
1482 | newfe_bh, orphan_name, | ||
1483 | &orphan_insert, orphan_dir); | ||
1484 | if (status < 0) { | ||
1485 | mlog_errno(status); | ||
1486 | goto bail; | ||
1487 | } | ||
1488 | } | ||
1376 | } else { | 1489 | } else { |
1377 | /* if the name was not found in new_dir, add it now */ | 1490 | /* if the name was not found in new_dir, add it now */ |
1378 | status = ocfs2_add_entry(handle, new_dentry, old_inode, | 1491 | status = ocfs2_add_entry(handle, new_dentry, old_inode, |
@@ -1642,6 +1755,7 @@ static int ocfs2_symlink(struct inode *dir, | |||
1642 | struct ocfs2_dir_lookup_result lookup = { NULL, }; | 1755 | struct ocfs2_dir_lookup_result lookup = { NULL, }; |
1643 | sigset_t oldset; | 1756 | sigset_t oldset; |
1644 | int did_block_signals = 0; | 1757 | int did_block_signals = 0; |
1758 | struct ocfs2_dentry_lock *dl = NULL; | ||
1645 | 1759 | ||
1646 | trace_ocfs2_symlink_begin(dir, dentry, symname, | 1760 | trace_ocfs2_symlink_begin(dir, dentry, symname, |
1647 | dentry->d_name.len, dentry->d_name.name); | 1761 | dentry->d_name.len, dentry->d_name.name); |
@@ -1830,6 +1944,8 @@ static int ocfs2_symlink(struct inode *dir, | |||
1830 | goto bail; | 1944 | goto bail; |
1831 | } | 1945 | } |
1832 | 1946 | ||
1947 | dl = dentry->d_fsdata; | ||
1948 | |||
1833 | status = ocfs2_add_entry(handle, dentry, inode, | 1949 | status = ocfs2_add_entry(handle, dentry, inode, |
1834 | le64_to_cpu(fe->i_blkno), parent_fe_bh, | 1950 | le64_to_cpu(fe->i_blkno), parent_fe_bh, |
1835 | &lookup); | 1951 | &lookup); |
@@ -1864,6 +1980,9 @@ bail: | |||
1864 | if (xattr_ac) | 1980 | if (xattr_ac) |
1865 | ocfs2_free_alloc_context(xattr_ac); | 1981 | ocfs2_free_alloc_context(xattr_ac); |
1866 | if ((status < 0) && inode) { | 1982 | if ((status < 0) && inode) { |
1983 | if (dl) | ||
1984 | ocfs2_cleanup_add_entry_failure(osb, dentry, inode); | ||
1985 | |||
1867 | OCFS2_I(inode)->ip_flags |= OCFS2_INODE_SKIP_ORPHAN_DIR; | 1986 | OCFS2_I(inode)->ip_flags |= OCFS2_INODE_SKIP_ORPHAN_DIR; |
1868 | clear_nlink(inode); | 1987 | clear_nlink(inode); |
1869 | iput(inode); | 1988 | iput(inode); |