Re: [RFC][PATCH] ovl: check lower ancestry on encode of lower dir file handle

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, Feb 15, 2018 at 6:07 PM, Miklos Szeredi <miklos@xxxxxxxxxx> wrote:
> On Tue, Feb 6, 2018 at 1:21 PM, Amir Goldstein <amir73il@xxxxxxxxx> wrote:
>> This change relaxes copy up on encode of merge dir with lower layer > 1
>> and handles the case of encoding a merge dir with lower layer 1, where an
>> ancestor is a non-indexed merge dir. In that case, decode of the lower
>> file handle will not have been possible if the non-indexed ancestor is
>> redirected before or after encode.
>>
>> Before encoding a non-upper directory file handle from real layer N, we
>> need to check if it will be possible to reconnect an overlay dentry from
>> the real lower decoded dentry. This is done by following the overlay
>> ancestry up to a 'layer N connected' ancestor and verifying that all
>> parents along the way are 'layer N connectable'. If an ancestor that is
>> NOT 'layer N connectable' is found, we need to copy up an ancestor, which
>> is 'layer N connectable', thus making that ancestor 'layer N connected'.
>
> Makes sense.  One comment inline, otherwise looks good.
>
>> For example:
>>
>>  layer 1: /a
>>  layer 2: /a/b/c
>>
>> The overlay dentry /a is NOT 'layer 2 connectable', because if dir /a is
>> copied up and renamed, upper dir /a will be indexed by lower dir /a from
>> layer 1. The dir /a from layer 2 will never be indexed, so the alrogithm
>> in ovl_lookup_real_ancestor() (*) will not be able to lookup a connected
>> overlay dentry from the connected lower dentry /a/b/c.
>>
>> To avoid this problem on decode time, we need to copy up an ancestor of
>> /a/b/c, which is 'layer 2 connectable', on encode time. That ancestor is
>> /a/b. After copy up (and index) of /a/b, it will become 'layer 2 connected'
>> and when the time comes to decode the file handle from lower dentry /a/b/c,
>> ovl_lookup_real_ancestor() will find the indexed ancestor /a/b and decoding
>> a connected overlay dentry will be accomplished.
>>
>> (*) the alrogithm in ovl_lookup_real_ancestor() can be improved to lookup
>> an entry /a in the lower layers above layer N and find the indexed dir /a
>> from layer 1. If that improvement is made, then the check for 'layer N
>> connected' will need to verify there are no redirects in lower layers above
>> layer N. In the example above, /a will be 'layer 2 connectable'. However,
>> if layer 2 dir /a is a target of a layer 1 redirect, then /a will NOT be
>> 'layer 2 connectable':
>>
>>  layer 1: /A (redirect = /a)
>>  layer 2: /a/b/c
>>
>> Signed-off-by: Amir Goldstein <amir73il@xxxxxxxxx>
>> ---
>>
>> Miklos,
>>
>> I was able to convince myself that this patch is correct and it passed
>> all existing tests and some manual tests of the new cases.
>>
>> I was also able to convince myself that the single CONNECTED bit in dentry
>> is all the optimization we need and that there is no added value in
>> gathering more state information on lookup.
>> This extra lookup information or redirected lower layers will be needed if
>> we ever implement (*) above.
>>
>> Was I able to also convince you that this patch is correct? and that no
>> extra lookup information is needed?
>>
>> I will write more tests to cover the cases handles by this change.
>>
>> Thanks,
>> Amir.
>>
>>  fs/overlayfs/export.c    | 176 +++++++++++++++++++++++++++++++++++++++--------
>>  fs/overlayfs/overlayfs.h |   1 +
>>  2 files changed, 147 insertions(+), 30 deletions(-)
>>
>> diff --git a/fs/overlayfs/export.c b/fs/overlayfs/export.c
>> index 07d70255095b..b545e3b8249f 100644
>> --- a/fs/overlayfs/export.c
>> +++ b/fs/overlayfs/export.c
>> @@ -19,6 +19,138 @@
>>  #include <linux/ratelimit.h>
>>  #include "overlayfs.h"
>>
>> +
>> +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) {
>> +               err = ovl_copy_up(dentry);
>> +               ovl_drop_write(dentry);
>> +       }
>> +
>> +       if (err) {
>> +               pr_warn_ratelimited("overlayfs: failed to copy up on encode (%pd2, err=%i)\n",
>> +                                   dentry, err);
>> +       }
>> +
>> +       return err;
>> +}
>> +
>> +/*
>> + * Before encoding a non-upper directory file handle from real layer N, we need
>> + * to check if it will be possible to reconnect an overlay dentry from the real
>> + * lower decoded dentry. This is done by following the overlay ancestry up to a
>> + * 'layer N connected' ancestor and verifying that all parents along the way are
>> + * 'layer N connectable'. If an ancestor that is NOT 'layer N connectable' is
>> + * found, we need to copy up an ancestor, which is 'layer N connectable', thus
>> + * making that ancestor 'layer N connected'. For example:
>> + *
>> + * layer 1: /a
>> + * layer 2: /a/b/c
>> + *
>> + * The overlay dentry /a is NOT 'layer 2 connectable', because if dir /a is
>> + * copied up and renamed, upper dir /a will be indexed by lower dir /a from
>> + * layer 1. The dir /a from layer 2 will never be indexed, so the alrogithm (*)
>> + * in ovl_lookup_real_ancestor() will not be able to lookup a connected overlay
>> + * dentry from the connected lower dentry /a/b/c.
>> + *
>> + * To avoid this problem on decode time, we need to copy up an ancestor of
>> + * /a/b/c, which is 'layer 2 connectable', on encode time. That ancestor is
>> + * /a/b. After copy up (and index) of /a/b, it will become 'layer 2 connected'
>> + * and when the time comes to decode the file handle from lower dentry /a/b/c,
>> + * ovl_lookup_real_ancestor() will find the indexed ancestor /a/b and decoding
>> + * a connected overlay dentry will be accomplished.
>> + *
>> + * (*) the alrogithm in ovl_lookup_real_ancestor() can be improved to lookup an
>> + * entry /a in the lower layers above layer N and find the indexed dir /a from
>> + * layer 1. If that improvement is made, then the check for 'layer N connected'
>> + * will need to verify there are no redirects in lower layers above N. In the
>> + * example above, /a will be 'layer 2 connectable'. However, if layer 2 dir /a
>> + * is a target of a layer 1 redirect, then /a will NOT be 'layer 2 connectable':
>> + *
>> + * layer 1: /A (redirect = /a)
>> + * layer 2: /a/b/c
>> + */
>> +static int ovl_dentry_connectable_layer(struct dentry *dentry)
>> +{
>> +       struct ovl_entry *oe = OVL_E(dentry);
>> +
>> +       /* We can get overlay root from root of any layer */
>> +       if (dentry == dentry->d_sb->s_root)
>> +               return oe->numlower;
>> +
>> +       /* We cannot get upper/overlay path from non-indexed lower dentry */
>> +       if (ovl_dentry_upper(dentry) &&
>
> Code is contradicting comment.  I guess code is wrong?
>


This is patch v1, but already posted patch v2 with a bug fix.
patch v2 has a comment above this function:
/* Return 0 for upper file handle, > 0 for lower file handle or < 0 on error. */

N-connectable means you can get from layer <= N to overlay path.
Returning 0 here mean 0-connected, meaning only upper file handle
can be decoded.

What do you find contradicting in code/comment?

>> +           !ovl_test_flag(OVL_INDEX, d_inode(dentry)))
>> +               return 0;
>> +
>> +       /* Pure upper cannot be ancestor of non pure upper */
>> +       if (WARN_ON(!oe->numlower))
>> +               return 0;
>> +
>> +       /* We can get upper/overlay path from indexed/lower dentry */
>> +       return oe->lowerstack[0].layer->idx;
>> +}
>> +

Thanks,
Amir.
--
To unsubscribe from this list: send the line "unsubscribe linux-unionfs" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux Filesystems Devel]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux