@@ -978,9 +978,6 @@ static int _fuse_atomic_open(struct inode *dir, struct dentry *entry,
goto out_free_ff;
}
goto free_and_fallback;
- } else if (err == -ELOOP) {
- /* likely a symlink */
- goto free_and_fallback;
} else {
if (d_really_is_positive(entry)) {
if (err != -EINTR && err != -ENOMEM)
@@ -1090,15 +1087,23 @@ static int _fuse_atomic_open(struct inode *dir, struct dentry *entry,
}
}
- if (S_ISDIR(mode))
+ if (S_ISDIR(mode) || S_ISDIR(outentry.attr.mode))
ff->open_flags &= ~FOPEN_DIRECT_IO;
- err = finish_open(file, entry, generic_file_open);
- if (err) {
- fi = get_fuse_inode(inode);
- fuse_sync_release(fi, ff, flags);
- } else {
- file->private_data = ff;
- fuse_finish_open(inode, file);
+
+ if (S_ISLNK(outentry.attr.mode)) {
+ err = finish_no_open(file, entry);
+ if (!alias)
+ dget(entry);
+ } else {
+ err = finish_open(file, entry, generic_file_open);
+ if (err) {
+ fi = get_fuse_inode(inode);
+ fuse_sync_release(fi, ff, flags);
+ } else {
+ file->private_data = ff;
+ fuse_finish_open(inode, file);
+ }
+ dput(alias);
}
kfree(forget);
@@ -1108,8 +1113,6 @@ static int _fuse_atomic_open(struct inode *dir, struct dentry *entry,
dput(switched_entry);
}
- dput(alias);
-
return err;
out_free_ff:
Symlinks must not be opened as it would result in ELOOP, but fallback to fuse_create_open is also not ideal, as it would result in atomic-open + lookup for symlinks. Atomic-open already carries all information lookup provides, so just use that and then call finish_no_open instead of finish_open. Codewise, as finish_no_open consumes a reference, compared to finish_open, dput(alias) must not be called for symlinks. Obviously, if we don't have an additional alias reference yet, we need to get one for symlinks. Signed-off-by: Bernd Schubert <bschubert@ddn.com> Cc: Miklos Szeredi <miklos@szeredi.hu> Cc: Dharmendra Singh <dsingh@ddn.com> Cc: Horst Birthelmer <hbirthelmer@ddn.com> Cc: linux-fsdevel@vger.kernel.org --- (If preferred, this could be merged into the main fuse atomic revalidate patch). Or adding the function could be moved up in the series. --- fs/fuse/dir.c | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-)