Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
d41bb034
Commit
d41bb034
authored
Mar 25, 2015
by
Dave Chinner
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'xfs-rename-whiteout' into for-next
Conflicts: fs/xfs/xfs_inode.c
parents
88e8fda9
7dcf5c3e
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
239 additions
and
171 deletions
+239
-171
fs/xfs/xfs_inode.c
fs/xfs/xfs_inode.c
+238
-170
fs/xfs/xfs_iops.c
fs/xfs/xfs_iops.c
+1
-1
No files found.
fs/xfs/xfs_inode.c
View file @
d41bb034
...
@@ -391,15 +391,14 @@ xfs_lock_inumorder(int lock_mode, int subclass)
...
@@ -391,15 +391,14 @@ xfs_lock_inumorder(int lock_mode, int subclass)
}
}
/*
/*
* The following routine will lock n inodes in exclusive mode.
* The following routine will lock n inodes in exclusive mode.
We assume the
*
We assume the
caller calls us with the inodes in i_ino order.
* caller calls us with the inodes in i_ino order.
*
*
* We need to detect deadlock where an inode that we lock
* We need to detect deadlock where an inode that we lock is in the AIL and we
* is in the AIL and we start waiting for another inode that is locked
* start waiting for another inode that is locked by a thread in a long running
* by a thread in a long running transaction (such as truncate). This can
* transaction (such as truncate). This can result in deadlock since the long
* result in deadlock since the long running trans might need to wait
* running trans might need to wait for the inode we just locked in order to
* for the inode we just locked in order to push the tail and free space
* push the tail and free space in the log.
* in the log.
*/
*/
void
void
xfs_lock_inodes
(
xfs_lock_inodes
(
...
@@ -410,30 +409,27 @@ xfs_lock_inodes(
...
@@ -410,30 +409,27 @@ xfs_lock_inodes(
int
attempts
=
0
,
i
,
j
,
try_lock
;
int
attempts
=
0
,
i
,
j
,
try_lock
;
xfs_log_item_t
*
lp
;
xfs_log_item_t
*
lp
;
ASSERT
(
ips
&&
(
inodes
>=
2
));
/* we need at least two */
/* currently supports between 2 and 5 inodes */
ASSERT
(
ips
&&
inodes
>=
2
&&
inodes
<=
5
);
try_lock
=
0
;
try_lock
=
0
;
i
=
0
;
i
=
0
;
again:
again:
for
(;
i
<
inodes
;
i
++
)
{
for
(;
i
<
inodes
;
i
++
)
{
ASSERT
(
ips
[
i
]);
ASSERT
(
ips
[
i
]);
if
(
i
&&
(
ips
[
i
]
==
ips
[
i
-
1
]))
/* Already locked */
if
(
i
&&
(
ips
[
i
]
==
ips
[
i
-
1
]))
/* Already locked */
continue
;
continue
;
/*
/*
* If try_lock is not set yet, make sure all locked inodes
* If try_lock is not set yet, make sure all locked inodes are
* are not in the AIL.
* not in the AIL. If any are, set try_lock to be used later.
* If any are, set try_lock to be used later.
*/
*/
if
(
!
try_lock
)
{
if
(
!
try_lock
)
{
for
(
j
=
(
i
-
1
);
j
>=
0
&&
!
try_lock
;
j
--
)
{
for
(
j
=
(
i
-
1
);
j
>=
0
&&
!
try_lock
;
j
--
)
{
lp
=
(
xfs_log_item_t
*
)
ips
[
j
]
->
i_itemp
;
lp
=
(
xfs_log_item_t
*
)
ips
[
j
]
->
i_itemp
;
if
(
lp
&&
(
lp
->
li_flags
&
XFS_LI_IN_AIL
))
{
if
(
lp
&&
(
lp
->
li_flags
&
XFS_LI_IN_AIL
))
try_lock
++
;
try_lock
++
;
}
}
}
}
}
...
@@ -443,51 +439,42 @@ xfs_lock_inodes(
...
@@ -443,51 +439,42 @@ xfs_lock_inodes(
* we can't get any, we must release all we have
* we can't get any, we must release all we have
* and try again.
* and try again.
*/
*/
if
(
!
try_lock
)
{
xfs_ilock
(
ips
[
i
],
xfs_lock_inumorder
(
lock_mode
,
i
));
continue
;
}
/* try_lock means we have an inode locked that is in the AIL. */
ASSERT
(
i
!=
0
);
if
(
xfs_ilock_nowait
(
ips
[
i
],
xfs_lock_inumorder
(
lock_mode
,
i
)))
continue
;
if
(
try_lock
)
{
/*
/* try_lock must be 0 if i is 0. */
* Unlock all previous guys and try again. xfs_iunlock will try
* to push the tail if the inode is in the AIL.
*/
attempts
++
;
for
(
j
=
i
-
1
;
j
>=
0
;
j
--
)
{
/*
/*
* try_lock means we have an inode locked
* Check to see if we've already unlocked this one. Not
* that is in the AIL.
* the first one going back, and the inode ptr is the
* same.
*/
*/
ASSERT
(
i
!=
0
);
if
(
j
!=
(
i
-
1
)
&&
ips
[
j
]
==
ips
[
j
+
1
])
if
(
!
xfs_ilock_nowait
(
ips
[
i
],
xfs_lock_inumorder
(
lock_mode
,
i
)))
{
continue
;
attempts
++
;
/*
* Unlock all previous guys and try again.
* xfs_iunlock will try to push the tail
* if the inode is in the AIL.
*/
for
(
j
=
i
-
1
;
j
>=
0
;
j
--
)
{
/*
* Check to see if we've already
* unlocked this one.
* Not the first one going back,
* and the inode ptr is the same.
*/
if
((
j
!=
(
i
-
1
))
&&
ips
[
j
]
==
ips
[
j
+
1
])
continue
;
xfs_iunlock
(
ips
[
j
],
lock_mode
);
}
if
((
attempts
%
5
)
==
0
)
{
xfs_iunlock
(
ips
[
j
],
lock_mode
);
delay
(
1
);
/* Don't just spin the CPU */
}
if
((
attempts
%
5
)
==
0
)
{
delay
(
1
);
/* Don't just spin the CPU */
#ifdef DEBUG
#ifdef DEBUG
xfs_lock_delays
++
;
xfs_lock_delays
++
;
#endif
#endif
}
i
=
0
;
try_lock
=
0
;
goto
again
;
}
}
else
{
xfs_ilock
(
ips
[
i
],
xfs_lock_inumorder
(
lock_mode
,
i
));
}
}
i
=
0
;
try_lock
=
0
;
goto
again
;
}
}
#ifdef DEBUG
#ifdef DEBUG
...
@@ -2681,19 +2668,22 @@ xfs_remove(
...
@@ -2681,19 +2668,22 @@ xfs_remove(
/*
/*
* Enter all inodes for a rename transaction into a sorted array.
* Enter all inodes for a rename transaction into a sorted array.
*/
*/
#define __XFS_SORT_INODES 5
STATIC
void
STATIC
void
xfs_sort_for_rename
(
xfs_sort_for_rename
(
xfs_inode_t
*
dp1
,
/* in: old (source) directory inode */
struct
xfs_inode
*
dp1
,
/* in: old (source) directory inode */
xfs_inode_t
*
dp2
,
/* in: new (target) directory inode */
struct
xfs_inode
*
dp2
,
/* in: new (target) directory inode */
xfs_inode_t
*
ip1
,
/* in: inode of old entry */
struct
xfs_inode
*
ip1
,
/* in: inode of old entry */
xfs_inode_t
*
ip2
,
/* in: inode of new entry, if it
struct
xfs_inode
*
ip2
,
/* in: inode of new entry */
already exists, NULL otherwise.
*/
struct
xfs_inode
*
wip
,
/* in: whiteout inode
*/
xfs_inode_t
**
i_tab
,
/* out: array of inode returned, sorted
*/
struct
xfs_inode
**
i_tab
,
/* out: sorted array of inodes
*/
int
*
num_inodes
)
/* out: number of
inodes in array */
int
*
num_inodes
)
/* in/out:
inodes in array */
{
{
xfs_inode_t
*
temp
;
int
i
,
j
;
int
i
,
j
;
ASSERT
(
*
num_inodes
==
__XFS_SORT_INODES
);
memset
(
i_tab
,
0
,
*
num_inodes
*
sizeof
(
struct
xfs_inode
*
));
/*
/*
* i_tab contains a list of pointers to inodes. We initialize
* i_tab contains a list of pointers to inodes. We initialize
* the table here & we'll sort it. We will then use it to
* the table here & we'll sort it. We will then use it to
...
@@ -2701,25 +2691,24 @@ xfs_sort_for_rename(
...
@@ -2701,25 +2691,24 @@ xfs_sort_for_rename(
*
*
* Note that the table may contain duplicates. e.g., dp1 == dp2.
* Note that the table may contain duplicates. e.g., dp1 == dp2.
*/
*/
i_tab
[
0
]
=
dp1
;
i
=
0
;
i_tab
[
1
]
=
dp2
;
i_tab
[
i
++
]
=
dp1
;
i_tab
[
2
]
=
ip1
;
i_tab
[
i
++
]
=
dp2
;
if
(
ip2
)
{
i_tab
[
i
++
]
=
ip1
;
*
num_inodes
=
4
;
if
(
ip2
)
i_tab
[
3
]
=
ip2
;
i_tab
[
i
++
]
=
ip2
;
}
else
{
if
(
wip
)
*
num_inodes
=
3
;
i_tab
[
i
++
]
=
wip
;
i_tab
[
3
]
=
NULL
;
*
num_inodes
=
i
;
}
/*
/*
* Sort the elements via bubble sort. (Remember, there are at
* Sort the elements via bubble sort. (Remember, there are at
* most
4
elements to sort, so this is adequate.)
* most
5
elements to sort, so this is adequate.)
*/
*/
for
(
i
=
0
;
i
<
*
num_inodes
;
i
++
)
{
for
(
i
=
0
;
i
<
*
num_inodes
;
i
++
)
{
for
(
j
=
1
;
j
<
*
num_inodes
;
j
++
)
{
for
(
j
=
1
;
j
<
*
num_inodes
;
j
++
)
{
if
(
i_tab
[
j
]
->
i_ino
<
i_tab
[
j
-
1
]
->
i_ino
)
{
if
(
i_tab
[
j
]
->
i_ino
<
i_tab
[
j
-
1
]
->
i_ino
)
{
temp
=
i_tab
[
j
];
struct
xfs_inode
*
temp
=
i_tab
[
j
];
i_tab
[
j
]
=
i_tab
[
j
-
1
];
i_tab
[
j
]
=
i_tab
[
j
-
1
];
i_tab
[
j
-
1
]
=
temp
;
i_tab
[
j
-
1
]
=
temp
;
}
}
...
@@ -2727,6 +2716,31 @@ xfs_sort_for_rename(
...
@@ -2727,6 +2716,31 @@ xfs_sort_for_rename(
}
}
}
}
static
int
xfs_finish_rename
(
struct
xfs_trans
*
tp
,
struct
xfs_bmap_free
*
free_list
)
{
int
committed
=
0
;
int
error
;
/*
* If this is a synchronous mount, make sure that the rename transaction
* goes to disk before returning to the user.
*/
if
(
tp
->
t_mountp
->
m_flags
&
(
XFS_MOUNT_WSYNC
|
XFS_MOUNT_DIRSYNC
))
xfs_trans_set_sync
(
tp
);
error
=
xfs_bmap_finish
(
&
tp
,
free_list
,
&
committed
);
if
(
error
)
{
xfs_bmap_cancel
(
free_list
);
xfs_trans_cancel
(
tp
,
XFS_TRANS_RELEASE_LOG_RES
|
XFS_TRANS_ABORT
);
return
error
;
}
return
xfs_trans_commit
(
tp
,
XFS_TRANS_RELEASE_LOG_RES
);
}
/*
/*
* xfs_cross_rename()
* xfs_cross_rename()
*
*
...
@@ -2755,14 +2769,14 @@ xfs_cross_rename(
...
@@ -2755,14 +2769,14 @@ xfs_cross_rename(
ip2
->
i_ino
,
ip2
->
i_ino
,
first_block
,
free_list
,
spaceres
);
first_block
,
free_list
,
spaceres
);
if
(
error
)
if
(
error
)
goto
out
;
goto
out
_trans_abort
;
/* Swap inode number for dirent in second parent */
/* Swap inode number for dirent in second parent */
error
=
xfs_dir_replace
(
tp
,
dp2
,
name2
,
error
=
xfs_dir_replace
(
tp
,
dp2
,
name2
,
ip1
->
i_ino
,
ip1
->
i_ino
,
first_block
,
free_list
,
spaceres
);
first_block
,
free_list
,
spaceres
);
if
(
error
)
if
(
error
)
goto
out
;
goto
out
_trans_abort
;
/*
/*
* If we're renaming one or more directories across different parents,
* If we're renaming one or more directories across different parents,
...
@@ -2777,16 +2791,16 @@ xfs_cross_rename(
...
@@ -2777,16 +2791,16 @@ xfs_cross_rename(
dp1
->
i_ino
,
first_block
,
dp1
->
i_ino
,
first_block
,
free_list
,
spaceres
);
free_list
,
spaceres
);
if
(
error
)
if
(
error
)
goto
out
;
goto
out
_trans_abort
;
/* transfer ip2 ".." reference to dp1 */
/* transfer ip2 ".." reference to dp1 */
if
(
!
S_ISDIR
(
ip1
->
i_d
.
di_mode
))
{
if
(
!
S_ISDIR
(
ip1
->
i_d
.
di_mode
))
{
error
=
xfs_droplink
(
tp
,
dp2
);
error
=
xfs_droplink
(
tp
,
dp2
);
if
(
error
)
if
(
error
)
goto
out
;
goto
out
_trans_abort
;
error
=
xfs_bumplink
(
tp
,
dp1
);
error
=
xfs_bumplink
(
tp
,
dp1
);
if
(
error
)
if
(
error
)
goto
out
;
goto
out
_trans_abort
;
}
}
/*
/*
...
@@ -2804,16 +2818,16 @@ xfs_cross_rename(
...
@@ -2804,16 +2818,16 @@ xfs_cross_rename(
dp2
->
i_ino
,
first_block
,
dp2
->
i_ino
,
first_block
,
free_list
,
spaceres
);
free_list
,
spaceres
);
if
(
error
)
if
(
error
)
goto
out
;
goto
out
_trans_abort
;
/* transfer ip1 ".." reference to dp2 */
/* transfer ip1 ".." reference to dp2 */
if
(
!
S_ISDIR
(
ip2
->
i_d
.
di_mode
))
{
if
(
!
S_ISDIR
(
ip2
->
i_d
.
di_mode
))
{
error
=
xfs_droplink
(
tp
,
dp1
);
error
=
xfs_droplink
(
tp
,
dp1
);
if
(
error
)
if
(
error
)
goto
out
;
goto
out
_trans_abort
;
error
=
xfs_bumplink
(
tp
,
dp2
);
error
=
xfs_bumplink
(
tp
,
dp2
);
if
(
error
)
if
(
error
)
goto
out
;
goto
out
_trans_abort
;
}
}
/*
/*
...
@@ -2841,66 +2855,108 @@ xfs_cross_rename(
...
@@ -2841,66 +2855,108 @@ xfs_cross_rename(
}
}
xfs_trans_ichgtime
(
tp
,
dp1
,
XFS_ICHGTIME_MOD
|
XFS_ICHGTIME_CHG
);
xfs_trans_ichgtime
(
tp
,
dp1
,
XFS_ICHGTIME_MOD
|
XFS_ICHGTIME_CHG
);
xfs_trans_log_inode
(
tp
,
dp1
,
XFS_ILOG_CORE
);
xfs_trans_log_inode
(
tp
,
dp1
,
XFS_ILOG_CORE
);
out:
return
xfs_finish_rename
(
tp
,
free_list
);
out_trans_abort:
xfs_bmap_cancel
(
free_list
);
xfs_trans_cancel
(
tp
,
XFS_TRANS_RELEASE_LOG_RES
|
XFS_TRANS_ABORT
);
return
error
;
return
error
;
}
}
/*
* xfs_rename_alloc_whiteout()
*
* Return a referenced, unlinked, unlocked inode that that can be used as a
* whiteout in a rename transaction. We use a tmpfile inode here so that if we
* crash between allocating the inode and linking it into the rename transaction
* recovery will free the inode and we won't leak it.
*/
static
int
xfs_rename_alloc_whiteout
(
struct
xfs_inode
*
dp
,
struct
xfs_inode
**
wip
)
{
struct
xfs_inode
*
tmpfile
;
int
error
;
error
=
xfs_create_tmpfile
(
dp
,
NULL
,
S_IFCHR
|
WHITEOUT_MODE
,
&
tmpfile
);
if
(
error
)
return
error
;
/* Satisfy xfs_bumplink that this is a real tmpfile */
xfs_finish_inode_setup
(
tmpfile
);
VFS_I
(
tmpfile
)
->
i_state
|=
I_LINKABLE
;
*
wip
=
tmpfile
;
return
0
;
}
/*
/*
* xfs_rename
* xfs_rename
*/
*/
int
int
xfs_rename
(
xfs_rename
(
xfs_inode_t
*
src_dp
,
struct
xfs_inode
*
src_dp
,
struct
xfs_name
*
src_name
,
struct
xfs_name
*
src_name
,
xfs_inode_t
*
src_ip
,
struct
xfs_inode
*
src_ip
,
xfs_inode_t
*
target_dp
,
struct
xfs_inode
*
target_dp
,
struct
xfs_name
*
target_name
,
struct
xfs_name
*
target_name
,
xfs_inode_t
*
target_ip
,
struct
xfs_inode
*
target_ip
,
unsigned
int
flags
)
unsigned
int
flags
)
{
{
xfs_trans_t
*
tp
=
NULL
;
struct
xfs_mount
*
mp
=
src_dp
->
i_mount
;
xfs_mount_t
*
mp
=
src_dp
->
i_mount
;
struct
xfs_trans
*
tp
;
int
new_parent
;
/* moving to a new dir */
struct
xfs_bmap_free
free_list
;
int
src_is_directory
;
/* src_name is a directory */
xfs_fsblock_t
first_block
;
int
error
;
struct
xfs_inode
*
wip
=
NULL
;
/* whiteout inode */
xfs_bmap_free_t
free_list
;
struct
xfs_inode
*
inodes
[
__XFS_SORT_INODES
]
;
xfs_fsblock_t
first_block
;
int
num_inodes
=
__XFS_SORT_INODES
;
int
cancel_flags
;
int
new_parent
=
(
src_dp
!=
target_dp
)
;
int
committed
;
int
src_is_directory
=
S_ISDIR
(
src_ip
->
i_d
.
di_mode
)
;
xfs_inode_t
*
inodes
[
4
]
;
int
cancel_flags
=
0
;
int
spaceres
;
int
spaceres
;
int
num_inodes
;
int
error
;
trace_xfs_rename
(
src_dp
,
target_dp
,
src_name
,
target_name
);
trace_xfs_rename
(
src_dp
,
target_dp
,
src_name
,
target_name
);
new_parent
=
(
src_dp
!=
target_dp
);
if
((
flags
&
RENAME_EXCHANGE
)
&&
!
target_ip
)
src_is_directory
=
S_ISDIR
(
src_ip
->
i_d
.
di_mode
);
return
-
EINVAL
;
/*
* If we are doing a whiteout operation, allocate the whiteout inode
* we will be placing at the target and ensure the type is set
* appropriately.
*/
if
(
flags
&
RENAME_WHITEOUT
)
{
ASSERT
(
!
(
flags
&
(
RENAME_NOREPLACE
|
RENAME_EXCHANGE
)));
error
=
xfs_rename_alloc_whiteout
(
target_dp
,
&
wip
);
if
(
error
)
return
error
;
/* setup target dirent info as whiteout */
src_name
->
type
=
XFS_DIR3_FT_CHRDEV
;
}
xfs_sort_for_rename
(
src_dp
,
target_dp
,
src_ip
,
target_ip
,
xfs_sort_for_rename
(
src_dp
,
target_dp
,
src_ip
,
target_ip
,
wip
,
inodes
,
&
num_inodes
);
inodes
,
&
num_inodes
);
xfs_bmap_init
(
&
free_list
,
&
first_block
);
tp
=
xfs_trans_alloc
(
mp
,
XFS_TRANS_RENAME
);
tp
=
xfs_trans_alloc
(
mp
,
XFS_TRANS_RENAME
);
cancel_flags
=
XFS_TRANS_RELEASE_LOG_RES
;
spaceres
=
XFS_RENAME_SPACE_RES
(
mp
,
target_name
->
len
);
spaceres
=
XFS_RENAME_SPACE_RES
(
mp
,
target_name
->
len
);
error
=
xfs_trans_reserve
(
tp
,
&
M_RES
(
mp
)
->
tr_rename
,
spaceres
,
0
);
error
=
xfs_trans_reserve
(
tp
,
&
M_RES
(
mp
)
->
tr_rename
,
spaceres
,
0
);
if
(
error
==
-
ENOSPC
)
{
if
(
error
==
-
ENOSPC
)
{
spaceres
=
0
;
spaceres
=
0
;
error
=
xfs_trans_reserve
(
tp
,
&
M_RES
(
mp
)
->
tr_rename
,
0
,
0
);
error
=
xfs_trans_reserve
(
tp
,
&
M_RES
(
mp
)
->
tr_rename
,
0
,
0
);
}
}
if
(
error
)
{
if
(
error
)
xfs_trans_cancel
(
tp
,
0
);
goto
out_trans_cancel
;
goto
std_return
;
cancel_flags
=
XFS_TRANS_RELEASE_LOG_RES
;
}
/*
/*
* Attach the dquots to the inodes
* Attach the dquots to the inodes
*/
*/
error
=
xfs_qm_vop_rename_dqattach
(
inodes
);
error
=
xfs_qm_vop_rename_dqattach
(
inodes
);
if
(
error
)
{
if
(
error
)
xfs_trans_cancel
(
tp
,
cancel_flags
);
goto
out_trans_cancel
;
goto
std_return
;
}
/*
/*
* Lock all the participating inodes. Depending upon whether
* Lock all the participating inodes. Depending upon whether
...
@@ -2921,6 +2977,8 @@ xfs_rename(
...
@@ -2921,6 +2977,8 @@ xfs_rename(
xfs_trans_ijoin
(
tp
,
src_ip
,
XFS_ILOCK_EXCL
);
xfs_trans_ijoin
(
tp
,
src_ip
,
XFS_ILOCK_EXCL
);
if
(
target_ip
)
if
(
target_ip
)
xfs_trans_ijoin
(
tp
,
target_ip
,
XFS_ILOCK_EXCL
);
xfs_trans_ijoin
(
tp
,
target_ip
,
XFS_ILOCK_EXCL
);
if
(
wip
)
xfs_trans_ijoin
(
tp
,
wip
,
XFS_ILOCK_EXCL
);
/*
/*
* If we are using project inheritance, we only allow renames
* If we are using project inheritance, we only allow renames
...
@@ -2930,24 +2988,16 @@ xfs_rename(
...
@@ -2930,24 +2988,16 @@ xfs_rename(
if
(
unlikely
((
target_dp
->
i_d
.
di_flags
&
XFS_DIFLAG_PROJINHERIT
)
&&
if
(
unlikely
((
target_dp
->
i_d
.
di_flags
&
XFS_DIFLAG_PROJINHERIT
)
&&
(
xfs_get_projid
(
target_dp
)
!=
xfs_get_projid
(
src_ip
))))
{
(
xfs_get_projid
(
target_dp
)
!=
xfs_get_projid
(
src_ip
))))
{
error
=
-
EXDEV
;
error
=
-
EXDEV
;
goto
error_return
;
goto
out_trans_cancel
;
}
}
/*
xfs_bmap_init
(
&
free_list
,
&
first_block
);
* Handle RENAME_EXCHANGE flags
*/
/* RENAME_EXCHANGE is unique from here on. */
if
(
flags
&
RENAME_EXCHANGE
)
{
if
(
flags
&
RENAME_EXCHANGE
)
if
(
target_ip
==
NULL
)
{
return
xfs_cross_rename
(
tp
,
src_dp
,
src_name
,
src_ip
,
error
=
-
EINVAL
;
target_dp
,
target_name
,
target_ip
,
goto
error_return
;
&
free_list
,
&
first_block
,
spaceres
);
}
error
=
xfs_cross_rename
(
tp
,
src_dp
,
src_name
,
src_ip
,
target_dp
,
target_name
,
target_ip
,
&
free_list
,
&
first_block
,
spaceres
);
if
(
error
)
goto
abort_return
;
goto
finish_rename
;
}
/*
/*
* Set up the target.
* Set up the target.
...
@@ -2960,7 +3010,7 @@ xfs_rename(
...
@@ -2960,7 +3010,7 @@ xfs_rename(
if
(
!
spaceres
)
{
if
(
!
spaceres
)
{
error
=
xfs_dir_canenter
(
tp
,
target_dp
,
target_name
);
error
=
xfs_dir_canenter
(
tp
,
target_dp
,
target_name
);
if
(
error
)
if
(
error
)
goto
error_return
;
goto
out_trans_cancel
;
}
}
/*
/*
* If target does not exist and the rename crosses
* If target does not exist and the rename crosses
...
@@ -2971,9 +3021,9 @@ xfs_rename(
...
@@ -2971,9 +3021,9 @@ xfs_rename(
src_ip
->
i_ino
,
&
first_block
,
src_ip
->
i_ino
,
&
first_block
,
&
free_list
,
spaceres
);
&
free_list
,
spaceres
);
if
(
error
==
-
ENOSPC
)
if
(
error
==
-
ENOSPC
)
goto
error_return
;
goto
out_bmap_cancel
;
if
(
error
)
if
(
error
)
goto
abort_return
;
goto
out_trans_abort
;
xfs_trans_ichgtime
(
tp
,
target_dp
,
xfs_trans_ichgtime
(
tp
,
target_dp
,
XFS_ICHGTIME_MOD
|
XFS_ICHGTIME_CHG
);
XFS_ICHGTIME_MOD
|
XFS_ICHGTIME_CHG
);
...
@@ -2981,7 +3031,7 @@ xfs_rename(
...
@@ -2981,7 +3031,7 @@ xfs_rename(
if
(
new_parent
&&
src_is_directory
)
{
if
(
new_parent
&&
src_is_directory
)
{
error
=
xfs_bumplink
(
tp
,
target_dp
);
error
=
xfs_bumplink
(
tp
,
target_dp
);
if
(
error
)
if
(
error
)
goto
abort_return
;
goto
out_trans_abort
;
}
}
}
else
{
/* target_ip != NULL */
}
else
{
/* target_ip != NULL */
/*
/*
...
@@ -2996,7 +3046,7 @@ xfs_rename(
...
@@ -2996,7 +3046,7 @@ xfs_rename(
if
(
!
(
xfs_dir_isempty
(
target_ip
))
||
if
(
!
(
xfs_dir_isempty
(
target_ip
))
||
(
target_ip
->
i_d
.
di_nlink
>
2
))
{
(
target_ip
->
i_d
.
di_nlink
>
2
))
{
error
=
-
EEXIST
;
error
=
-
EEXIST
;
goto
error_return
;
goto
out_trans_cancel
;
}
}
}
}
...
@@ -3013,7 +3063,7 @@ xfs_rename(
...
@@ -3013,7 +3063,7 @@ xfs_rename(
src_ip
->
i_ino
,
src_ip
->
i_ino
,
&
first_block
,
&
free_list
,
spaceres
);
&
first_block
,
&
free_list
,
spaceres
);
if
(
error
)
if
(
error
)
goto
abort_return
;
goto
out_trans_abort
;
xfs_trans_ichgtime
(
tp
,
target_dp
,
xfs_trans_ichgtime
(
tp
,
target_dp
,
XFS_ICHGTIME_MOD
|
XFS_ICHGTIME_CHG
);
XFS_ICHGTIME_MOD
|
XFS_ICHGTIME_CHG
);
...
@@ -3024,7 +3074,7 @@ xfs_rename(
...
@@ -3024,7 +3074,7 @@ xfs_rename(
*/
*/
error
=
xfs_droplink
(
tp
,
target_ip
);
error
=
xfs_droplink
(
tp
,
target_ip
);
if
(
error
)
if
(
error
)
goto
abort_return
;
goto
out_trans_abort
;
if
(
src_is_directory
)
{
if
(
src_is_directory
)
{
/*
/*
...
@@ -3032,7 +3082,7 @@ xfs_rename(
...
@@ -3032,7 +3082,7 @@ xfs_rename(
*/
*/
error
=
xfs_droplink
(
tp
,
target_ip
);
error
=
xfs_droplink
(
tp
,
target_ip
);
if
(
error
)
if
(
error
)
goto
abort_return
;
goto
out_trans_abort
;
}
}
}
/* target_ip != NULL */
}
/* target_ip != NULL */
...
@@ -3049,7 +3099,7 @@ xfs_rename(
...
@@ -3049,7 +3099,7 @@ xfs_rename(
&
first_block
,
&
free_list
,
spaceres
);
&
first_block
,
&
free_list
,
spaceres
);
ASSERT
(
error
!=
-
EEXIST
);
ASSERT
(
error
!=
-
EEXIST
);
if
(
error
)
if
(
error
)
goto
abort_return
;
goto
out_trans_abort
;
}
}
/*
/*
...
@@ -3075,49 +3125,67 @@ xfs_rename(
...
@@ -3075,49 +3125,67 @@ xfs_rename(
*/
*/
error
=
xfs_droplink
(
tp
,
src_dp
);
error
=
xfs_droplink
(
tp
,
src_dp
);
if
(
error
)
if
(
error
)
goto
abort_return
;
goto
out_trans_abort
;
}
}
error
=
xfs_dir_removename
(
tp
,
src_dp
,
src_name
,
src_ip
->
i_ino
,
/*
* For whiteouts, we only need to update the source dirent with the
* inode number of the whiteout inode rather than removing it
* altogether.
*/
if
(
wip
)
{
error
=
xfs_dir_replace
(
tp
,
src_dp
,
src_name
,
wip
->
i_ino
,
&
first_block
,
&
free_list
,
spaceres
);
&
first_block
,
&
free_list
,
spaceres
);
}
else
error
=
xfs_dir_removename
(
tp
,
src_dp
,
src_name
,
src_ip
->
i_ino
,
&
first_block
,
&
free_list
,
spaceres
);
if
(
error
)
if
(
error
)
goto
abort_return
;
goto
out_trans_abort
;
xfs_trans_ichgtime
(
tp
,
src_dp
,
XFS_ICHGTIME_MOD
|
XFS_ICHGTIME_CHG
);
xfs_trans_log_inode
(
tp
,
src_dp
,
XFS_ILOG_CORE
);
if
(
new_parent
)
xfs_trans_log_inode
(
tp
,
target_dp
,
XFS_ILOG_CORE
);
finish_rename:
/*
/*
* If this is a synchronous mount, make sure that the
* For whiteouts, we need to bump the link count on the whiteout inode.
* rename transaction goes to disk before returning to
* This means that failures all the way up to this point leave the inode
* the user.
* on the unlinked list and so cleanup is a simple matter of dropping
* the remaining reference to it. If we fail here after bumping the link
* count, we're shutting down the filesystem so we'll never see the
* intermediate state on disk.
*/
*/
if
(
mp
->
m_flags
&
(
XFS_MOUNT_WSYNC
|
XFS_MOUNT_DIRSYNC
))
{
if
(
wip
)
{
xfs_trans_set_sync
(
tp
);
ASSERT
(
wip
->
i_d
.
di_nlink
==
0
);
}
error
=
xfs_bumplink
(
tp
,
wip
);
if
(
error
)
goto
out_trans_abort
;
error
=
xfs_iunlink_remove
(
tp
,
wip
);
if
(
error
)
goto
out_trans_abort
;
xfs_trans_log_inode
(
tp
,
wip
,
XFS_ILOG_CORE
);
error
=
xfs_bmap_finish
(
&
tp
,
&
free_list
,
&
committed
);
/*
if
(
error
)
{
* Now we have a real link, clear the "I'm a tmpfile" state
xfs_bmap_cancel
(
&
free_list
);
* flag from the inode so it doesn't accidentally get misused in
xfs_trans_cancel
(
tp
,
(
XFS_TRANS_RELEASE_LOG_RES
|
* future.
XFS_TRANS_ABORT
));
*/
goto
std_return
;
VFS_I
(
wip
)
->
i_state
&=
~
I_LINKABLE
;
}
}
/*
xfs_trans_ichgtime
(
tp
,
src_dp
,
XFS_ICHGTIME_MOD
|
XFS_ICHGTIME_CHG
);
* trans_commit will unlock src_ip, target_ip & decrement
xfs_trans_log_inode
(
tp
,
src_dp
,
XFS_ILOG_CORE
);
* the vnode references.
if
(
new_parent
)
*/
xfs_trans_log_inode
(
tp
,
target_dp
,
XFS_ILOG_CORE
);
return
xfs_trans_commit
(
tp
,
XFS_TRANS_RELEASE_LOG_RES
);
abort_return:
error
=
xfs_finish_rename
(
tp
,
&
free_list
);
if
(
wip
)
IRELE
(
wip
);
return
error
;
out_trans_abort:
cancel_flags
|=
XFS_TRANS_ABORT
;
cancel_flags
|=
XFS_TRANS_ABORT
;
error_return
:
out_bmap_cancel
:
xfs_bmap_cancel
(
&
free_list
);
xfs_bmap_cancel
(
&
free_list
);
out_trans_cancel:
xfs_trans_cancel
(
tp
,
cancel_flags
);
xfs_trans_cancel
(
tp
,
cancel_flags
);
std_return:
if
(
wip
)
IRELE
(
wip
);
return
error
;
return
error
;
}
}
...
...
fs/xfs/xfs_iops.c
View file @
d41bb034
...
@@ -394,7 +394,7 @@ xfs_vn_rename(
...
@@ -394,7 +394,7 @@ xfs_vn_rename(
struct
xfs_name
oname
;
struct
xfs_name
oname
;
struct
xfs_name
nname
;
struct
xfs_name
nname
;
if
(
flags
&
~
(
RENAME_NOREPLACE
|
RENAME_EXCHANGE
))
if
(
flags
&
~
(
RENAME_NOREPLACE
|
RENAME_EXCHANGE
|
RENAME_WHITEOUT
))
return
-
EINVAL
;
return
-
EINVAL
;
/* if we are exchanging files, we need to set i_mode of both files */
/* if we are exchanging files, we need to set i_mode of both files */
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment