Skip to content

Commit a19239b

Browse files
dhowellsbrauner
authored andcommitted
afs: Add support for RENAME_NOREPLACE and RENAME_EXCHANGE
Add support for RENAME_NOREPLACE and RENAME_EXCHANGE, if the server supports them. The default is translated to YFS.Rename_Replace, falling back to YFS.Rename; RENAME_NOREPLACE is translated to YFS.Rename_NoReplace and RENAME_EXCHANGE to YFS.Rename_Exchange, both of which fall back to reporting EINVAL. Signed-off-by: David Howells <dhowells@redhat.com> Link: https://lore.kernel.org/740476.1758718189@warthog.procyon.org.uk cc: Marc Dionne <marc.dionne@auristor.com> cc: Dan Carpenter <dan.carpenter@linaro.org> cc: linux-afs@lists.infradead.org Signed-off-by: Christian Brauner <brauner@kernel.org>
1 parent 8f5ae30 commit a19239b

10 files changed

Lines changed: 480 additions & 64 deletions

File tree

fs/afs/dir.c

Lines changed: 176 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1823,7 +1823,8 @@ static int afs_symlink(struct mnt_idmap *idmap, struct inode *dir,
18231823

18241824
static void afs_rename_success(struct afs_operation *op)
18251825
{
1826-
struct afs_vnode *vnode = AFS_FS_I(d_inode(op->dentry));
1826+
struct afs_vnode *vnode = op->more_files[0].vnode;
1827+
struct afs_vnode *new_vnode = op->more_files[1].vnode;
18271828

18281829
_enter("op=%08x", op->debug_id);
18291830

@@ -1834,22 +1835,40 @@ static void afs_rename_success(struct afs_operation *op)
18341835
op->ctime = op->file[1].scb.status.mtime_client;
18351836
afs_vnode_commit_status(op, &op->file[1]);
18361837
}
1838+
if (op->more_files[0].scb.have_status)
1839+
afs_vnode_commit_status(op, &op->more_files[0]);
1840+
if (op->more_files[1].scb.have_status)
1841+
afs_vnode_commit_status(op, &op->more_files[1]);
18371842

18381843
/* If we're moving a subdir between dirs, we need to update
18391844
* its DV counter too as the ".." will be altered.
18401845
*/
1841-
if (S_ISDIR(vnode->netfs.inode.i_mode) &&
1842-
op->file[0].vnode != op->file[1].vnode) {
1843-
u64 new_dv;
1846+
if (op->file[0].vnode != op->file[1].vnode) {
1847+
if (S_ISDIR(vnode->netfs.inode.i_mode)) {
1848+
u64 new_dv;
18441849

1845-
write_seqlock(&vnode->cb_lock);
1850+
write_seqlock(&vnode->cb_lock);
18461851

1847-
new_dv = vnode->status.data_version + 1;
1848-
trace_afs_set_dv(vnode, new_dv);
1849-
vnode->status.data_version = new_dv;
1850-
inode_set_iversion_raw(&vnode->netfs.inode, new_dv);
1852+
new_dv = vnode->status.data_version + 1;
1853+
trace_afs_set_dv(vnode, new_dv);
1854+
vnode->status.data_version = new_dv;
1855+
inode_set_iversion_raw(&vnode->netfs.inode, new_dv);
18511856

1852-
write_sequnlock(&vnode->cb_lock);
1857+
write_sequnlock(&vnode->cb_lock);
1858+
}
1859+
1860+
if ((op->rename.rename_flags & RENAME_EXCHANGE) &&
1861+
S_ISDIR(new_vnode->netfs.inode.i_mode)) {
1862+
u64 new_dv;
1863+
1864+
write_seqlock(&new_vnode->cb_lock);
1865+
1866+
new_dv = new_vnode->status.data_version + 1;
1867+
new_vnode->status.data_version = new_dv;
1868+
inode_set_iversion_raw(&new_vnode->netfs.inode, new_dv);
1869+
1870+
write_sequnlock(&new_vnode->cb_lock);
1871+
}
18531872
}
18541873
}
18551874

@@ -1900,8 +1919,8 @@ static void afs_rename_edit_dir(struct afs_operation *op)
19001919
if (S_ISDIR(vnode->netfs.inode.i_mode) &&
19011920
new_dvnode != orig_dvnode &&
19021921
test_bit(AFS_VNODE_DIR_VALID, &vnode->flags))
1903-
afs_edit_dir_update_dotdot(vnode, new_dvnode,
1904-
afs_edit_dir_for_rename_sub);
1922+
afs_edit_dir_update(vnode, &dotdot_name, new_dvnode,
1923+
afs_edit_dir_for_rename_sub);
19051924

19061925
new_inode = d_inode(new_dentry);
19071926
if (new_inode) {
@@ -1915,9 +1934,6 @@ static void afs_rename_edit_dir(struct afs_operation *op)
19151934

19161935
/* Now we can update d_fsdata on the dentries to reflect their
19171936
* new parent's data_version.
1918-
*
1919-
* Note that if we ever implement RENAME_EXCHANGE, we'll have
1920-
* to update both dentries with opposing dir versions.
19211937
*/
19221938
afs_update_dentry_version(op, new_dvp, op->dentry);
19231939
afs_update_dentry_version(op, new_dvp, op->dentry_2);
@@ -1930,6 +1946,67 @@ static void afs_rename_edit_dir(struct afs_operation *op)
19301946
fscache_end_operation(&new_cres);
19311947
}
19321948

1949+
static void afs_rename_exchange_edit_dir(struct afs_operation *op)
1950+
{
1951+
struct afs_vnode_param *orig_dvp = &op->file[0];
1952+
struct afs_vnode_param *new_dvp = &op->file[1];
1953+
struct afs_vnode *orig_dvnode = orig_dvp->vnode;
1954+
struct afs_vnode *new_dvnode = new_dvp->vnode;
1955+
struct afs_vnode *old_vnode = op->more_files[0].vnode;
1956+
struct afs_vnode *new_vnode = op->more_files[1].vnode;
1957+
struct dentry *old_dentry = op->dentry;
1958+
struct dentry *new_dentry = op->dentry_2;
1959+
1960+
_enter("op=%08x", op->debug_id);
1961+
1962+
if (new_dvnode == orig_dvnode) {
1963+
down_write(&orig_dvnode->validate_lock);
1964+
if (test_bit(AFS_VNODE_DIR_VALID, &orig_dvnode->flags) &&
1965+
orig_dvnode->status.data_version == orig_dvp->dv_before + orig_dvp->dv_delta) {
1966+
afs_edit_dir_update(orig_dvnode, &old_dentry->d_name,
1967+
new_vnode, afs_edit_dir_for_rename_0);
1968+
afs_edit_dir_update(orig_dvnode, &new_dentry->d_name,
1969+
old_vnode, afs_edit_dir_for_rename_1);
1970+
}
1971+
1972+
d_exchange(old_dentry, new_dentry);
1973+
up_write(&orig_dvnode->validate_lock);
1974+
} else {
1975+
down_write(&orig_dvnode->validate_lock);
1976+
if (test_bit(AFS_VNODE_DIR_VALID, &orig_dvnode->flags) &&
1977+
orig_dvnode->status.data_version == orig_dvp->dv_before + orig_dvp->dv_delta)
1978+
afs_edit_dir_update(orig_dvnode, &old_dentry->d_name,
1979+
new_vnode, afs_edit_dir_for_rename_0);
1980+
1981+
up_write(&orig_dvnode->validate_lock);
1982+
down_write(&new_dvnode->validate_lock);
1983+
1984+
if (test_bit(AFS_VNODE_DIR_VALID, &new_dvnode->flags) &&
1985+
new_dvnode->status.data_version == new_dvp->dv_before + new_dvp->dv_delta)
1986+
afs_edit_dir_update(new_dvnode, &new_dentry->d_name,
1987+
old_vnode, afs_edit_dir_for_rename_1);
1988+
1989+
if (S_ISDIR(old_vnode->netfs.inode.i_mode) &&
1990+
test_bit(AFS_VNODE_DIR_VALID, &old_vnode->flags))
1991+
afs_edit_dir_update(old_vnode, &dotdot_name, new_dvnode,
1992+
afs_edit_dir_for_rename_sub);
1993+
1994+
if (S_ISDIR(new_vnode->netfs.inode.i_mode) &&
1995+
test_bit(AFS_VNODE_DIR_VALID, &new_vnode->flags))
1996+
afs_edit_dir_update(new_vnode, &dotdot_name, orig_dvnode,
1997+
afs_edit_dir_for_rename_sub);
1998+
1999+
/* Now we can update d_fsdata on the dentries to reflect their
2000+
* new parents' data_version.
2001+
*/
2002+
afs_update_dentry_version(op, new_dvp, old_dentry);
2003+
afs_update_dentry_version(op, orig_dvp, new_dentry);
2004+
2005+
d_exchange(old_dentry, new_dentry);
2006+
up_write(&new_dvnode->validate_lock);
2007+
}
2008+
}
2009+
19332010
static void afs_rename_put(struct afs_operation *op)
19342011
{
19352012
_enter("op=%08x", op->debug_id);
@@ -1948,6 +2025,32 @@ static const struct afs_operation_ops afs_rename_operation = {
19482025
.put = afs_rename_put,
19492026
};
19502027

2028+
#if 0 /* Autoswitched in yfs_fs_rename_replace(). */
2029+
static const struct afs_operation_ops afs_rename_replace_operation = {
2030+
.issue_afs_rpc = NULL,
2031+
.issue_yfs_rpc = yfs_fs_rename_replace,
2032+
.success = afs_rename_success,
2033+
.edit_dir = afs_rename_edit_dir,
2034+
.put = afs_rename_put,
2035+
};
2036+
#endif
2037+
2038+
static const struct afs_operation_ops afs_rename_noreplace_operation = {
2039+
.issue_afs_rpc = NULL,
2040+
.issue_yfs_rpc = yfs_fs_rename_noreplace,
2041+
.success = afs_rename_success,
2042+
.edit_dir = afs_rename_edit_dir,
2043+
.put = afs_rename_put,
2044+
};
2045+
2046+
static const struct afs_operation_ops afs_rename_exchange_operation = {
2047+
.issue_afs_rpc = NULL,
2048+
.issue_yfs_rpc = yfs_fs_rename_exchange,
2049+
.success = afs_rename_success,
2050+
.edit_dir = afs_rename_exchange_edit_dir,
2051+
.put = afs_rename_put,
2052+
};
2053+
19512054
/*
19522055
* rename a file in an AFS filesystem and/or move it between directories
19532056
*/
@@ -1956,10 +2059,10 @@ static int afs_rename(struct mnt_idmap *idmap, struct inode *old_dir,
19562059
struct dentry *new_dentry, unsigned int flags)
19572060
{
19582061
struct afs_operation *op;
1959-
struct afs_vnode *orig_dvnode, *new_dvnode, *vnode;
2062+
struct afs_vnode *orig_dvnode, *new_dvnode, *vnode, *new_vnode = NULL;
19602063
int ret;
19612064

1962-
if (flags)
2065+
if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE))
19632066
return -EINVAL;
19642067

19652068
/* Don't allow silly-rename files be moved around. */
@@ -1969,6 +2072,8 @@ static int afs_rename(struct mnt_idmap *idmap, struct inode *old_dir,
19692072
vnode = AFS_FS_I(d_inode(old_dentry));
19702073
orig_dvnode = AFS_FS_I(old_dir);
19712074
new_dvnode = AFS_FS_I(new_dir);
2075+
if (d_is_positive(new_dentry))
2076+
new_vnode = AFS_FS_I(d_inode(new_dentry));
19722077

19732078
_enter("{%llx:%llu},{%llx:%llu},{%llx:%llu},{%pd}",
19742079
orig_dvnode->fid.vid, orig_dvnode->fid.vnode,
@@ -1989,6 +2094,11 @@ static int afs_rename(struct mnt_idmap *idmap, struct inode *old_dir,
19892094
if (ret < 0)
19902095
goto error;
19912096

2097+
ret = -ENOMEM;
2098+
op->more_files = kvcalloc(2, sizeof(struct afs_vnode_param), GFP_KERNEL);
2099+
if (!op->more_files)
2100+
goto error;
2101+
19922102
afs_op_set_vnode(op, 0, orig_dvnode);
19932103
afs_op_set_vnode(op, 1, new_dvnode); /* May be same as orig_dvnode */
19942104
op->file[0].dv_delta = 1;
@@ -1997,46 +2107,63 @@ static int afs_rename(struct mnt_idmap *idmap, struct inode *old_dir,
19972107
op->file[1].modification = true;
19982108
op->file[0].update_ctime = true;
19992109
op->file[1].update_ctime = true;
2110+
op->more_files[0].vnode = vnode;
2111+
op->more_files[0].speculative = true;
2112+
op->more_files[1].vnode = new_vnode;
2113+
op->more_files[1].speculative = true;
2114+
op->nr_files = 4;
20002115

20012116
op->dentry = old_dentry;
20022117
op->dentry_2 = new_dentry;
2118+
op->rename.rename_flags = flags;
20032119
op->rename.new_negative = d_is_negative(new_dentry);
2004-
op->ops = &afs_rename_operation;
20052120

2006-
/* For non-directories, check whether the target is busy and if so,
2007-
* make a copy of the dentry and then do a silly-rename. If the
2008-
* silly-rename succeeds, the copied dentry is hashed and becomes the
2009-
* new target.
2010-
*/
2011-
if (d_is_positive(new_dentry) && !d_is_dir(new_dentry)) {
2012-
/* To prevent any new references to the target during the
2013-
* rename, we unhash the dentry in advance.
2121+
if (flags & RENAME_NOREPLACE) {
2122+
op->ops = &afs_rename_noreplace_operation;
2123+
} else if (flags & RENAME_EXCHANGE) {
2124+
op->ops = &afs_rename_exchange_operation;
2125+
d_drop(new_dentry);
2126+
} else {
2127+
/* If we might displace the target, we might need to do silly
2128+
* rename.
20142129
*/
2015-
if (!d_unhashed(new_dentry)) {
2016-
d_drop(new_dentry);
2017-
op->rename.rehash = new_dentry;
2018-
}
2130+
op->ops = &afs_rename_operation;
20192131

2020-
if (d_count(new_dentry) > 2) {
2021-
/* copy the target dentry's name */
2022-
op->rename.tmp = d_alloc(new_dentry->d_parent,
2023-
&new_dentry->d_name);
2024-
if (!op->rename.tmp) {
2025-
afs_op_nomem(op);
2026-
goto error;
2132+
/* For non-directories, check whether the target is busy and if
2133+
* so, make a copy of the dentry and then do a silly-rename.
2134+
* If the silly-rename succeeds, the copied dentry is hashed
2135+
* and becomes the new target.
2136+
*/
2137+
if (d_is_positive(new_dentry) && !d_is_dir(new_dentry)) {
2138+
/* To prevent any new references to the target during
2139+
* the rename, we unhash the dentry in advance.
2140+
*/
2141+
if (!d_unhashed(new_dentry)) {
2142+
d_drop(new_dentry);
2143+
op->rename.rehash = new_dentry;
20272144
}
20282145

2029-
ret = afs_sillyrename(new_dvnode,
2030-
AFS_FS_I(d_inode(new_dentry)),
2031-
new_dentry, op->key);
2032-
if (ret) {
2033-
afs_op_set_error(op, ret);
2034-
goto error;
2146+
if (d_count(new_dentry) > 2) {
2147+
/* copy the target dentry's name */
2148+
op->rename.tmp = d_alloc(new_dentry->d_parent,
2149+
&new_dentry->d_name);
2150+
if (!op->rename.tmp) {
2151+
afs_op_nomem(op);
2152+
goto error;
2153+
}
2154+
2155+
ret = afs_sillyrename(new_dvnode,
2156+
AFS_FS_I(d_inode(new_dentry)),
2157+
new_dentry, op->key);
2158+
if (ret) {
2159+
afs_op_set_error(op, ret);
2160+
goto error;
2161+
}
2162+
2163+
op->dentry_2 = op->rename.tmp;
2164+
op->rename.rehash = NULL;
2165+
op->rename.new_negative = true;
20352166
}
2036-
2037-
op->dentry_2 = op->rename.tmp;
2038-
op->rename.rehash = NULL;
2039-
op->rename.new_negative = true;
20402167
}
20412168
}
20422169

@@ -2052,6 +2179,8 @@ static int afs_rename(struct mnt_idmap *idmap, struct inode *old_dir,
20522179
d_drop(old_dentry);
20532180

20542181
ret = afs_do_sync_operation(op);
2182+
if (ret == -ENOTSUPP)
2183+
ret = -EINVAL;
20552184
out:
20562185
afs_dir_unuse_cookie(orig_dvnode, ret);
20572186
if (new_dvnode != orig_dvnode)

fs/afs/dir_edit.c

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -522,11 +522,11 @@ void afs_edit_dir_remove(struct afs_vnode *vnode,
522522
}
523523

524524
/*
525-
* Edit a subdirectory that has been moved between directories to update the
526-
* ".." entry.
525+
* Edit an entry in a directory to update the vnode it refers to. This is also
526+
* used to update the ".." entry in a directory.
527527
*/
528-
void afs_edit_dir_update_dotdot(struct afs_vnode *vnode, struct afs_vnode *new_dvnode,
529-
enum afs_edit_dir_reason why)
528+
void afs_edit_dir_update(struct afs_vnode *vnode, const struct qstr *name,
529+
struct afs_vnode *new_dvnode, enum afs_edit_dir_reason why)
530530
{
531531
union afs_xdr_dir_block *block;
532532
union afs_xdr_dirent *de;
@@ -557,7 +557,7 @@ void afs_edit_dir_update_dotdot(struct afs_vnode *vnode, struct afs_vnode *new_d
557557
if (!test_bit(AFS_VNODE_DIR_VALID, &vnode->flags))
558558
goto already_invalidated;
559559

560-
slot = afs_dir_scan_block(block, &dotdot_name, b);
560+
slot = afs_dir_scan_block(block, name, b);
561561
if (slot >= 0)
562562
goto found_dirent;
563563

@@ -566,7 +566,7 @@ void afs_edit_dir_update_dotdot(struct afs_vnode *vnode, struct afs_vnode *new_d
566566

567567
/* Didn't find the dirent to clobber. Download the directory again. */
568568
trace_afs_edit_dir(vnode, why, afs_edit_dir_update_nodd,
569-
0, 0, 0, 0, "..");
569+
0, 0, 0, 0, name->name);
570570
afs_invalidate_dir(vnode, afs_dir_invalid_edit_upd_no_dd);
571571
goto out;
572572

@@ -576,7 +576,7 @@ void afs_edit_dir_update_dotdot(struct afs_vnode *vnode, struct afs_vnode *new_d
576576
de->u.unique = htonl(new_dvnode->fid.unique);
577577

578578
trace_afs_edit_dir(vnode, why, afs_edit_dir_update_dd, b, slot,
579-
ntohl(de->u.vnode), ntohl(de->u.unique), "..");
579+
ntohl(de->u.vnode), ntohl(de->u.unique), name->name);
580580

581581
kunmap_local(block);
582582
netfs_single_mark_inode_dirty(&vnode->netfs.inode);
@@ -589,12 +589,12 @@ void afs_edit_dir_update_dotdot(struct afs_vnode *vnode, struct afs_vnode *new_d
589589
already_invalidated:
590590
kunmap_local(block);
591591
trace_afs_edit_dir(vnode, why, afs_edit_dir_update_inval,
592-
0, 0, 0, 0, "..");
592+
0, 0, 0, 0, name->name);
593593
goto out;
594594

595595
error:
596596
trace_afs_edit_dir(vnode, why, afs_edit_dir_update_error,
597-
0, 0, 0, 0, "..");
597+
0, 0, 0, 0, name->name);
598598
goto out;
599599
}
600600

0 commit comments

Comments
 (0)