2024-01-03 15:20:02

by Chuck Lever

[permalink] [raw]
Subject: [PATCH v2 2/2] fs: Create a generic is_dot_dotdot() utility

From: Chuck Lever <[email protected]>

De-duplicate the same functionality in several places by hoisting
the is_dot_dotdot() function into linux/fs.h.

Suggested-by: Amir Goldstein <[email protected]>
Signed-off-by: Chuck Lever <[email protected]>
---
fs/crypto/fname.c | 8 +-------
fs/ecryptfs/crypto.c | 10 ----------
fs/exportfs/expfs.c | 4 +---
fs/f2fs/f2fs.h | 11 -----------
include/linux/fs.h | 9 +++++++++
5 files changed, 11 insertions(+), 31 deletions(-)

diff --git a/fs/crypto/fname.c b/fs/crypto/fname.c
index 7b3fc189593a..0ad52fbe51c9 100644
--- a/fs/crypto/fname.c
+++ b/fs/crypto/fname.c
@@ -74,13 +74,7 @@ struct fscrypt_nokey_name {

static inline bool fscrypt_is_dot_dotdot(const struct qstr *str)
{
- if (str->len == 1 && str->name[0] == '.')
- return true;
-
- if (str->len == 2 && str->name[0] == '.' && str->name[1] == '.')
- return true;
-
- return false;
+ return is_dot_dotdot(str->name, str->len);
}

/**
diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c
index 03bd55069d86..2fe0f3af1a08 100644
--- a/fs/ecryptfs/crypto.c
+++ b/fs/ecryptfs/crypto.c
@@ -1949,16 +1949,6 @@ int ecryptfs_encrypt_and_encode_filename(
return rc;
}

-static bool is_dot_dotdot(const char *name, size_t name_size)
-{
- if (name_size == 1 && name[0] == '.')
- return true;
- else if (name_size == 2 && name[0] == '.' && name[1] == '.')
- return true;
-
- return false;
-}
-
/**
* ecryptfs_decode_and_decrypt_filename - converts the encoded cipher text name to decoded plaintext
* @plaintext_name: The plaintext name
diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c
index 84af58eaf2ca..07ea3d62b298 100644
--- a/fs/exportfs/expfs.c
+++ b/fs/exportfs/expfs.c
@@ -255,9 +255,7 @@ static bool filldir_one(struct dir_context *ctx, const char *name, int len,
container_of(ctx, struct getdents_callback, ctx);

buf->sequence++;
- /* Ignore the '.' and '..' entries */
- if ((len > 2 || name[0] != '.' || (len == 2 && name[1] != '.')) &&
- buf->ino == ino && len <= NAME_MAX) {
+ if (buf->ino == ino && len <= NAME_MAX && !is_dot_dotdot(name, len)) {
memcpy(buf->name, name, len);
buf->name[len] = '\0';
buf->found = 1;
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 9043cedfa12b..322a3b8a3533 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -3368,17 +3368,6 @@ static inline bool f2fs_cp_error(struct f2fs_sb_info *sbi)
return is_set_ckpt_flags(sbi, CP_ERROR_FLAG);
}

-static inline bool is_dot_dotdot(const u8 *name, size_t len)
-{
- if (len == 1 && name[0] == '.')
- return true;
-
- if (len == 2 && name[0] == '.' && name[1] == '.')
- return true;
-
- return false;
-}
-
static inline void *f2fs_kmalloc(struct f2fs_sb_info *sbi,
size_t size, gfp_t flags)
{
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 98b7a7a8c42e..179eea797c22 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2846,6 +2846,15 @@ extern bool path_is_under(const struct path *, const struct path *);

extern char *file_path(struct file *, char *, int);

+static inline bool is_dot_dotdot(const char *name, size_t len)
+{
+ if (len == 1 && name[0] == '.')
+ return true;
+ if (len == 2 && name[0] == '.' && name[1] == '.')
+ return true;
+ return false;
+}
+
#include <linux/err.h>

/* needed for stackable file system support */




2024-01-03 19:08:03

by Jeffrey Layton

[permalink] [raw]
Subject: Re: [PATCH v2 2/2] fs: Create a generic is_dot_dotdot() utility

On Wed, 2024-01-03 at 10:19 -0500, Chuck Lever wrote:
> From: Chuck Lever <[email protected]>
>
> De-duplicate the same functionality in several places by hoisting
> the is_dot_dotdot() function into linux/fs.h.
>
> Suggested-by: Amir Goldstein <[email protected]>
> Signed-off-by: Chuck Lever <[email protected]>
> ---
> fs/crypto/fname.c | 8 +-------
> fs/ecryptfs/crypto.c | 10 ----------
> fs/exportfs/expfs.c | 4 +---
> fs/f2fs/f2fs.h | 11 -----------
> include/linux/fs.h | 9 +++++++++
> 5 files changed, 11 insertions(+), 31 deletions(-)
>
> diff --git a/fs/crypto/fname.c b/fs/crypto/fname.c
> index 7b3fc189593a..0ad52fbe51c9 100644
> --- a/fs/crypto/fname.c
> +++ b/fs/crypto/fname.c
> @@ -74,13 +74,7 @@ struct fscrypt_nokey_name {
>
> static inline bool fscrypt_is_dot_dotdot(const struct qstr *str)
> {
> - if (str->len == 1 && str->name[0] == '.')
> - return true;
> -
> - if (str->len == 2 && str->name[0] == '.' && str->name[1] == '.')
> - return true;
> -
> - return false;
> + return is_dot_dotdot(str->name, str->len);
> }
>
> /**
> diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c
> index 03bd55069d86..2fe0f3af1a08 100644
> --- a/fs/ecryptfs/crypto.c
> +++ b/fs/ecryptfs/crypto.c
> @@ -1949,16 +1949,6 @@ int ecryptfs_encrypt_and_encode_filename(
> return rc;
> }
>
> -static bool is_dot_dotdot(const char *name, size_t name_size)
> -{
> - if (name_size == 1 && name[0] == '.')
> - return true;
> - else if (name_size == 2 && name[0] == '.' && name[1] == '.')
> - return true;
> -
> - return false;
> -}
> -
> /**
> * ecryptfs_decode_and_decrypt_filename - converts the encoded cipher text name to decoded plaintext
> * @plaintext_name: The plaintext name
> diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c
> index 84af58eaf2ca..07ea3d62b298 100644
> --- a/fs/exportfs/expfs.c
> +++ b/fs/exportfs/expfs.c
> @@ -255,9 +255,7 @@ static bool filldir_one(struct dir_context *ctx, const char *name, int len,
> container_of(ctx, struct getdents_callback, ctx);
>
> buf->sequence++;
> - /* Ignore the '.' and '..' entries */
> - if ((len > 2 || name[0] != '.' || (len == 2 && name[1] != '.')) &&
> - buf->ino == ino && len <= NAME_MAX) {
> + if (buf->ino == ino && len <= NAME_MAX && !is_dot_dotdot(name, len)) {
> memcpy(buf->name, name, len);
> buf->name[len] = '\0';
> buf->found = 1;
> diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
> index 9043cedfa12b..322a3b8a3533 100644
> --- a/fs/f2fs/f2fs.h
> +++ b/fs/f2fs/f2fs.h
> @@ -3368,17 +3368,6 @@ static inline bool f2fs_cp_error(struct f2fs_sb_info *sbi)
> return is_set_ckpt_flags(sbi, CP_ERROR_FLAG);
> }
>
> -static inline bool is_dot_dotdot(const u8 *name, size_t len)
> -{
> - if (len == 1 && name[0] == '.')
> - return true;
> -
> - if (len == 2 && name[0] == '.' && name[1] == '.')
> - return true;
> -
> - return false;
> -}
> -
> static inline void *f2fs_kmalloc(struct f2fs_sb_info *sbi,
> size_t size, gfp_t flags)
> {
> diff --git a/include/linux/fs.h b/include/linux/fs.h
> index 98b7a7a8c42e..179eea797c22 100644
> --- a/include/linux/fs.h
> +++ b/include/linux/fs.h
> @@ -2846,6 +2846,15 @@ extern bool path_is_under(const struct path *, const struct path *);
>
> extern char *file_path(struct file *, char *, int);
>
> +static inline bool is_dot_dotdot(const char *name, size_t len)
> +{
> + if (len == 1 && name[0] == '.')
> + return true;
> + if (len == 2 && name[0] == '.' && name[1] == '.')
> + return true;
> + return false;
> +}
> +
> #include <linux/err.h>
>
> /* needed for stackable file system support */
>
>

Looks good to me. I took a quick look to see if there were other open-
coded versions, but I didn't see any.

Reviewed-by: Jeff Layton <[email protected]>

2024-01-04 07:46:25

by Amir Goldstein

[permalink] [raw]
Subject: Re: [PATCH v2 2/2] fs: Create a generic is_dot_dotdot() utility

On Wed, Jan 3, 2024 at 9:08 PM Jeff Layton <[email protected]> wrote:
>
> On Wed, 2024-01-03 at 10:19 -0500, Chuck Lever wrote:
> > From: Chuck Lever <[email protected]>
> >
> > De-duplicate the same functionality in several places by hoisting
> > the is_dot_dotdot() function into linux/fs.h.
> >
> > Suggested-by: Amir Goldstein <[email protected]>
> > Signed-off-by: Chuck Lever <[email protected]>
> > ---
> > fs/crypto/fname.c | 8 +-------
> > fs/ecryptfs/crypto.c | 10 ----------
> > fs/exportfs/expfs.c | 4 +---
> > fs/f2fs/f2fs.h | 11 -----------
> > include/linux/fs.h | 9 +++++++++
> > 5 files changed, 11 insertions(+), 31 deletions(-)
> >
> > diff --git a/fs/crypto/fname.c b/fs/crypto/fname.c
> > index 7b3fc189593a..0ad52fbe51c9 100644
> > --- a/fs/crypto/fname.c
> > +++ b/fs/crypto/fname.c
> > @@ -74,13 +74,7 @@ struct fscrypt_nokey_name {
> >
> > static inline bool fscrypt_is_dot_dotdot(const struct qstr *str)
> > {
> > - if (str->len == 1 && str->name[0] == '.')
> > - return true;
> > -
> > - if (str->len == 2 && str->name[0] == '.' && str->name[1] == '.')
> > - return true;
> > -
> > - return false;
> > + return is_dot_dotdot(str->name, str->len);
> > }
> >
> > /**
> > diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c
> > index 03bd55069d86..2fe0f3af1a08 100644
> > --- a/fs/ecryptfs/crypto.c
> > +++ b/fs/ecryptfs/crypto.c
> > @@ -1949,16 +1949,6 @@ int ecryptfs_encrypt_and_encode_filename(
> > return rc;
> > }
> >
> > -static bool is_dot_dotdot(const char *name, size_t name_size)
> > -{
> > - if (name_size == 1 && name[0] == '.')
> > - return true;
> > - else if (name_size == 2 && name[0] == '.' && name[1] == '.')
> > - return true;
> > -
> > - return false;
> > -}
> > -
> > /**
> > * ecryptfs_decode_and_decrypt_filename - converts the encoded cipher text name to decoded plaintext
> > * @plaintext_name: The plaintext name
> > diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c
> > index 84af58eaf2ca..07ea3d62b298 100644
> > --- a/fs/exportfs/expfs.c
> > +++ b/fs/exportfs/expfs.c
> > @@ -255,9 +255,7 @@ static bool filldir_one(struct dir_context *ctx, const char *name, int len,
> > container_of(ctx, struct getdents_callback, ctx);
> >
> > buf->sequence++;
> > - /* Ignore the '.' and '..' entries */
> > - if ((len > 2 || name[0] != '.' || (len == 2 && name[1] != '.')) &&
> > - buf->ino == ino && len <= NAME_MAX) {
> > + if (buf->ino == ino && len <= NAME_MAX && !is_dot_dotdot(name, len)) {
> > memcpy(buf->name, name, len);
> > buf->name[len] = '\0';
> > buf->found = 1;
> > diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
> > index 9043cedfa12b..322a3b8a3533 100644
> > --- a/fs/f2fs/f2fs.h
> > +++ b/fs/f2fs/f2fs.h
> > @@ -3368,17 +3368,6 @@ static inline bool f2fs_cp_error(struct f2fs_sb_info *sbi)
> > return is_set_ckpt_flags(sbi, CP_ERROR_FLAG);
> > }
> >
> > -static inline bool is_dot_dotdot(const u8 *name, size_t len)
> > -{
> > - if (len == 1 && name[0] == '.')
> > - return true;
> > -
> > - if (len == 2 && name[0] == '.' && name[1] == '.')
> > - return true;
> > -
> > - return false;
> > -}
> > -
> > static inline void *f2fs_kmalloc(struct f2fs_sb_info *sbi,
> > size_t size, gfp_t flags)
> > {
> > diff --git a/include/linux/fs.h b/include/linux/fs.h
> > index 98b7a7a8c42e..179eea797c22 100644
> > --- a/include/linux/fs.h
> > +++ b/include/linux/fs.h
> > @@ -2846,6 +2846,15 @@ extern bool path_is_under(const struct path *, const struct path *);
> >
> > extern char *file_path(struct file *, char *, int);
> >
> > +static inline bool is_dot_dotdot(const char *name, size_t len)
> > +{
> > + if (len == 1 && name[0] == '.')
> > + return true;
> > + if (len == 2 && name[0] == '.' && name[1] == '.')
> > + return true;
> > + return false;
> > +}
> > +
> > #include <linux/err.h>
> >
> > /* needed for stackable file system support */
> >
> >
>
> Looks good to me. I took a quick look to see if there were other open-
> coded versions, but I didn't see any.
>

The outstanding open-coded version that wasn't deduped is in
lookup_one_common(), which is the version that Trond used and
mentioned in his patch.

It is also a slightly more "efficient" version, but I have no idea if
that really matters.

In any case, having lookup_one_common() and get_name() use
the same helper is clearly prefered, because the check in lookup_one()
is the declared reason for the get_name() patch.

Thanks,
Amir.

2024-01-04 14:22:37

by Chuck Lever

[permalink] [raw]
Subject: Re: [PATCH v2 2/2] fs: Create a generic is_dot_dotdot() utility

On Thu, Jan 04, 2024 at 09:46:07AM +0200, Amir Goldstein wrote:
> On Wed, Jan 3, 2024 at 9:08 PM Jeff Layton <[email protected]> wrote:
> >
> > On Wed, 2024-01-03 at 10:19 -0500, Chuck Lever wrote:
> > > From: Chuck Lever <[email protected]>
> > >
> > > De-duplicate the same functionality in several places by hoisting
> > > the is_dot_dotdot() function into linux/fs.h.
> > >
> > > Suggested-by: Amir Goldstein <[email protected]>
> > > Signed-off-by: Chuck Lever <[email protected]>
> > > ---
> > > fs/crypto/fname.c | 8 +-------
> > > fs/ecryptfs/crypto.c | 10 ----------
> > > fs/exportfs/expfs.c | 4 +---
> > > fs/f2fs/f2fs.h | 11 -----------
> > > include/linux/fs.h | 9 +++++++++
> > > 5 files changed, 11 insertions(+), 31 deletions(-)
> > >
> > > diff --git a/fs/crypto/fname.c b/fs/crypto/fname.c
> > > index 7b3fc189593a..0ad52fbe51c9 100644
> > > --- a/fs/crypto/fname.c
> > > +++ b/fs/crypto/fname.c
> > > @@ -74,13 +74,7 @@ struct fscrypt_nokey_name {
> > >
> > > static inline bool fscrypt_is_dot_dotdot(const struct qstr *str)
> > > {
> > > - if (str->len == 1 && str->name[0] == '.')
> > > - return true;
> > > -
> > > - if (str->len == 2 && str->name[0] == '.' && str->name[1] == '.')
> > > - return true;
> > > -
> > > - return false;
> > > + return is_dot_dotdot(str->name, str->len);
> > > }
> > >
> > > /**
> > > diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c
> > > index 03bd55069d86..2fe0f3af1a08 100644
> > > --- a/fs/ecryptfs/crypto.c
> > > +++ b/fs/ecryptfs/crypto.c
> > > @@ -1949,16 +1949,6 @@ int ecryptfs_encrypt_and_encode_filename(
> > > return rc;
> > > }
> > >
> > > -static bool is_dot_dotdot(const char *name, size_t name_size)
> > > -{
> > > - if (name_size == 1 && name[0] == '.')
> > > - return true;
> > > - else if (name_size == 2 && name[0] == '.' && name[1] == '.')
> > > - return true;
> > > -
> > > - return false;
> > > -}
> > > -
> > > /**
> > > * ecryptfs_decode_and_decrypt_filename - converts the encoded cipher text name to decoded plaintext
> > > * @plaintext_name: The plaintext name
> > > diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c
> > > index 84af58eaf2ca..07ea3d62b298 100644
> > > --- a/fs/exportfs/expfs.c
> > > +++ b/fs/exportfs/expfs.c
> > > @@ -255,9 +255,7 @@ static bool filldir_one(struct dir_context *ctx, const char *name, int len,
> > > container_of(ctx, struct getdents_callback, ctx);
> > >
> > > buf->sequence++;
> > > - /* Ignore the '.' and '..' entries */
> > > - if ((len > 2 || name[0] != '.' || (len == 2 && name[1] != '.')) &&
> > > - buf->ino == ino && len <= NAME_MAX) {
> > > + if (buf->ino == ino && len <= NAME_MAX && !is_dot_dotdot(name, len)) {
> > > memcpy(buf->name, name, len);
> > > buf->name[len] = '\0';
> > > buf->found = 1;
> > > diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
> > > index 9043cedfa12b..322a3b8a3533 100644
> > > --- a/fs/f2fs/f2fs.h
> > > +++ b/fs/f2fs/f2fs.h
> > > @@ -3368,17 +3368,6 @@ static inline bool f2fs_cp_error(struct f2fs_sb_info *sbi)
> > > return is_set_ckpt_flags(sbi, CP_ERROR_FLAG);
> > > }
> > >
> > > -static inline bool is_dot_dotdot(const u8 *name, size_t len)
> > > -{
> > > - if (len == 1 && name[0] == '.')
> > > - return true;
> > > -
> > > - if (len == 2 && name[0] == '.' && name[1] == '.')
> > > - return true;
> > > -
> > > - return false;
> > > -}
> > > -
> > > static inline void *f2fs_kmalloc(struct f2fs_sb_info *sbi,
> > > size_t size, gfp_t flags)
> > > {
> > > diff --git a/include/linux/fs.h b/include/linux/fs.h
> > > index 98b7a7a8c42e..179eea797c22 100644
> > > --- a/include/linux/fs.h
> > > +++ b/include/linux/fs.h
> > > @@ -2846,6 +2846,15 @@ extern bool path_is_under(const struct path *, const struct path *);
> > >
> > > extern char *file_path(struct file *, char *, int);
> > >
> > > +static inline bool is_dot_dotdot(const char *name, size_t len)
> > > +{
> > > + if (len == 1 && name[0] == '.')
> > > + return true;
> > > + if (len == 2 && name[0] == '.' && name[1] == '.')
> > > + return true;
> > > + return false;
> > > +}
> > > +
> > > #include <linux/err.h>
> > >
> > > /* needed for stackable file system support */
> > >
> > >
> >
> > Looks good to me. I took a quick look to see if there were other open-
> > coded versions, but I didn't see any.
> >
>
> The outstanding open-coded version that wasn't deduped is in
> lookup_one_common(), which is the version that Trond used and
> mentioned in his patch.
>
> It is also a slightly more "efficient" version, but I have no idea if
> that really matters.

It probably matters in lookup_one_common(), but not in any of the
other callers.


> In any case, having lookup_one_common() and get_name() use
> the same helper is clearly prefered, because the check in lookup_one()
> is the declared reason for the get_name() patch.

I will send a v3.

--
Chuck Lever