From: Richard Weinberger <richard@nod.at>
To: linux-mtd@lists.infradead.org
Cc: linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org,
dedekind1@gmail.com, adrian.hunter@intel.com, tytso@mit.edu,
jaegeuk@kernel.org, david@sigma-star.at, wd@denx.de,
sbabic@denx.de, dengler@linutronix.de, ebiggers@google.com,
mhalcrow@google.com, hch@infradead.org,
Richard Weinberger <richard@nod.at>
Subject: [PATCH 25/29] ubifs: Add full hash lookup support
Date: Sun, 13 Nov 2016 22:21:08 +0100 [thread overview]
Message-ID: <1479072072-6844-26-git-send-email-richard@nod.at> (raw)
In-Reply-To: <1479072072-6844-1-git-send-email-richard@nod.at>
UBIFS stores a 32bit hash of every file, for traditional lookups by name
this scheme is fine since UBIFS can first try to find the file by the
hash of the filename and upon collisions it can walk through all entries
with the same hash and do a string compare.
When filesnames are encrypted fscrypto will ask the filesystem for a
unique cookie, based on this cookie the filesystem has to be able to
locate the target file again. With 32bit hashes this is impossible
because the chance for collisions is very high. Do deal with that we
store a 32bit cookie directly in the UBIFS directory entry node such
that we get a 64bit cookie (32bit from filename hash and the dent
cookie). For a lookup by hash UBIFS finds the entry by the first 32bit
and then compares the dent cookie. If it does not match, it has to do a
linear search of the whole directory and compares all dent cookies until
the correct entry is found.
Signed-off-by: Richard Weinberger <richard@nod.at>
---
fs/ubifs/dir.c | 7 +++-
fs/ubifs/journal.c | 1 -
fs/ubifs/tnc.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++++-
fs/ubifs/ubifs-media.h | 5 ++-
fs/ubifs/ubifs.h | 2 +
5 files changed, 107 insertions(+), 7 deletions(-)
diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c
index 7d3bc3fb8831..7f01f3d2ac3b 100644
--- a/fs/ubifs/dir.c
+++ b/fs/ubifs/dir.c
@@ -253,7 +253,7 @@ static struct dentry *ubifs_lookup(struct inode *dir, struct dentry *dentry,
ubifs_assert(fname_len(&nm) == 0);
ubifs_assert(fname_name(&nm) == NULL);
dent_key_init_hash(c, &key, dir->i_ino, nm.hash);
- err = ubifs_tnc_lookup(c, &key, dent);
+ err = ubifs_tnc_lookup_dh(c, &key, dent, nm.minor_hash);
} else {
dent_key_init(c, &key, dir->i_ino, &nm);
err = ubifs_tnc_lookup_nm(c, &key, dent, &nm);
@@ -628,7 +628,10 @@ static int ubifs_readdir(struct file *file, struct dir_context *ctx)
if (encrypted) {
fstr.len = fstr_real_len;
- err = fscrypt_fname_disk_to_usr(dir, key_hash_flash(c, &dent->key), 0, &nm.disk_name, &fstr);
+ err = fscrypt_fname_disk_to_usr(dir, key_hash_flash(c,
+ &dent->key),
+ le32_to_cpu(dent->cookie),
+ &nm.disk_name, &fstr);
if (err)
goto out;
} else {
diff --git a/fs/ubifs/journal.c b/fs/ubifs/journal.c
index f2b989dbe25a..0698cccc6223 100644
--- a/fs/ubifs/journal.c
+++ b/fs/ubifs/journal.c
@@ -78,7 +78,6 @@ static inline void zero_ino_node_unused(struct ubifs_ino_node *ino)
static inline void zero_dent_node_unused(struct ubifs_dent_node *dent)
{
dent->padding1 = 0;
- memset(dent->padding2, 0, 4);
}
/**
diff --git a/fs/ubifs/tnc.c b/fs/ubifs/tnc.c
index 0d751297873e..1eaf994addb4 100644
--- a/fs/ubifs/tnc.c
+++ b/fs/ubifs/tnc.c
@@ -1783,7 +1783,7 @@ int ubifs_tnc_bulk_read(struct ubifs_info *c, struct bu_info *bu)
* @node: the node is returned here
* @nm: node name
*
- * This function look up and reads a node which contains name hash in the key.
+ * This function looks up and reads a node which contains name hash in the key.
* Since the hash may have collisions, there may be many nodes with the same
* key, so we have to sequentially look to all of them until the needed one is
* found. This function returns zero in case of success, %-ENOENT if the node
@@ -1831,7 +1831,7 @@ static int do_lookup_nm(struct ubifs_info *c, const union ubifs_key *key,
* @node: the node is returned here
* @nm: node name
*
- * This function look up and reads a node which contains name hash in the key.
+ * This function looks up and reads a node which contains name hash in the key.
* Since the hash may have collisions, there may be many nodes with the same
* key, so we have to sequentially look to all of them until the needed one is
* found. This function returns zero in case of success, %-ENOENT if the node
@@ -1859,9 +1859,104 @@ int ubifs_tnc_lookup_nm(struct ubifs_info *c, const union ubifs_key *key,
* Unluckily, there are hash collisions and we have to iterate over
* them look at each direntry with colliding name hash sequentially.
*/
+
return do_lookup_nm(c, key, node, nm);
}
+static int do_lookup_dh(struct ubifs_info *c, const union ubifs_key *key,
+ struct ubifs_dent_node *dent, uint32_t cookie)
+{
+ int n, err, type = key_type(c, key);
+ struct ubifs_znode *znode;
+ struct ubifs_zbranch *zbr;
+ union ubifs_key *cur_key, start_key;
+
+ ubifs_assert(is_hash_key(c, key));
+
+ lowest_dent_key(c, &start_key, key_inum(c, key));
+ cur_key = &start_key;
+
+ for (;;) {
+ mutex_lock(&c->tnc_mutex);
+
+ err = ubifs_lookup_level0(c, cur_key, &znode, &n);
+ if (unlikely(err < 0))
+ goto out_unlock;
+
+ if (!err) {
+ err = tnc_next(c, &znode, &n);
+ if (err)
+ goto out_unlock;
+ }
+
+ zbr = &znode->zbranch[n];
+ cur_key = &zbr->key;
+
+ if (key_inum(c, cur_key) != key_inum(c, key) ||
+ key_type(c, cur_key) != type) {
+ err = -ENOENT;
+ goto out_unlock;
+ }
+
+ err = tnc_read_hashed_node(c, zbr, dent);
+ if (err)
+ goto out_unlock;
+
+ if (key_hash(c, key) == key_hash(c, cur_key) &&
+ le32_to_cpu(dent->cookie) == cookie) {
+ /* We found the entry. :-) */
+ err = 0;
+ goto out_unlock;
+ }
+
+ mutex_unlock(&c->tnc_mutex);
+ }
+
+ ubifs_assert(0);
+
+out_unlock:
+ mutex_unlock(&c->tnc_mutex);
+ return err;
+}
+
+/**
+ * ubifs_tnc_lookup_dh - look up a "double hashed" node.
+ * @c: UBIFS file-system description object
+ * @key: node key to lookup
+ * @node: the node is returned here
+ * @cookie: node cookie for collision resolution
+ *
+ * This function looks up and reads a node which contains name hash in the key.
+ * Since the hash may have collisions, there may be many nodes with the same
+ * key, so we have to sequentially look to all of them until the needed one
+ * with the same cookie value is found.
+ * This function returns zero in case of success, %-ENOENT if the node
+ * was not found, and a negative error code in case of failure.
+ */
+int ubifs_tnc_lookup_dh(struct ubifs_info *c, const union ubifs_key *key,
+ void *node, uint32_t cookie)
+{
+ int err;
+ const struct ubifs_dent_node *dent = node;
+
+ /*
+ * We assume that in most of the cases there are no name collisions and
+ * 'ubifs_tnc_lookup()' returns us the right direntry.
+ */
+ err = ubifs_tnc_lookup(c, key, node);
+ if (err)
+ return err;
+
+ if (le32_to_cpu(dent->cookie) == cookie)
+ return 0;
+
+ /*
+ * Unluckily, there are hash collisions and we have to iterate over
+ * them look at each direntry with colliding name hash sequentially.
+ */
+ return do_lookup_dh(c, key, node, cookie);
+}
+
/**
* correct_parent_keys - correct parent znodes' keys.
* @c: UBIFS file-system description object
diff --git a/fs/ubifs/ubifs-media.h b/fs/ubifs/ubifs-media.h
index e46331dcca4c..249124d9a801 100644
--- a/fs/ubifs/ubifs-media.h
+++ b/fs/ubifs/ubifs-media.h
@@ -530,7 +530,8 @@ struct ubifs_ino_node {
* @padding1: reserved for future, zeroes
* @type: type of the target inode (%UBIFS_ITYPE_REG, %UBIFS_ITYPE_DIR, etc)
* @nlen: name length
- * @padding2: reserved for future, zeroes
+ * @cookie: A 32bits random number, used to construct a 64bits
+ * identifier.
* @name: zero-terminated name
*
* Note, do not forget to amend 'zero_dent_node_unused()' function when
@@ -543,7 +544,7 @@ struct ubifs_dent_node {
__u8 padding1;
__u8 type;
__le16 nlen;
- __u8 padding2[4]; /* Watch 'zero_dent_node_unused()' if changing! */
+ __le32 cookie;
__u8 name[];
} __packed;
diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h
index 122c7d95eb8e..8d9946082665 100644
--- a/fs/ubifs/ubifs.h
+++ b/fs/ubifs/ubifs.h
@@ -1580,6 +1580,8 @@ int ubifs_lookup_level0(struct ubifs_info *c, const union ubifs_key *key,
struct ubifs_znode **zn, int *n);
int ubifs_tnc_lookup_nm(struct ubifs_info *c, const union ubifs_key *key,
void *node, const struct fscrypt_name *nm);
+int ubifs_tnc_lookup_dh(struct ubifs_info *c, const union ubifs_key *key,
+ void *node, uint32_t secondary_hash);
int ubifs_tnc_locate(struct ubifs_info *c, const union ubifs_key *key,
void *node, int *lnum, int *offs);
int ubifs_tnc_add(struct ubifs_info *c, const union ubifs_key *key, int lnum,
--
2.7.3
next prev parent reply other threads:[~2016-11-13 21:24 UTC|newest]
Thread overview: 47+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-11-13 21:20 [PATCH 00/29] UBIFS File Encryption v1 Richard Weinberger
2016-11-13 21:20 ` [PATCH 01/29] fscrypt: Add in-place encryption mode Richard Weinberger
2016-11-15 18:14 ` Eric Biggers
2016-11-25 12:09 ` David Gstir
2016-11-27 6:49 ` Eric Biggers
2016-11-13 21:20 ` [PATCH 02/29] fscrypt: Allow fscrypt_decrypt_page() to function with non-writeback pages Richard Weinberger
2016-11-15 18:19 ` Eric Biggers
2016-11-24 17:43 ` David Gstir
2016-11-13 21:20 ` [PATCH 03/29] fscrypt: Enable partial page encryption Richard Weinberger
2016-11-15 18:31 ` Eric Biggers
2016-11-13 21:20 ` [PATCH 04/29] fscrypt: Constify struct inode pointer Richard Weinberger
2016-11-13 21:20 ` [PATCH 05/29] fscrypt: Let fs select encryption index/tweak Richard Weinberger
2016-11-15 18:43 ` Eric Biggers
[not found] ` <98AAB80A-A0BE-4408-A514-DC3B8D19C5F7@sigma-star.at>
2016-11-27 7:00 ` Eric Biggers
2016-11-13 21:20 ` [PATCH 06/29] ubifs: Export ubifs_check_dir_empty() Richard Weinberger
2016-11-13 21:20 ` [PATCH 07/29] ubifs: Export xattr get and set functions Richard Weinberger
2016-11-13 21:20 ` [PATCH 08/29] ubifs: Define UBIFS crypto context xattr Richard Weinberger
2016-11-13 21:20 ` [PATCH 09/29] ubifs: Add skeleton for fscrypto Richard Weinberger
2016-11-13 21:20 ` [PATCH 10/29] ubifs: Massage ubifs_listxattr() for encryption context Richard Weinberger
2016-11-13 21:20 ` [PATCH 11/29] ubifs: Implement directory open operation Richard Weinberger
2016-11-13 21:20 ` [PATCH 12/29] ubifs: Implement file " Richard Weinberger
2016-11-13 21:20 ` [PATCH 13/29] ubifs: Enforce crypto policy in ->link and ->rename Richard Weinberger
2016-11-13 21:20 ` [PATCH 14/29] ubifs: Preload crypto context in ->lookup() Richard Weinberger
2016-11-13 21:20 ` [PATCH 15/29] ubifs: Massage assert in ubifs_xattr_set() wrt. fscrypto Richard Weinberger
2016-11-13 21:20 ` [PATCH 16/29] ubifs: Enforce crypto policy in mmap Richard Weinberger
2016-11-13 21:21 ` [PATCH 17/29] ubifs: Introduce new data node field, compr_size Richard Weinberger
2016-11-13 21:21 ` [PATCH 18/29] ubifs: Constify struct inode pointer in ubifs_crypt_is_encrypted() Richard Weinberger
2016-11-13 21:21 ` [PATCH 19/29] ubifs: Implement encrypt/decrypt for all IO Richard Weinberger
2016-11-13 23:03 ` kbuild test robot
2016-11-13 21:21 ` [PATCH 20/29] ubifs: Relax checks in ubifs_validate_entry() Richard Weinberger
2016-11-13 21:21 ` [PATCH 21/29] ubifs: Make r5 hash binary string aware Richard Weinberger
2016-11-13 21:21 ` [PATCH 22/29] ubifs: Implement encrypted filenames Richard Weinberger
2016-11-13 21:21 ` [PATCH 23/29] ubifs: Add support for encrypted symlinks Richard Weinberger
2016-11-13 21:21 ` [PATCH 24/29] ubifs: Rename tnc_read_node_nm Richard Weinberger
2016-11-13 21:21 ` Richard Weinberger [this message]
2016-11-13 21:21 ` [PATCH 26/29] ubifs: Use a random number for cookies Richard Weinberger
2016-11-13 21:21 ` [PATCH 27/29] ubifs: Implement UBIFS_FLG_DOUBLE_HASH Richard Weinberger
2016-11-13 21:21 ` [PATCH 28/29] ubifs: Implement UBIFS_FLG_ENCRYPTION Richard Weinberger
2016-11-13 21:21 ` [PATCH 29/29] ubifs: Raise write version to 5 Richard Weinberger
2016-11-14 3:05 ` [PATCH 00/29] UBIFS File Encryption v1 Theodore Ts'o
2016-11-14 12:01 ` Richard Weinberger
2016-11-25 8:18 ` Richard Weinberger
2016-11-27 17:52 ` Theodore Ts'o
2016-11-27 22:21 ` Richard Weinberger
2016-11-28 0:43 ` Theodore Ts'o
2016-11-28 1:27 ` Eric Biggers
2016-11-29 2:27 ` Theodore Ts'o
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1479072072-6844-26-git-send-email-richard@nod.at \
--to=richard@nod.at \
--cc=adrian.hunter@intel.com \
--cc=david@sigma-star.at \
--cc=dedekind1@gmail.com \
--cc=dengler@linutronix.de \
--cc=ebiggers@google.com \
--cc=hch@infradead.org \
--cc=jaegeuk@kernel.org \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mtd@lists.infradead.org \
--cc=mhalcrow@google.com \
--cc=sbabic@denx.de \
--cc=tytso@mit.edu \
--cc=wd@denx.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).