]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - fs/ubifs/tnc.c
ubifs: Implement UBIFS_FLG_DOUBLE_HASH
[karo-tx-linux.git] / fs / ubifs / tnc.c
index fa9a20cc60d6744e13ef7cc2f788f0fda0861d58..74ae2de949df68b5918a3656840eb5ab22c8cda1 100644 (file)
@@ -378,7 +378,7 @@ static void lnc_free(struct ubifs_zbranch *zbr)
 }
 
 /**
- * tnc_read_node_nm - read a "hashed" leaf node.
+ * tnc_read_hashed_node - read a "hashed" leaf node.
  * @c: UBIFS file-system description object
  * @zbr: key and position of the node
  * @node: node is returned here
@@ -388,8 +388,8 @@ static void lnc_free(struct ubifs_zbranch *zbr)
  * added to LNC. Returns zero in case of success or a negative negative error
  * code in case of failure.
  */
-static int tnc_read_node_nm(struct ubifs_info *c, struct ubifs_zbranch *zbr,
-                           void *node)
+static int tnc_read_hashed_node(struct ubifs_info *c, struct ubifs_zbranch *zbr,
+                               void *node)
 {
        int err;
 
@@ -519,7 +519,7 @@ static int fallible_read_node(struct ubifs_info *c, const union ubifs_key *key,
  * of failure, a negative error code is returned.
  */
 static int matches_name(struct ubifs_info *c, struct ubifs_zbranch *zbr,
-                       const struct qstr *nm)
+                       const struct fscrypt_name *nm)
 {
        struct ubifs_dent_node *dent;
        int nlen, err;
@@ -542,11 +542,11 @@ static int matches_name(struct ubifs_info *c, struct ubifs_zbranch *zbr,
                dent = zbr->leaf;
 
        nlen = le16_to_cpu(dent->nlen);
-       err = memcmp(dent->name, nm->name, min_t(int, nlen, nm->len));
+       err = memcmp(dent->name, fname_name(nm), min_t(int, nlen, fname_len(nm)));
        if (err == 0) {
-               if (nlen == nm->len)
+               if (nlen == fname_len(nm))
                        return NAME_MATCHES;
-               else if (nlen < nm->len)
+               else if (nlen < fname_len(nm))
                        return NAME_LESS;
                else
                        return NAME_GREATER;
@@ -689,7 +689,7 @@ static int tnc_prev(struct ubifs_info *c, struct ubifs_znode **zn, int *n)
  */
 static int resolve_collision(struct ubifs_info *c, const union ubifs_key *key,
                             struct ubifs_znode **zn, int *n,
-                            const struct qstr *nm)
+                            const struct fscrypt_name *nm)
 {
        int err;
 
@@ -807,7 +807,7 @@ static int resolve_collision(struct ubifs_info *c, const union ubifs_key *key,
  */
 static int fallible_matches_name(struct ubifs_info *c,
                                 struct ubifs_zbranch *zbr,
-                                const struct qstr *nm)
+                                const struct fscrypt_name *nm)
 {
        struct ubifs_dent_node *dent;
        int nlen, err;
@@ -835,11 +835,11 @@ static int fallible_matches_name(struct ubifs_info *c,
                dent = zbr->leaf;
 
        nlen = le16_to_cpu(dent->nlen);
-       err = memcmp(dent->name, nm->name, min_t(int, nlen, nm->len));
+       err = memcmp(dent->name, fname_name(nm), min_t(int, nlen, fname_len(nm)));
        if (err == 0) {
-               if (nlen == nm->len)
+               if (nlen == fname_len(nm))
                        return NAME_MATCHES;
-               else if (nlen < nm->len)
+               else if (nlen < fname_len(nm))
                        return NAME_LESS;
                else
                        return NAME_GREATER;
@@ -878,7 +878,8 @@ out_free:
 static int fallible_resolve_collision(struct ubifs_info *c,
                                      const union ubifs_key *key,
                                      struct ubifs_znode **zn, int *n,
-                                     const struct qstr *nm, int adding)
+                                     const struct fscrypt_name *nm,
+                                     int adding)
 {
        struct ubifs_znode *o_znode = NULL, *znode = *zn;
        int uninitialized_var(o_n), err, cmp, unsure = 0, nn = *n;
@@ -1453,7 +1454,7 @@ again:
                 * In this case the leaf node cache gets used, so we pass the
                 * address of the zbranch and keep the mutex locked
                 */
-               err = tnc_read_node_nm(c, zt, node);
+               err = tnc_read_hashed_node(c, zt, node);
                goto out;
        }
        if (safely) {
@@ -1782,19 +1783,19 @@ 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
  * was not found, and a negative error code in case of failure.
  */
 static int do_lookup_nm(struct ubifs_info *c, const union ubifs_key *key,
-                       void *node, const struct qstr *nm)
+                       void *node, const struct fscrypt_name *nm)
 {
        int found, n, err;
        struct ubifs_znode *znode;
 
-       dbg_tnck(key, "name '%.*s' key ", nm->len, nm->name);
+       //dbg_tnck(key, "name '%.*s' key ", nm->len, nm->name);
        mutex_lock(&c->tnc_mutex);
        found = ubifs_lookup_level0(c, key, &znode, &n);
        if (!found) {
@@ -1816,7 +1817,7 @@ static int do_lookup_nm(struct ubifs_info *c, const union ubifs_key *key,
                goto out_unlock;
        }
 
-       err = tnc_read_node_nm(c, &znode->zbranch[n], node);
+       err = tnc_read_hashed_node(c, &znode->zbranch[n], node);
 
 out_unlock:
        mutex_unlock(&c->tnc_mutex);
@@ -1830,14 +1831,14 @@ out_unlock:
  * @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
  * was not found, and a negative error code in case of failure.
  */
 int ubifs_tnc_lookup_nm(struct ubifs_info *c, const union ubifs_key *key,
-                       void *node, const struct qstr *nm)
+                       void *node, const struct fscrypt_name *nm)
 {
        int err, len;
        const struct ubifs_dent_node *dent = node;
@@ -1851,16 +1852,105 @@ int ubifs_tnc_lookup_nm(struct ubifs_info *c, const union ubifs_key *key,
                return err;
 
        len = le16_to_cpu(dent->nlen);
-       if (nm->len == len && !memcmp(dent->name, nm->name, len))
+       if (fname_len(nm) == len && !memcmp(dent->name, fname_name(nm), len))
                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_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 *dkey, start_key;
+
+       ubifs_assert(is_hash_key(c, key));
+
+       lowest_dent_key(c, &start_key, key_inum(c, key));
+
+       mutex_lock(&c->tnc_mutex);
+       err = ubifs_lookup_level0(c, &start_key, &znode, &n);
+       if (unlikely(err < 0))
+               goto out_unlock;
+
+       for (;;) {
+               if (!err) {
+                       err = tnc_next(c, &znode, &n);
+                       if (err)
+                               goto out_unlock;
+               }
+
+               zbr = &znode->zbranch[n];
+               dkey = &zbr->key;
+
+               if (key_inum(c, dkey) != key_inum(c, key) ||
+                   key_type(c, dkey) != 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, dkey) &&
+                   le32_to_cpu(dent->cookie) == cookie)
+                       goto out_unlock;
+       }
+
+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;
+
+       if (!c->double_hash)
+               return -EOPNOTSUPP;
+
+       /*
+        * 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
@@ -2279,14 +2369,15 @@ out_unlock:
  * may have collisions, like directory entry keys.
  */
 int ubifs_tnc_add_nm(struct ubifs_info *c, const union ubifs_key *key,
-                    int lnum, int offs, int len, const struct qstr *nm)
+                    int lnum, int offs, int len,
+                    const struct fscrypt_name *nm)
 {
        int found, n, err = 0;
        struct ubifs_znode *znode;
 
        mutex_lock(&c->tnc_mutex);
-       dbg_tnck(key, "LEB %d:%d, name '%.*s', key ",
-                lnum, offs, nm->len, nm->name);
+       //dbg_tnck(key, "LEB %d:%d, name '%.*s', key ",
+       //       lnum, offs, nm->len, nm->name);
        found = lookup_level0_dirty(c, key, &znode, &n);
        if (found < 0) {
                err = found;
@@ -2344,7 +2435,7 @@ int ubifs_tnc_add_nm(struct ubifs_info *c, const union ubifs_key *key,
                         * by passing 'ubifs_tnc_remove_nm()' the same key but
                         * an unmatchable name.
                         */
-                       struct qstr noname = { .name = "" };
+                       struct fscrypt_name noname = { .disk_name = { .name = "", .len = 1 } };
 
                        err = dbg_check_tnc(c, 0);
                        mutex_unlock(&c->tnc_mutex);
@@ -2514,13 +2605,13 @@ out_unlock:
  * Returns %0 on success or negative error code on failure.
  */
 int ubifs_tnc_remove_nm(struct ubifs_info *c, const union ubifs_key *key,
-                       const struct qstr *nm)
+                       const struct fscrypt_name *nm)
 {
        int n, err;
        struct ubifs_znode *znode;
 
        mutex_lock(&c->tnc_mutex);
-       dbg_tnck(key, "%.*s, key ", nm->len, nm->name);
+       //dbg_tnck(key, "%.*s, key ", nm->len, nm->name);
        err = lookup_level0_dirty(c, key, &znode, &n);
        if (err < 0)
                goto out_unlock;
@@ -2669,7 +2760,7 @@ int ubifs_tnc_remove_ino(struct ubifs_info *c, ino_t inum)
 {
        union ubifs_key key1, key2;
        struct ubifs_dent_node *xent, *pxent = NULL;
-       struct qstr nm = { .name = NULL };
+       struct fscrypt_name nm = {0};
 
        dbg_tnc("ino %lu", (unsigned long)inum);
 
@@ -2694,8 +2785,8 @@ int ubifs_tnc_remove_ino(struct ubifs_info *c, ino_t inum)
                dbg_tnc("xent '%s', ino %lu", xent->name,
                        (unsigned long)xattr_inum);
 
-               nm.name = xent->name;
-               nm.len = le16_to_cpu(xent->nlen);
+               fname_name(&nm) = xent->name;
+               fname_len(&nm) = le16_to_cpu(xent->nlen);
                err = ubifs_tnc_remove_nm(c, &key1, &nm);
                if (err) {
                        kfree(xent);
@@ -2747,7 +2838,7 @@ int ubifs_tnc_remove_ino(struct ubifs_info *c, ino_t inum)
  */
 struct ubifs_dent_node *ubifs_tnc_next_ent(struct ubifs_info *c,
                                           union ubifs_key *key,
-                                          const struct qstr *nm)
+                                          const struct fscrypt_name *nm)
 {
        int n, err, type = key_type(c, key);
        struct ubifs_znode *znode;
@@ -2755,7 +2846,7 @@ struct ubifs_dent_node *ubifs_tnc_next_ent(struct ubifs_info *c,
        struct ubifs_zbranch *zbr;
        union ubifs_key *dkey;
 
-       dbg_tnck(key, "%s ", nm->name ? (char *)nm->name : "(lowest)");
+       //dbg_tnck(key, "%s ", nm->name ? (char *)nm->name : "(lowest)");
        ubifs_assert(is_hash_key(c, key));
 
        mutex_lock(&c->tnc_mutex);
@@ -2763,7 +2854,7 @@ struct ubifs_dent_node *ubifs_tnc_next_ent(struct ubifs_info *c,
        if (unlikely(err < 0))
                goto out_unlock;
 
-       if (nm->name) {
+       if (fname_len(nm) > 0) {
                if (err) {
                        /* Handle collisions */
                        err = resolve_collision(c, key, &znode, &n, nm);
@@ -2813,7 +2904,7 @@ struct ubifs_dent_node *ubifs_tnc_next_ent(struct ubifs_info *c,
                goto out_free;
        }
 
-       err = tnc_read_node_nm(c, zbr, dent);
+       err = tnc_read_hashed_node(c, zbr, dent);
        if (unlikely(err))
                goto out_free;