Skip to content

Commit 528e3d1

Browse files
ubifs: Add full hash lookup support
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>
1 parent b91dc98 commit 528e3d1

File tree

5 files changed

+98
-7
lines changed

5 files changed

+98
-7
lines changed

fs/ubifs/dir.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ static struct dentry *ubifs_lookup(struct inode *dir, struct dentry *dentry,
253253
ubifs_assert(fname_len(&nm) == 0);
254254
ubifs_assert(fname_name(&nm) == NULL);
255255
dent_key_init_hash(c, &key, dir->i_ino, nm.hash);
256-
err = ubifs_tnc_lookup(c, &key, dent);
256+
err = ubifs_tnc_lookup_dh(c, &key, dent, nm.minor_hash);
257257
} else {
258258
dent_key_init(c, &key, dir->i_ino, &nm);
259259
err = ubifs_tnc_lookup_nm(c, &key, dent, &nm);
@@ -628,7 +628,10 @@ static int ubifs_readdir(struct file *file, struct dir_context *ctx)
628628
if (encrypted) {
629629
fstr.len = fstr_real_len;
630630

631-
err = fscrypt_fname_disk_to_usr(dir, key_hash_flash(c, &dent->key), 0, &nm.disk_name, &fstr);
631+
err = fscrypt_fname_disk_to_usr(dir, key_hash_flash(c,
632+
&dent->key),
633+
le32_to_cpu(dent->cookie),
634+
&nm.disk_name, &fstr);
632635
if (err)
633636
goto out;
634637
} else {

fs/ubifs/journal.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,6 @@ static inline void zero_ino_node_unused(struct ubifs_ino_node *ino)
7878
static inline void zero_dent_node_unused(struct ubifs_dent_node *dent)
7979
{
8080
dent->padding1 = 0;
81-
memset(dent->padding2, 0, 4);
8281
}
8382

8483
/**

fs/ubifs/tnc.c

Lines changed: 88 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1783,7 +1783,7 @@ int ubifs_tnc_bulk_read(struct ubifs_info *c, struct bu_info *bu)
17831783
* @node: the node is returned here
17841784
* @nm: node name
17851785
*
1786-
* This function look up and reads a node which contains name hash in the key.
1786+
* This function looks up and reads a node which contains name hash in the key.
17871787
* Since the hash may have collisions, there may be many nodes with the same
17881788
* key, so we have to sequentially look to all of them until the needed one is
17891789
* 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,
18311831
* @node: the node is returned here
18321832
* @nm: node name
18331833
*
1834-
* This function look up and reads a node which contains name hash in the key.
1834+
* This function looks up and reads a node which contains name hash in the key.
18351835
* Since the hash may have collisions, there may be many nodes with the same
18361836
* key, so we have to sequentially look to all of them until the needed one is
18371837
* found. This function returns zero in case of success, %-ENOENT if the node
@@ -1859,9 +1859,95 @@ int ubifs_tnc_lookup_nm(struct ubifs_info *c, const union ubifs_key *key,
18591859
* Unluckily, there are hash collisions and we have to iterate over
18601860
* them look at each direntry with colliding name hash sequentially.
18611861
*/
1862+
18621863
return do_lookup_nm(c, key, node, nm);
18631864
}
18641865

1866+
static int do_lookup_dh(struct ubifs_info *c, const union ubifs_key *key,
1867+
struct ubifs_dent_node *dent, uint32_t cookie)
1868+
{
1869+
int n, err, type = key_type(c, key);
1870+
struct ubifs_znode *znode;
1871+
struct ubifs_zbranch *zbr;
1872+
union ubifs_key *dkey, start_key;
1873+
1874+
ubifs_assert(is_hash_key(c, key));
1875+
1876+
lowest_dent_key(c, &start_key, key_inum(c, key));
1877+
1878+
mutex_lock(&c->tnc_mutex);
1879+
err = ubifs_lookup_level0(c, &start_key, &znode, &n);
1880+
if (unlikely(err < 0))
1881+
goto out_unlock;
1882+
1883+
for (;;) {
1884+
if (!err) {
1885+
err = tnc_next(c, &znode, &n);
1886+
if (err)
1887+
goto out_unlock;
1888+
}
1889+
1890+
zbr = &znode->zbranch[n];
1891+
dkey = &zbr->key;
1892+
1893+
if (key_inum(c, dkey) != key_inum(c, key) ||
1894+
key_type(c, dkey) != type) {
1895+
err = -ENOENT;
1896+
goto out_unlock;
1897+
}
1898+
1899+
err = tnc_read_hashed_node(c, zbr, dent);
1900+
if (err)
1901+
goto out_unlock;
1902+
1903+
if (key_hash(c, key) == key_hash(c, dkey) &&
1904+
le32_to_cpu(dent->cookie) == cookie)
1905+
goto out_unlock;
1906+
}
1907+
1908+
out_unlock:
1909+
mutex_unlock(&c->tnc_mutex);
1910+
return err;
1911+
}
1912+
1913+
/**
1914+
* ubifs_tnc_lookup_dh - look up a "double hashed" node.
1915+
* @c: UBIFS file-system description object
1916+
* @key: node key to lookup
1917+
* @node: the node is returned here
1918+
* @cookie: node cookie for collision resolution
1919+
*
1920+
* This function looks up and reads a node which contains name hash in the key.
1921+
* Since the hash may have collisions, there may be many nodes with the same
1922+
* key, so we have to sequentially look to all of them until the needed one
1923+
* with the same cookie value is found.
1924+
* This function returns zero in case of success, %-ENOENT if the node
1925+
* was not found, and a negative error code in case of failure.
1926+
*/
1927+
int ubifs_tnc_lookup_dh(struct ubifs_info *c, const union ubifs_key *key,
1928+
void *node, uint32_t cookie)
1929+
{
1930+
int err;
1931+
const struct ubifs_dent_node *dent = node;
1932+
1933+
/*
1934+
* We assume that in most of the cases there are no name collisions and
1935+
* 'ubifs_tnc_lookup()' returns us the right direntry.
1936+
*/
1937+
err = ubifs_tnc_lookup(c, key, node);
1938+
if (err)
1939+
return err;
1940+
1941+
if (le32_to_cpu(dent->cookie) == cookie)
1942+
return 0;
1943+
1944+
/*
1945+
* Unluckily, there are hash collisions and we have to iterate over
1946+
* them look at each direntry with colliding name hash sequentially.
1947+
*/
1948+
return do_lookup_dh(c, key, node, cookie);
1949+
}
1950+
18651951
/**
18661952
* correct_parent_keys - correct parent znodes' keys.
18671953
* @c: UBIFS file-system description object

fs/ubifs/ubifs-media.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -530,7 +530,8 @@ struct ubifs_ino_node {
530530
* @padding1: reserved for future, zeroes
531531
* @type: type of the target inode (%UBIFS_ITYPE_REG, %UBIFS_ITYPE_DIR, etc)
532532
* @nlen: name length
533-
* @padding2: reserved for future, zeroes
533+
* @cookie: A 32bits random number, used to construct a 64bits
534+
* identifier.
534535
* @name: zero-terminated name
535536
*
536537
* Note, do not forget to amend 'zero_dent_node_unused()' function when
@@ -543,7 +544,7 @@ struct ubifs_dent_node {
543544
__u8 padding1;
544545
__u8 type;
545546
__le16 nlen;
546-
__u8 padding2[4]; /* Watch 'zero_dent_node_unused()' if changing! */
547+
__le32 cookie;
547548
__u8 name[];
548549
} __packed;
549550

fs/ubifs/ubifs.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1571,6 +1571,8 @@ int ubifs_lookup_level0(struct ubifs_info *c, const union ubifs_key *key,
15711571
struct ubifs_znode **zn, int *n);
15721572
int ubifs_tnc_lookup_nm(struct ubifs_info *c, const union ubifs_key *key,
15731573
void *node, const struct fscrypt_name *nm);
1574+
int ubifs_tnc_lookup_dh(struct ubifs_info *c, const union ubifs_key *key,
1575+
void *node, uint32_t secondary_hash);
15741576
int ubifs_tnc_locate(struct ubifs_info *c, const union ubifs_key *key,
15751577
void *node, int *lnum, int *offs);
15761578
int ubifs_tnc_add(struct ubifs_info *c, const union ubifs_key *key, int lnum,

0 commit comments

Comments
 (0)