+ /* Volatile file name may look like:
+ * <parent>/LUSTRE_VOLATILE_HDR:<mdt_index>:<random>:fd=<fd>
+ * where fd is opened descriptor of reference file.
+ */
+ if (unlikely(filename_is_volatile(dentry->d_name.name,
+ dentry->d_name.len, NULL))) {
+ int ctx_size = LLCRYPT_ENC_CTX_SIZE;
+ struct lustre_sb_info *lsi;
+ struct file *ref_file;
+ struct inode *ref_inode;
+ char *p, *q, *fd_str;
+ void *ctx;
+ int fd;
+
+ p = strnstr(dentry->d_name.name, ":fd=",
+ dentry->d_name.len);
+ if (!p || strlen(p + 4) == 0)
+ GOTO(out, retval = ERR_PTR(-EINVAL));
+
+ q = strchrnul(p + 4, ':');
+ fd_str = kstrndup(p + 4, q - p - 4, GFP_NOFS);
+ if (!fd_str)
+ GOTO(out, retval = ERR_PTR(-ENOMEM));
+ rc = kstrtouint(fd_str, 10, &fd);
+ kfree(fd_str);
+ if (rc)
+ GOTO(inherit, rc = -EINVAL);
+
+ ref_file = fget(fd);
+ if (!ref_file)
+ GOTO(inherit, rc = -EINVAL);
+
+ ref_inode = file_inode(ref_file);
+ if (!ref_inode) {
+ fput(ref_file);
+ GOTO(inherit, rc = -EINVAL);
+ }
+
+ lsi = s2lsi(ref_inode->i_sb);
+
+getctx:
+ OBD_ALLOC(ctx, ctx_size);
+ if (!ctx)
+ GOTO(out, retval = ERR_PTR(-ENOMEM));
+
+#ifdef CONFIG_LL_ENCRYPTION
+ rc = lsi->lsi_cop->get_context(ref_inode,
+ ctx, ctx_size);
+#else
+ rc = -ENODATA;
+#endif
+ if (rc == -ERANGE) {
+ OBD_FREE(ctx, ctx_size);
+ ctx_size *= 2;
+ goto getctx;
+ }
+ fput(ref_file);
+ if (rc < 0) {
+ OBD_FREE(ctx, ctx_size);
+ GOTO(inherit, rc);
+ }
+
+ op_data->op_file_encctx_size = rc;
+ if (rc == ctx_size) {
+ op_data->op_file_encctx = ctx;
+ } else {
+ OBD_ALLOC(op_data->op_file_encctx,
+ op_data->op_file_encctx_size);
+ if (!op_data->op_file_encctx) {
+ OBD_FREE(ctx, ctx_size);
+ GOTO(out, retval = ERR_PTR(-ENOMEM));
+ }
+ memcpy(op_data->op_file_encctx, ctx,
+ op_data->op_file_encctx_size);
+ OBD_FREE(ctx, ctx_size);
+ }
+
+ } else {
+inherit:
+ rc = llcrypt_inherit_context(parent, NULL, op_data,
+ false);
+ if (rc)
+ GOTO(out, retval = ERR_PTR(rc));
+ }