summaryrefslogtreecommitdiff
path: root/fs/overlayfs
diff options
context:
space:
mode:
authorAmir Goldstein <amir73il@gmail.com>2018-01-18 13:15:26 +0200
committerMiklos Szeredi <mszeredi@redhat.com>2018-01-24 11:26:01 +0100
commit05e1f11816d7952ef26cc37fdd6637f834d675a9 (patch)
tree99300526916d405ff06d2bd9d789372367491c4a /fs/overlayfs
parentb305e8443f3a87e794927085106db7ebc99a4f74 (diff)
ovl: copy up before encoding non-connectable dir file handle
Decoding a merge dir, whose origin's parent is under a redirected lower dir is not always possible. As a simple aproximation, we do not encode lower dir file handles when overlay has multiple lower layers and origin is below the topmost lower layer. We should later relax this condition and copy up only the parent that is under a redirected lower. Signed-off-by: Amir Goldstein <amir73il@gmail.com> Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
Diffstat (limited to 'fs/overlayfs')
-rw-r--r--fs/overlayfs/export.c53
1 files changed, 49 insertions, 4 deletions
diff --git a/fs/overlayfs/export.c b/fs/overlayfs/export.c
index 862c368883c9..9da498ea75db 100644
--- a/fs/overlayfs/export.c
+++ b/fs/overlayfs/export.c
@@ -34,17 +34,35 @@
* --------------------------------
* Pure upper | U
* Non-indexed upper | U
- * Indexed upper | L
- * Non-upper | L
+ * Indexed upper | L (*)
+ * Non-upper | L (*)
*
* U = upper file handle
* L = lower file handle
+ *
+ * (*) Connecting an overlay dir from real lower dentry is not always
+ * possible when there are redirects in lower layers. To mitigate this case,
+ * we copy up the lower dir first and then encode an upper dir file handle.
*/
static bool ovl_should_encode_origin(struct dentry *dentry)
{
+ struct ovl_fs *ofs = dentry->d_sb->s_fs_info;
+
if (!ovl_dentry_lower(dentry))
return false;
+ /*
+ * Decoding a merge dir, whose origin's parent is under a redirected
+ * lower dir is not always possible. As a simple aproximation, we do
+ * not encode lower dir file handles when overlay has multiple lower
+ * layers and origin is below the topmost lower layer.
+ *
+ * TODO: copy up only the parent that is under redirected lower.
+ */
+ if (d_is_dir(dentry) && ofs->upper_mnt &&
+ OVL_E(dentry)->lowerstack[0].layer->idx > 1)
+ return false;
+
/* Decoding a non-indexed upper from origin is not implemented */
if (ovl_dentry_upper(dentry) &&
!ovl_test_flag(OVL_INDEX, d_inode(dentry)))
@@ -53,16 +71,43 @@ static bool ovl_should_encode_origin(struct dentry *dentry)
return true;
}
+static int ovl_encode_maybe_copy_up(struct dentry *dentry)
+{
+ int err;
+
+ if (ovl_dentry_upper(dentry))
+ return 0;
+
+ err = ovl_want_write(dentry);
+ if (err)
+ return err;
+
+ err = ovl_copy_up(dentry);
+
+ ovl_drop_write(dentry);
+ return err;
+}
+
static int ovl_d_to_fh(struct dentry *dentry, char *buf, int buflen)
{
- struct dentry *upper = ovl_dentry_upper(dentry);
+ struct dentry *upper;
struct dentry *origin = ovl_dentry_lower(dentry);
struct ovl_fh *fh = NULL;
int err;
- if (!ovl_should_encode_origin(dentry))
+ /*
+ * If we should not encode a lower dir file handle, copy up and encode
+ * an upper dir file handle.
+ */
+ if (!ovl_should_encode_origin(dentry)) {
+ err = ovl_encode_maybe_copy_up(dentry);
+ if (err)
+ goto fail;
+
origin = NULL;
+ }
+ upper = ovl_dentry_upper(dentry);
err = -EACCES;
if (!upper || origin)
goto fail;