diff options
Diffstat (limited to 'fs/crypto/crypto.c')
| -rw-r--r-- | fs/crypto/crypto.c | 55 | 
1 files changed, 43 insertions, 12 deletions
diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c index ce654526c0fb..0f46cf550907 100644 --- a/fs/crypto/crypto.c +++ b/fs/crypto/crypto.c @@ -45,12 +45,18 @@ static mempool_t *fscrypt_bounce_page_pool = NULL;  static LIST_HEAD(fscrypt_free_ctxs);  static DEFINE_SPINLOCK(fscrypt_ctx_lock); -struct workqueue_struct *fscrypt_read_workqueue; +static struct workqueue_struct *fscrypt_read_workqueue;  static DEFINE_MUTEX(fscrypt_init_mutex);  static struct kmem_cache *fscrypt_ctx_cachep;  struct kmem_cache *fscrypt_info_cachep; +void fscrypt_enqueue_decrypt_work(struct work_struct *work) +{ +	queue_work(fscrypt_read_workqueue, work); +} +EXPORT_SYMBOL(fscrypt_enqueue_decrypt_work); +  /**   * fscrypt_release_ctx() - Releases an encryption context   * @ctx: The encryption context to release. @@ -156,12 +162,8 @@ int fscrypt_do_page_crypto(const struct inode *inode, fscrypt_direction_t rw,  	}  	req = skcipher_request_alloc(tfm, gfp_flags); -	if (!req) { -		printk_ratelimited(KERN_ERR -				"%s: crypto_request_alloc() failed\n", -				__func__); +	if (!req)  		return -ENOMEM; -	}  	skcipher_request_set_callback(  		req, CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP, @@ -178,9 +180,10 @@ int fscrypt_do_page_crypto(const struct inode *inode, fscrypt_direction_t rw,  		res = crypto_wait_req(crypto_skcipher_encrypt(req), &wait);  	skcipher_request_free(req);  	if (res) { -		printk_ratelimited(KERN_ERR -			"%s: crypto_skcipher_encrypt() returned %d\n", -			__func__, res); +		fscrypt_err(inode->i_sb, +			    "%scryption failed for inode %lu, block %llu: %d", +			    (rw == FS_DECRYPT ? "de" : "en"), +			    inode->i_ino, lblk_num, res);  		return res;  	}  	return 0; @@ -326,7 +329,6 @@ static int fscrypt_d_revalidate(struct dentry *dentry, unsigned int flags)  		return 0;  	} -	/* this should eventually be an flag in d_flags */  	spin_lock(&dentry->d_lock);  	cached_with_key = dentry->d_flags & DCACHE_ENCRYPTED_WITH_KEY;  	spin_unlock(&dentry->d_lock); @@ -353,7 +355,6 @@ static int fscrypt_d_revalidate(struct dentry *dentry, unsigned int flags)  const struct dentry_operations fscrypt_d_ops = {  	.d_revalidate = fscrypt_d_revalidate,  }; -EXPORT_SYMBOL(fscrypt_d_ops);  void fscrypt_restore_control_page(struct page *page)  { @@ -422,13 +423,43 @@ fail:  	return res;  } +void fscrypt_msg(struct super_block *sb, const char *level, +		 const char *fmt, ...) +{ +	static DEFINE_RATELIMIT_STATE(rs, DEFAULT_RATELIMIT_INTERVAL, +				      DEFAULT_RATELIMIT_BURST); +	struct va_format vaf; +	va_list args; + +	if (!__ratelimit(&rs)) +		return; + +	va_start(args, fmt); +	vaf.fmt = fmt; +	vaf.va = &args; +	if (sb) +		printk("%sfscrypt (%s): %pV\n", level, sb->s_id, &vaf); +	else +		printk("%sfscrypt: %pV\n", level, &vaf); +	va_end(args); +} +  /**   * fscrypt_init() - Set up for fs encryption.   */  static int __init fscrypt_init(void)  { +	/* +	 * Use an unbound workqueue to allow bios to be decrypted in parallel +	 * even when they happen to complete on the same CPU.  This sacrifices +	 * locality, but it's worthwhile since decryption is CPU-intensive. +	 * +	 * Also use a high-priority workqueue to prioritize decryption work, +	 * which blocks reads from completing, over regular application tasks. +	 */  	fscrypt_read_workqueue = alloc_workqueue("fscrypt_read_queue", -							WQ_HIGHPRI, 0); +						 WQ_UNBOUND | WQ_HIGHPRI, +						 num_online_cpus());  	if (!fscrypt_read_workqueue)  		goto fail;  |