diff options
author | Eric Sandeen <sandeen@redhat.com> | 2008-02-06 04:38:37 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2008-02-06 13:41:13 -0500 |
commit | af440f52927e4b6941aa94e3cfc698adb0f22663 (patch) | |
tree | 00a7fdc2b09e8e6146f0fd0bc055688d58eea939 /fs/ecryptfs | |
parent | 19e66a67e9b25874cd5e184e7d381ce1b955df11 (diff) |
ecryptfs: check for existing key_tfm at mount time
Jeff Moyer pointed out that a mount; umount loop of ecryptfs, with the same
cipher & other mount options, created a new ecryptfs_key_tfm_cache item
each time, and the cache could grow quite large this way.
Looking at this with mhalcrow, we saw that ecryptfs_parse_options()
unconditionally called ecryptfs_add_new_key_tfm(), which is what was adding
these items.
Refactor ecryptfs_get_tfm_and_mutex_for_cipher_name() to create a new
helper function, ecryptfs_tfm_exists(), which checks for the cipher on the
cached key_tfm_list, and sets a pointer to it if it exists. This can then
be called from ecryptfs_parse_options(), and new key_tfm's can be added
only when a cached one is not found.
With list locking changes suggested by akpm.
Signed-off-by: Eric Sandeen <sandeen@redhat.com>
Cc: Michael Halcrow <mhalcrow@us.ibm.com>
Cc: Jeff Moyer <jmoyer@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/ecryptfs')
-rw-r--r-- | fs/ecryptfs/crypto.c | 67 | ||||
-rw-r--r-- | fs/ecryptfs/ecryptfs_kernel.h | 3 | ||||
-rw-r--r-- | fs/ecryptfs/main.c | 10 |
3 files changed, 63 insertions, 17 deletions
diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c index 40d14625f515..a066e109ad9c 100644 --- a/fs/ecryptfs/crypto.c +++ b/fs/ecryptfs/crypto.c | |||
@@ -1779,7 +1779,7 @@ out: | |||
1779 | 1779 | ||
1780 | struct kmem_cache *ecryptfs_key_tfm_cache; | 1780 | struct kmem_cache *ecryptfs_key_tfm_cache; |
1781 | static struct list_head key_tfm_list; | 1781 | static struct list_head key_tfm_list; |
1782 | static struct mutex key_tfm_list_mutex; | 1782 | struct mutex key_tfm_list_mutex; |
1783 | 1783 | ||
1784 | int ecryptfs_init_crypto(void) | 1784 | int ecryptfs_init_crypto(void) |
1785 | { | 1785 | { |
@@ -1788,6 +1788,11 @@ int ecryptfs_init_crypto(void) | |||
1788 | return 0; | 1788 | return 0; |
1789 | } | 1789 | } |
1790 | 1790 | ||
1791 | /** | ||
1792 | * ecryptfs_destroy_crypto - free all cached key_tfms on key_tfm_list | ||
1793 | * | ||
1794 | * Called only at module unload time | ||
1795 | */ | ||
1791 | int ecryptfs_destroy_crypto(void) | 1796 | int ecryptfs_destroy_crypto(void) |
1792 | { | 1797 | { |
1793 | struct ecryptfs_key_tfm *key_tfm, *key_tfm_tmp; | 1798 | struct ecryptfs_key_tfm *key_tfm, *key_tfm_tmp; |
@@ -1811,6 +1816,8 @@ ecryptfs_add_new_key_tfm(struct ecryptfs_key_tfm **key_tfm, char *cipher_name, | |||
1811 | struct ecryptfs_key_tfm *tmp_tfm; | 1816 | struct ecryptfs_key_tfm *tmp_tfm; |
1812 | int rc = 0; | 1817 | int rc = 0; |
1813 | 1818 | ||
1819 | BUG_ON(!mutex_is_locked(&key_tfm_list_mutex)); | ||
1820 | |||
1814 | tmp_tfm = kmem_cache_alloc(ecryptfs_key_tfm_cache, GFP_KERNEL); | 1821 | tmp_tfm = kmem_cache_alloc(ecryptfs_key_tfm_cache, GFP_KERNEL); |
1815 | if (key_tfm != NULL) | 1822 | if (key_tfm != NULL) |
1816 | (*key_tfm) = tmp_tfm; | 1823 | (*key_tfm) = tmp_tfm; |
@@ -1837,13 +1844,50 @@ ecryptfs_add_new_key_tfm(struct ecryptfs_key_tfm **key_tfm, char *cipher_name, | |||
1837 | (*key_tfm) = NULL; | 1844 | (*key_tfm) = NULL; |
1838 | goto out; | 1845 | goto out; |
1839 | } | 1846 | } |
1840 | mutex_lock(&key_tfm_list_mutex); | ||
1841 | list_add(&tmp_tfm->key_tfm_list, &key_tfm_list); | 1847 | list_add(&tmp_tfm->key_tfm_list, &key_tfm_list); |
1842 | mutex_unlock(&key_tfm_list_mutex); | ||
1843 | out: | 1848 | out: |
1844 | return rc; | 1849 | return rc; |
1845 | } | 1850 | } |
1846 | 1851 | ||
1852 | /** | ||
1853 | * ecryptfs_tfm_exists - Search for existing tfm for cipher_name. | ||
1854 | * @cipher_name: the name of the cipher to search for | ||
1855 | * @key_tfm: set to corresponding tfm if found | ||
1856 | * | ||
1857 | * Searches for cached key_tfm matching @cipher_name | ||
1858 | * Must be called with &key_tfm_list_mutex held | ||
1859 | * Returns 1 if found, with @key_tfm set | ||
1860 | * Returns 0 if not found, with @key_tfm set to NULL | ||
1861 | */ | ||
1862 | int ecryptfs_tfm_exists(char *cipher_name, struct ecryptfs_key_tfm **key_tfm) | ||
1863 | { | ||
1864 | struct ecryptfs_key_tfm *tmp_key_tfm; | ||
1865 | |||
1866 | BUG_ON(!mutex_is_locked(&key_tfm_list_mutex)); | ||
1867 | |||
1868 | list_for_each_entry(tmp_key_tfm, &key_tfm_list, key_tfm_list) { | ||
1869 | if (strcmp(tmp_key_tfm->cipher_name, cipher_name) == 0) { | ||
1870 | if (key_tfm) | ||
1871 | (*key_tfm) = tmp_key_tfm; | ||
1872 | return 1; | ||
1873 | } | ||
1874 | } | ||
1875 | if (key_tfm) | ||
1876 | (*key_tfm) = NULL; | ||
1877 | return 0; | ||
1878 | } | ||
1879 | |||
1880 | /** | ||
1881 | * ecryptfs_get_tfm_and_mutex_for_cipher_name | ||
1882 | * | ||
1883 | * @tfm: set to cached tfm found, or new tfm created | ||
1884 | * @tfm_mutex: set to mutex for cached tfm found, or new tfm created | ||
1885 | * @cipher_name: the name of the cipher to search for and/or add | ||
1886 | * | ||
1887 | * Sets pointers to @tfm & @tfm_mutex matching @cipher_name. | ||
1888 | * Searches for cached item first, and creates new if not found. | ||
1889 | * Returns 0 on success, non-zero if adding new cipher failed | ||
1890 | */ | ||
1847 | int ecryptfs_get_tfm_and_mutex_for_cipher_name(struct crypto_blkcipher **tfm, | 1891 | int ecryptfs_get_tfm_and_mutex_for_cipher_name(struct crypto_blkcipher **tfm, |
1848 | struct mutex **tfm_mutex, | 1892 | struct mutex **tfm_mutex, |
1849 | char *cipher_name) | 1893 | char *cipher_name) |
@@ -1853,22 +1897,17 @@ int ecryptfs_get_tfm_and_mutex_for_cipher_name(struct crypto_blkcipher **tfm, | |||
1853 | 1897 | ||
1854 | (*tfm) = NULL; | 1898 | (*tfm) = NULL; |
1855 | (*tfm_mutex) = NULL; | 1899 | (*tfm_mutex) = NULL; |
1900 | |||
1856 | mutex_lock(&key_tfm_list_mutex); | 1901 | mutex_lock(&key_tfm_list_mutex); |
1857 | list_for_each_entry(key_tfm, &key_tfm_list, key_tfm_list) { | 1902 | if (!ecryptfs_tfm_exists(cipher_name, &key_tfm)) { |
1858 | if (strcmp(key_tfm->cipher_name, cipher_name) == 0) { | 1903 | rc = ecryptfs_add_new_key_tfm(&key_tfm, cipher_name, 0); |
1859 | (*tfm) = key_tfm->key_tfm; | 1904 | if (rc) { |
1860 | (*tfm_mutex) = &key_tfm->key_tfm_mutex; | 1905 | printk(KERN_ERR "Error adding new key_tfm to list; " |
1861 | mutex_unlock(&key_tfm_list_mutex); | 1906 | "rc = [%d]\n", rc); |
1862 | goto out; | 1907 | goto out; |
1863 | } | 1908 | } |
1864 | } | 1909 | } |
1865 | mutex_unlock(&key_tfm_list_mutex); | 1910 | mutex_unlock(&key_tfm_list_mutex); |
1866 | rc = ecryptfs_add_new_key_tfm(&key_tfm, cipher_name, 0); | ||
1867 | if (rc) { | ||
1868 | printk(KERN_ERR "Error adding new key_tfm to list; rc = [%d]\n", | ||
1869 | rc); | ||
1870 | goto out; | ||
1871 | } | ||
1872 | (*tfm) = key_tfm->key_tfm; | 1911 | (*tfm) = key_tfm->key_tfm; |
1873 | (*tfm_mutex) = &key_tfm->key_tfm_mutex; | 1912 | (*tfm_mutex) = &key_tfm->key_tfm_mutex; |
1874 | out: | 1913 | out: |
diff --git a/fs/ecryptfs/ecryptfs_kernel.h b/fs/ecryptfs/ecryptfs_kernel.h index f44f71b7605a..5007f788da01 100644 --- a/fs/ecryptfs/ecryptfs_kernel.h +++ b/fs/ecryptfs/ecryptfs_kernel.h | |||
@@ -323,6 +323,8 @@ struct ecryptfs_key_tfm { | |||
323 | unsigned char cipher_name[ECRYPTFS_MAX_CIPHER_NAME_SIZE + 1]; | 323 | unsigned char cipher_name[ECRYPTFS_MAX_CIPHER_NAME_SIZE + 1]; |
324 | }; | 324 | }; |
325 | 325 | ||
326 | extern struct mutex key_tfm_list_mutex; | ||
327 | |||
326 | /** | 328 | /** |
327 | * This struct is to enable a mount-wide passphrase/salt combo. This | 329 | * This struct is to enable a mount-wide passphrase/salt combo. This |
328 | * is more or less a stopgap to provide similar functionality to other | 330 | * is more or less a stopgap to provide similar functionality to other |
@@ -617,6 +619,7 @@ ecryptfs_add_new_key_tfm(struct ecryptfs_key_tfm **key_tfm, char *cipher_name, | |||
617 | size_t key_size); | 619 | size_t key_size); |
618 | int ecryptfs_init_crypto(void); | 620 | int ecryptfs_init_crypto(void); |
619 | int ecryptfs_destroy_crypto(void); | 621 | int ecryptfs_destroy_crypto(void); |
622 | int ecryptfs_tfm_exists(char *cipher_name, struct ecryptfs_key_tfm **key_tfm); | ||
620 | int ecryptfs_get_tfm_and_mutex_for_cipher_name(struct crypto_blkcipher **tfm, | 623 | int ecryptfs_get_tfm_and_mutex_for_cipher_name(struct crypto_blkcipher **tfm, |
621 | struct mutex **tfm_mutex, | 624 | struct mutex **tfm_mutex, |
622 | char *cipher_name); | 625 | char *cipher_name); |
diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c index dc620fc16595..778c420e4cac 100644 --- a/fs/ecryptfs/main.c +++ b/fs/ecryptfs/main.c | |||
@@ -410,9 +410,13 @@ static int ecryptfs_parse_options(struct super_block *sb, char *options) | |||
410 | if (!cipher_key_bytes_set) { | 410 | if (!cipher_key_bytes_set) { |
411 | mount_crypt_stat->global_default_cipher_key_size = 0; | 411 | mount_crypt_stat->global_default_cipher_key_size = 0; |
412 | } | 412 | } |
413 | rc = ecryptfs_add_new_key_tfm( | 413 | mutex_lock(&key_tfm_list_mutex); |
414 | NULL, mount_crypt_stat->global_default_cipher_name, | 414 | if (!ecryptfs_tfm_exists(mount_crypt_stat->global_default_cipher_name, |
415 | mount_crypt_stat->global_default_cipher_key_size); | 415 | NULL)) |
416 | rc = ecryptfs_add_new_key_tfm( | ||
417 | NULL, mount_crypt_stat->global_default_cipher_name, | ||
418 | mount_crypt_stat->global_default_cipher_key_size); | ||
419 | mutex_unlock(&key_tfm_list_mutex); | ||
416 | if (rc) { | 420 | if (rc) { |
417 | printk(KERN_ERR "Error attempting to initialize cipher with " | 421 | printk(KERN_ERR "Error attempting to initialize cipher with " |
418 | "name = [%s] and key size = [%td]; rc = [%d]\n", | 422 | "name = [%s] and key size = [%td]; rc = [%d]\n", |