Skip to content

Commit a55712b

Browse files
author
Darrick J. Wong
committed
xfs: create libxfs helper to exchange two directory entries
Create a new libxfs function to exchange two directory entries. The upcoming metadata directory feature will need this to replace a metadata inode directory entry. Signed-off-by: Darrick J. Wong <[email protected]> Reviewed-by: Christoph Hellwig <[email protected]>
1 parent 90636e4 commit a55712b

File tree

3 files changed

+142
-98
lines changed

3 files changed

+142
-98
lines changed

fs/xfs/libxfs/xfs_dir2.c

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -955,3 +955,128 @@ xfs_dir_remove_child(
955955

956956
return 0;
957957
}
958+
959+
/*
960+
* Exchange the entry (@name1, @ip1) in directory @dp1 with the entry (@name2,
961+
* @ip2) in directory @dp2, and update '..' @ip1 and @ip2's entries as needed.
962+
* @ip1 and @ip2 need not be of the same type.
963+
*
964+
* All inodes must have the ILOCK held, and both entries must already exist.
965+
*/
966+
int
967+
xfs_dir_exchange_children(
968+
struct xfs_trans *tp,
969+
struct xfs_dir_update *du1,
970+
struct xfs_dir_update *du2,
971+
unsigned int spaceres)
972+
{
973+
struct xfs_inode *dp1 = du1->dp;
974+
const struct xfs_name *name1 = du1->name;
975+
struct xfs_inode *ip1 = du1->ip;
976+
struct xfs_inode *dp2 = du2->dp;
977+
const struct xfs_name *name2 = du2->name;
978+
struct xfs_inode *ip2 = du2->ip;
979+
int ip1_flags = 0;
980+
int ip2_flags = 0;
981+
int dp2_flags = 0;
982+
int error;
983+
984+
/* Swap inode number for dirent in first parent */
985+
error = xfs_dir_replace(tp, dp1, name1, ip2->i_ino, spaceres);
986+
if (error)
987+
return error;
988+
989+
/* Swap inode number for dirent in second parent */
990+
error = xfs_dir_replace(tp, dp2, name2, ip1->i_ino, spaceres);
991+
if (error)
992+
return error;
993+
994+
/*
995+
* If we're renaming one or more directories across different parents,
996+
* update the respective ".." entries (and link counts) to match the new
997+
* parents.
998+
*/
999+
if (dp1 != dp2) {
1000+
dp2_flags = XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG;
1001+
1002+
if (S_ISDIR(VFS_I(ip2)->i_mode)) {
1003+
error = xfs_dir_replace(tp, ip2, &xfs_name_dotdot,
1004+
dp1->i_ino, spaceres);
1005+
if (error)
1006+
return error;
1007+
1008+
/* transfer ip2 ".." reference to dp1 */
1009+
if (!S_ISDIR(VFS_I(ip1)->i_mode)) {
1010+
error = xfs_droplink(tp, dp2);
1011+
if (error)
1012+
return error;
1013+
xfs_bumplink(tp, dp1);
1014+
}
1015+
1016+
/*
1017+
* Although ip1 isn't changed here, userspace needs
1018+
* to be warned about the change, so that applications
1019+
* relying on it (like backup ones), will properly
1020+
* notify the change
1021+
*/
1022+
ip1_flags |= XFS_ICHGTIME_CHG;
1023+
ip2_flags |= XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG;
1024+
}
1025+
1026+
if (S_ISDIR(VFS_I(ip1)->i_mode)) {
1027+
error = xfs_dir_replace(tp, ip1, &xfs_name_dotdot,
1028+
dp2->i_ino, spaceres);
1029+
if (error)
1030+
return error;
1031+
1032+
/* transfer ip1 ".." reference to dp2 */
1033+
if (!S_ISDIR(VFS_I(ip2)->i_mode)) {
1034+
error = xfs_droplink(tp, dp1);
1035+
if (error)
1036+
return error;
1037+
xfs_bumplink(tp, dp2);
1038+
}
1039+
1040+
/*
1041+
* Although ip2 isn't changed here, userspace needs
1042+
* to be warned about the change, so that applications
1043+
* relying on it (like backup ones), will properly
1044+
* notify the change
1045+
*/
1046+
ip1_flags |= XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG;
1047+
ip2_flags |= XFS_ICHGTIME_CHG;
1048+
}
1049+
}
1050+
1051+
if (ip1_flags) {
1052+
xfs_trans_ichgtime(tp, ip1, ip1_flags);
1053+
xfs_trans_log_inode(tp, ip1, XFS_ILOG_CORE);
1054+
}
1055+
if (ip2_flags) {
1056+
xfs_trans_ichgtime(tp, ip2, ip2_flags);
1057+
xfs_trans_log_inode(tp, ip2, XFS_ILOG_CORE);
1058+
}
1059+
if (dp2_flags) {
1060+
xfs_trans_ichgtime(tp, dp2, dp2_flags);
1061+
xfs_trans_log_inode(tp, dp2, XFS_ILOG_CORE);
1062+
}
1063+
xfs_trans_ichgtime(tp, dp1, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
1064+
xfs_trans_log_inode(tp, dp1, XFS_ILOG_CORE);
1065+
1066+
/* Schedule parent pointer replacements */
1067+
if (du1->ppargs) {
1068+
error = xfs_parent_replacename(tp, du1->ppargs, dp1, name1,
1069+
dp2, name2, ip1);
1070+
if (error)
1071+
return error;
1072+
}
1073+
1074+
if (du2->ppargs) {
1075+
error = xfs_parent_replacename(tp, du2->ppargs, dp2, name2,
1076+
dp1, name1, ip2);
1077+
if (error)
1078+
return error;
1079+
}
1080+
1081+
return 0;
1082+
}

fs/xfs/libxfs/xfs_dir2.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,4 +325,7 @@ int xfs_dir_add_child(struct xfs_trans *tp, unsigned int resblks,
325325
int xfs_dir_remove_child(struct xfs_trans *tp, unsigned int resblks,
326326
struct xfs_dir_update *du);
327327

328+
int xfs_dir_exchange_children(struct xfs_trans *tp, struct xfs_dir_update *du1,
329+
struct xfs_dir_update *du2, unsigned int spaceres);
330+
328331
#endif /* __XFS_DIR2_H__ */

fs/xfs/xfs_inode.c

Lines changed: 14 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -2238,108 +2238,24 @@ xfs_cross_rename(
22382238
struct xfs_parent_args *ip2_ppargs,
22392239
int spaceres)
22402240
{
2241-
int error = 0;
2242-
int ip1_flags = 0;
2243-
int ip2_flags = 0;
2244-
int dp2_flags = 0;
2245-
2246-
/* Swap inode number for dirent in first parent */
2247-
error = xfs_dir_replace(tp, dp1, name1, ip2->i_ino, spaceres);
2248-
if (error)
2249-
goto out_trans_abort;
2241+
struct xfs_dir_update du1 = {
2242+
.dp = dp1,
2243+
.name = name1,
2244+
.ip = ip1,
2245+
.ppargs = ip1_ppargs,
2246+
};
2247+
struct xfs_dir_update du2 = {
2248+
.dp = dp2,
2249+
.name = name2,
2250+
.ip = ip2,
2251+
.ppargs = ip2_ppargs,
2252+
};
2253+
int error;
22502254

2251-
/* Swap inode number for dirent in second parent */
2252-
error = xfs_dir_replace(tp, dp2, name2, ip1->i_ino, spaceres);
2255+
error = xfs_dir_exchange_children(tp, &du1, &du2, spaceres);
22532256
if (error)
22542257
goto out_trans_abort;
22552258

2256-
/*
2257-
* If we're renaming one or more directories across different parents,
2258-
* update the respective ".." entries (and link counts) to match the new
2259-
* parents.
2260-
*/
2261-
if (dp1 != dp2) {
2262-
dp2_flags = XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG;
2263-
2264-
if (S_ISDIR(VFS_I(ip2)->i_mode)) {
2265-
error = xfs_dir_replace(tp, ip2, &xfs_name_dotdot,
2266-
dp1->i_ino, spaceres);
2267-
if (error)
2268-
goto out_trans_abort;
2269-
2270-
/* transfer ip2 ".." reference to dp1 */
2271-
if (!S_ISDIR(VFS_I(ip1)->i_mode)) {
2272-
error = xfs_droplink(tp, dp2);
2273-
if (error)
2274-
goto out_trans_abort;
2275-
xfs_bumplink(tp, dp1);
2276-
}
2277-
2278-
/*
2279-
* Although ip1 isn't changed here, userspace needs
2280-
* to be warned about the change, so that applications
2281-
* relying on it (like backup ones), will properly
2282-
* notify the change
2283-
*/
2284-
ip1_flags |= XFS_ICHGTIME_CHG;
2285-
ip2_flags |= XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG;
2286-
}
2287-
2288-
if (S_ISDIR(VFS_I(ip1)->i_mode)) {
2289-
error = xfs_dir_replace(tp, ip1, &xfs_name_dotdot,
2290-
dp2->i_ino, spaceres);
2291-
if (error)
2292-
goto out_trans_abort;
2293-
2294-
/* transfer ip1 ".." reference to dp2 */
2295-
if (!S_ISDIR(VFS_I(ip2)->i_mode)) {
2296-
error = xfs_droplink(tp, dp1);
2297-
if (error)
2298-
goto out_trans_abort;
2299-
xfs_bumplink(tp, dp2);
2300-
}
2301-
2302-
/*
2303-
* Although ip2 isn't changed here, userspace needs
2304-
* to be warned about the change, so that applications
2305-
* relying on it (like backup ones), will properly
2306-
* notify the change
2307-
*/
2308-
ip1_flags |= XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG;
2309-
ip2_flags |= XFS_ICHGTIME_CHG;
2310-
}
2311-
}
2312-
2313-
/* Schedule parent pointer replacements */
2314-
if (ip1_ppargs) {
2315-
error = xfs_parent_replacename(tp, ip1_ppargs, dp1, name1, dp2,
2316-
name2, ip1);
2317-
if (error)
2318-
goto out_trans_abort;
2319-
}
2320-
2321-
if (ip2_ppargs) {
2322-
error = xfs_parent_replacename(tp, ip2_ppargs, dp2, name2, dp1,
2323-
name1, ip2);
2324-
if (error)
2325-
goto out_trans_abort;
2326-
}
2327-
2328-
if (ip1_flags) {
2329-
xfs_trans_ichgtime(tp, ip1, ip1_flags);
2330-
xfs_trans_log_inode(tp, ip1, XFS_ILOG_CORE);
2331-
}
2332-
if (ip2_flags) {
2333-
xfs_trans_ichgtime(tp, ip2, ip2_flags);
2334-
xfs_trans_log_inode(tp, ip2, XFS_ILOG_CORE);
2335-
}
2336-
if (dp2_flags) {
2337-
xfs_trans_ichgtime(tp, dp2, dp2_flags);
2338-
xfs_trans_log_inode(tp, dp2, XFS_ILOG_CORE);
2339-
}
2340-
xfs_trans_ichgtime(tp, dp1, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
2341-
xfs_trans_log_inode(tp, dp1, XFS_ILOG_CORE);
2342-
23432259
/*
23442260
* Inform our hook clients that we've finished an exchange operation as
23452261
* follows: removed the source and target files from their directories;

0 commit comments

Comments
 (0)