Skip to content

Commit 5b0a414

Browse files
author
Miklos Szeredi
committed
ovl: fix filattr copy-up failure
This regression can be reproduced with ntfs-3g and overlayfs: mkdir lower upper work overlay dd if=/dev/zero of=ntfs.raw bs=1M count=2 mkntfs -F ntfs.raw mount ntfs.raw lower touch lower/file.txt mount -t overlay -o lowerdir=lower,upperdir=upper,workdir=work - overlay mv overlay/file.txt overlay/file2.txt mv fails and (misleadingly) prints mv: cannot move 'overlay/file.txt' to a subdirectory of itself, 'overlay/file2.txt' The reason is that ovl_copy_fileattr() is triggered due to S_NOATIME being set on all inodes (by fuse) regardless of fileattr. ovl_copy_fileattr() tries to retrieve file attributes from lower file, but that fails because filesystem does not support this ioctl (this should fail with ENOTTY, but ntfs-3g return EINVAL instead). This failure is propagated to origial operation (in this case rename) that triggered the copy-up. The fix is to ignore ENOTTY and EINVAL errors from fileattr_get() in copy up. This also requires turning the internal ENOIOCTLCMD into ENOTTY. As a further measure to prevent unnecessary failures, only try the fileattr_get/set on upper if there are any flags to copy up. Side note: a number of filesystems set S_NOATIME (and sometimes other inode flags) irrespective of fileattr flags. This causes unnecessary calls during copy up, which might lead to a performance issue, especially if latency is high. To fix this, the kernel would need to differentiate between the two cases. E.g. introduce SB_NOATIME_UPDATE, a per-sb variant of S_NOATIME. SB_NOATIME doesn't work, because that's interpreted as "filesystem doesn't store an atime attribute" Reported-and-tested-by: Kevin Locke <[email protected]> Fixes: 72db821 ("ovl: copy up sync/noatime fileattr flags") Cc: <[email protected]> # v5.15 Signed-off-by: Miklos Szeredi <[email protected]>
1 parent 1f5573c commit 5b0a414

File tree

2 files changed

+22
-6
lines changed

2 files changed

+22
-6
lines changed

fs/overlayfs/copy_up.c

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -140,12 +140,14 @@ static int ovl_copy_fileattr(struct inode *inode, struct path *old,
140140
int err;
141141

142142
err = ovl_real_fileattr_get(old, &oldfa);
143-
if (err)
144-
return err;
145-
146-
err = ovl_real_fileattr_get(new, &newfa);
147-
if (err)
143+
if (err) {
144+
/* Ntfs-3g returns -EINVAL for "no fileattr support" */
145+
if (err == -ENOTTY || err == -EINVAL)
146+
return 0;
147+
pr_warn("failed to retrieve lower fileattr (%pd2, err=%i)\n",
148+
old, err);
148149
return err;
150+
}
149151

150152
/*
151153
* We cannot set immutable and append-only flags on upper inode,
@@ -159,6 +161,17 @@ static int ovl_copy_fileattr(struct inode *inode, struct path *old,
159161
return err;
160162
}
161163

164+
/* Don't bother copying flags if none are set */
165+
if (!(oldfa.flags & OVL_COPY_FS_FLAGS_MASK))
166+
return 0;
167+
168+
err = ovl_real_fileattr_get(new, &newfa);
169+
if (err) {
170+
pr_warn("failed to retrieve upper fileattr (%pd2, err=%i)\n",
171+
new, err);
172+
return err;
173+
}
174+
162175
BUILD_BUG_ON(OVL_COPY_FS_FLAGS_MASK & ~FS_COMMON_FL);
163176
newfa.flags &= ~OVL_COPY_FS_FLAGS_MASK;
164177
newfa.flags |= (oldfa.flags & OVL_COPY_FS_FLAGS_MASK);

fs/overlayfs/inode.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -610,7 +610,10 @@ int ovl_real_fileattr_get(struct path *realpath, struct fileattr *fa)
610610
if (err)
611611
return err;
612612

613-
return vfs_fileattr_get(realpath->dentry, fa);
613+
err = vfs_fileattr_get(realpath->dentry, fa);
614+
if (err == -ENOIOCTLCMD)
615+
err = -ENOTTY;
616+
return err;
614617
}
615618

616619
int ovl_fileattr_get(struct dentry *dentry, struct fileattr *fa)

0 commit comments

Comments
 (0)