#include <linux/random.h>
#include <linux/statfs.h>
#include <linux/time.h>
+#include <linux/file.h>
#include <linux/types.h>
#include <libcfs/linux/linux-uuid.h>
#include <linux/version.h>
unsigned long lru_page_max;
struct sysinfo si;
int rc;
- int i;
ENTRY;
#endif
set_bit(LL_SBI_LAZYSTATFS, sbi->ll_flags);
- for (i = 0; i <= LL_PROCESS_HIST_MAX; i++) {
- spin_lock_init(&sbi->ll_rw_extents_info.pp_extents[i].
- pp_r_hist.oh_lock);
- spin_lock_init(&sbi->ll_rw_extents_info.pp_extents[i].
- pp_w_hist.oh_lock);
- }
-
/* metadata statahead is enabled by default */
sbi->ll_sa_running_max = LL_SA_RUNNING_DEF;
sbi->ll_sa_max = LL_SA_RPC_DEF;
set_bit(LL_SBI_TINY_WRITE, sbi->ll_flags);
set_bit(LL_SBI_PARALLEL_DIO, sbi->ll_flags);
ll_sbi_set_encrypt(sbi, true);
+ ll_sbi_set_name_encrypt(sbi, true);
/* root squash */
sbi->ll_squash.rsi_uid = 0;
sizeof(struct ll_foreign_symlink_upcall_item));
sbi->ll_foreign_symlink_upcall_items = NULL;
}
+ ll_free_rw_stats_info(sbi);
pcc_super_fini(&sbi->ll_pcc_super);
OBD_FREE(sbi, sizeof(*sbi));
}
u64 valid;
int size, err, checksum;
bool api32;
+ void *encctx;
+ int encctxlen;
ENTRY;
sbi->ll_md_obd = class_name2obd(md);
data->ocd_connect_flags &= ~OBD_CONNECT_PINGLESS;
obd_connect_set_secctx(data);
- if (ll_sbi_has_encrypt(sbi))
+ if (ll_sbi_has_encrypt(sbi)) {
+ obd_connect_set_name_enc(data);
obd_connect_set_enc(data);
+ }
#if defined(CONFIG_SECURITY)
data->ocd_connect_flags2 |= OBD_CONNECT2_SELINUX_POLICY;
sb->s_blocksize_bits = log2(osfs->os_bsize);
sb->s_magic = LL_SUPER_MAGIC;
sb->s_maxbytes = MAX_LFS_FILESIZE;
+ sbi->ll_inode_cache_enabled = 1;
sbi->ll_namelen = osfs->os_namelen;
sbi->ll_mnt.mnt = current->fs->root.mnt;
+ sbi->ll_mnt_ns = current->nsproxy->mnt_ns;
if (test_bit(LL_SBI_USER_XATTR, sbi->ll_flags) &&
!(data->ocd_connect_flags & OBD_CONNECT_XATTR)) {
set_bit(LL_SBI_FILE_SECCTX, sbi->ll_flags);
if (ll_sbi_has_encrypt(sbi) && !obd_connect_has_enc(data)) {
- if (ll_sbi_has_test_dummy_encryption(sbi))
+ if (ll_sb_has_test_dummy_encryption(sb))
LCONSOLE_WARN("%s: server %s does not support encryption feature, encryption deactivated.\n",
sbi->ll_fsname,
sbi->ll_md_exp->exp_obd->obd_name);
ll_sbi_set_encrypt(sbi, false);
}
+ if (ll_sbi_has_name_encrypt(sbi) && !obd_connect_has_name_enc(data)) {
+ struct lustre_sb_info *lsi = s2lsi(sb);
+
+ if (ll_sb_has_test_dummy_encryption(sb))
+ LCONSOLE_WARN("%s: server %s does not support name encryption, not using it.\n",
+ sbi->ll_fsname,
+ sbi->ll_md_exp->exp_obd->obd_name);
+ lsi->lsi_flags &= ~LSI_FILENAME_ENC;
+ ll_sbi_set_name_encrypt(sbi, false);
+ }
+
if (data->ocd_ibits_known & MDS_INODELOCK_XATTR) {
if (!(data->ocd_connect_flags & OBD_CONNECT_MAX_EASIZE)) {
LCONSOLE_INFO("%s: disabling xattr cache due to "
if (ll_sbi_has_encrypt(sbi) &&
!obd_connect_has_enc(&sbi->ll_dt_obd->u.lov.lov_ocd)) {
- if (ll_sbi_has_test_dummy_encryption(sbi))
+ if (ll_sb_has_test_dummy_encryption(sb))
LCONSOLE_WARN("%s: server %s does not support encryption feature, encryption deactivated.\n",
sbi->ll_fsname, dt);
ll_sbi_set_encrypt(sbi, false);
- } else if (ll_sbi_has_test_dummy_encryption(sbi)) {
+ } else if (ll_sb_has_test_dummy_encryption(sb)) {
LCONSOLE_WARN("Test dummy encryption mode enabled\n");
}
/* make root inode
* XXX: move this to after cbd setup? */
- valid = OBD_MD_FLGETATTR | OBD_MD_FLBLOCKS | OBD_MD_FLMODEASIZE;
+ valid = OBD_MD_FLGETATTR | OBD_MD_FLBLOCKS | OBD_MD_FLMODEASIZE |
+ OBD_MD_ENCCTX;
if (test_bit(LL_SBI_ACL, sbi->ll_flags))
valid |= OBD_MD_FLACL;
err = md_getattr(sbi->ll_md_exp, op_data, &request);
+ /* We need enc ctx info, so reset it in op_data to
+ * prevent it from being freed.
+ */
+ encctx = op_data->op_file_encctx;
+ encctxlen = op_data->op_file_encctx_size;
+ op_data->op_file_encctx = NULL;
+ op_data->op_file_encctx_size = 0;
OBD_FREE_PTR(op_data);
if (err) {
CERROR("%s: md_getattr failed for root: rc = %d\n",
api32 = test_bit(LL_SBI_32BIT_API, sbi->ll_flags);
root = ll_iget(sb, cl_fid_build_ino(&sbi->ll_root_fid, api32), &lmd);
md_free_lustre_md(sbi->ll_md_exp, &lmd);
- ptlrpc_req_finished(request);
if (IS_ERR(root)) {
lmd_clear_acl(&lmd);
root = NULL;
CERROR("%s: bad ll_iget() for root: rc = %d\n",
sbi->ll_fsname, err);
+ ptlrpc_req_finished(request);
GOTO(out_root, err);
}
+ if (encctxlen) {
+ CDEBUG(D_SEC,
+ "server returned encryption ctx for root inode "DFID"\n",
+ PFID(&sbi->ll_root_fid));
+ err = ll_set_encflags(root, encctx, encctxlen, true);
+ if (err)
+ CWARN("%s: cannot set enc ctx for "DFID": rc = %d\n",
+ sbi->ll_fsname,
+ PFID(&sbi->ll_root_fid), err);
+ }
+ ptlrpc_req_finished(request);
+
checksum = test_bit(LL_SBI_CHECKSUM, sbi->ll_flags);
if (sbi->ll_checksum_set) {
err = obd_set_info_async(NULL, sbi->ll_dt_exp,
{LL_SBI_VERBOSE, "verbose"},
{LL_SBI_VERBOSE, "noverbose"},
{LL_SBI_ALWAYS_PING, "always_ping"},
+ {LL_SBI_TEST_DUMMY_ENCRYPTION, "test_dummy_encryption=%s"},
{LL_SBI_TEST_DUMMY_ENCRYPTION, "test_dummy_encryption"},
{LL_SBI_ENCRYPT, "encrypt"},
{LL_SBI_ENCRYPT, "noencrypt"},
{LL_SBI_TINY_WRITE, "tiny_write"},
{LL_SBI_FILE_HEAT, "file_heat"},
{LL_SBI_PARALLEL_DIO, "parallel_dio"},
+ {LL_SBI_ENCRYPT_NAME, "name_encrypt"},
};
int ll_sbi_flags_seq_show(struct seq_file *m, void *v)
{
struct ll_sb_info *sbi = ll_s2sbi(sb);
char *s2, *s1, *opts;
+ int err = 0;
ENTRY;
if (!options)
case LL_SBI_CHECKSUM:
sbi->ll_checksum_set = 1;
- /* fall through */
+ fallthrough;
case LL_SBI_USER_XATTR:
case LL_SBI_USER_FID2PATH:
case LL_SBI_LRU_RESIZE:
break;
case LL_SBI_TEST_DUMMY_ENCRYPTION: {
#ifdef HAVE_LUSTRE_CRYPTO
+#ifdef HAVE_FSCRYPT_DUMMY_CONTEXT_ENABLED
set_bit(token, sbi->ll_flags);
#else
+ struct lustre_sb_info *lsi = s2lsi(sb);
+
+ err = llcrypt_set_test_dummy_encryption(sb, &args[0],
+ &lsi->lsi_dummy_enc_ctx);
+ if (!err)
+ break;
+
+ if (err == -EEXIST)
+ LCONSOLE_WARN(
+ "Can't change test_dummy_encryption");
+ else if (err == -EINVAL)
+ LCONSOLE_WARN(
+ "Value of option \"%s\" unrecognized",
+ options);
+ else
+ LCONSOLE_WARN(
+ "Error processing option \"%s\" [%d]",
+ options, err);
+ err = -1;
+#endif
+#else
LCONSOLE_WARN("Test dummy encryption mount option ignored: encryption not supported\n");
#endif
break;
LCONSOLE_ERROR_MSG(0x152,
"invalid %s option\n", s1);
}
- /* fall through */
+ fallthrough;
default:
break;
}
}
kfree(opts);
- RETURN(0);
+ RETURN(err);
}
void ll_lli_init(struct ll_inode_info *lli)
#define MAX_STRING_SIZE 128
#ifndef HAVE_SUPER_SETUP_BDI_NAME
-
-#define LSI_BDI_INITIALIZED 0x00400000
-
#ifndef HAVE_BDI_CAP_MAP_COPY
# define BDI_CAP_MAP_COPY 0
#endif
if (err)
GOTO(out_free_cfg, err);
+ if (ll_sb_has_test_dummy_encryption(sb))
+ /* enable filename encryption by default for dummy enc mode */
+ lsi->lsi_flags |= LSI_FILENAME_ENC;
+ else
+ /* filename encryption is disabled by default */
+ lsi->lsi_flags &= ~LSI_FILENAME_ENC;
+
/* kernel >= 2.6.38 store dentry operations in sb->s_d_op. */
sb->s_d_op = &ll_d_ops;
if (err)
GOTO(out_free_cfg, err);
+ /* disable kernel readahead */
+ sb->s_bdi->ra_pages = 0;
+
/* Call ll_debugfs_register_super() before lustre_process_log()
* so that "llite.*.*" params can be processed correctly.
*/
client_common_put_super(sb);
}
+ /* imitate failed cleanup */
+ if (OBD_FAIL_CHECK(OBD_FAIL_OBD_CLEANUP))
+ goto skip_cleanup;
+
next = 0;
while ((obd = class_devices_in_group(&sbi->ll_sb_uuid, &next)))
class_manual_cleanup(obd);
+skip_cleanup:
if (test_bit(LL_SBI_VERBOSE, sbi->ll_flags))
LCONSOLE_WARN("Unmounted %s\n", profilenm ? profilenm : "");
}
#endif
+ llcrypt_free_dummy_context(&lsi->lsi_dummy_enc_ctx);
ll_free_sbi(sb);
lsi->lsi_llsbi = NULL;
out_no_sbi:
lmv_free_memmd(lli->lli_default_lsm_md);
lli->lli_default_lsm_md = NULL;
}
+ lli->lli_inherit_depth = 0;
up_write(&lli->lli_lsm_sem);
}
RETURN_EXIT;
}
rc = ll_init_lsm_md(inode, md);
- up_write(&lli->lli_lsm_sem);
-
- if (rc)
+ if (rc) {
+ up_write(&lli->lli_lsm_sem);
RETURN(rc);
+ }
+
+ /* md_merge_attr() may take long, since lsm is already set, switch to
+ * read lock.
+ */
+ downgrade_write(&lli->lli_lsm_sem);
/* set md->lmv to NULL, so the following free lustre_md will not free
* this lsm.
*/
md->lmv = NULL;
- /* md_merge_attr() may take long, since lsm is already set, switch to
- * read lock.
- */
- down_read(&lli->lli_lsm_sem);
-
if (!lmv_dir_striped(lli->lli_lsm_md))
GOTO(unlock, rc = 0);
!S_ISDIR(inode->i_mode)) {
ia_valid = op_data->op_attr.ia_valid;
op_data->op_attr.ia_valid &= ~TIMES_SET_FLAGS;
- rc = simple_setattr(dentry, &op_data->op_attr);
+ rc = simple_setattr(&init_user_ns, dentry,
+ &op_data->op_attr);
op_data->op_attr.ia_valid = ia_valid;
}
} else if (rc != -EPERM && rc != -EACCES && rc != -ETXTBSY) {
op_data->op_attr.ia_valid &= ~(TIMES_SET_FLAGS | ATTR_SIZE);
if (S_ISREG(inode->i_mode))
inode_lock(inode);
- rc = simple_setattr(dentry, &op_data->op_attr);
+ rc = simple_setattr(&init_user_ns, dentry, &op_data->op_attr);
if (S_ISREG(inode->i_mode))
inode_unlock(inode);
op_data->op_attr.ia_valid = ia_valid;
struct cl_2queue *queue = NULL;
struct cl_sync_io *anchor = NULL;
bool holdinglock = false;
- bool lockedbymyself = true;
int rc;
ENTRY;
if (!PageUptodate(vmpage) && !PageDirty(vmpage) &&
!PageWriteback(vmpage)) {
/* read page */
- /* set PagePrivate2 to detect special case of empty page
- * in osc_brw_fini_request()
+ /* Set PagePrivate2 to detect special case of empty page
+ * in osc_brw_fini_request().
+ * It is also used to tell ll_io_read_page() that we do not
+ * want the vmpage to be unlocked.
*/
SetPagePrivate2(vmpage);
rc = ll_io_read_page(env, io, clpage, NULL);
- if (!PagePrivate2(vmpage))
+ if (!PagePrivate2(vmpage)) {
/* PagePrivate2 was cleared in osc_brw_fini_request()
* meaning we read an empty page. In this case, in order
* to avoid allocating unnecessary block in truncated
* file, we must not zero and write as below. Subsequent
* server-side truncate will handle things correctly.
*/
+ cl_page_unassume(env, io, clpage);
GOTO(clpfini, rc = 0);
+ }
ClearPagePrivate2(vmpage);
if (rc)
GOTO(clpfini, rc);
- lockedbymyself = trylock_page(vmpage);
- cl_page_assume(env, io, clpage);
}
- /* zero range in page */
+ /* Thanks to PagePrivate2 flag, ll_io_read_page() did not unlock
+ * the vmpage, so we are good to proceed and zero range in page.
+ */
zero_user(vmpage, offset, len);
if (holdinglock && clpage) {
anchor = &vvp_env_info(env)->vti_anchor;
cl_sync_io_init(anchor, 1);
clpage->cp_sync_io = anchor;
- cl_2queue_add(queue, clpage, true);
+ cl_page_list_add(&queue->c2_qin, clpage, true);
rc = cl_io_submit_rw(env, io, CRT_WRITE, queue);
if (rc)
GOTO(queuefini1, rc);
queuefini2:
cl_2queue_discard(env, io, queue);
queuefini1:
- cl_2queue_disown(env, io, queue);
+ cl_2queue_disown(env, queue);
cl_2queue_fini(env, queue);
}
if (clpage)
cl_page_put(env, clpage);
pagefini:
- if (lockedbymyself) {
- unlock_page(vmpage);
- put_page(vmpage);
- }
+ unlock_page(vmpage);
+ put_page(vmpage);
rellock:
if (holdinglock)
cl_lock_release(env, lock);
RETURN(rc);
}
+/**
+ * Get reference file from volatile file name.
+ * Volatile file name may look like:
+ * <parent>/LUSTRE_VOLATILE_HDR:<mdt_index>:<random>:fd=<fd>
+ * where fd is opened descriptor of reference file.
+ *
+ * \param[in] volatile_name volatile file name
+ * \param[in] volatile_len volatile file name length
+ * \param[out] ref_file pointer to struct file of reference file
+ *
+ * \retval 0 on success
+ * \retval negative errno on failure
+ */
+int volatile_ref_file(const char *volatile_name, int volatile_len,
+ struct file **ref_file)
+{
+ char *p, *q, *fd_str;
+ int fd, rc;
+
+ p = strnstr(volatile_name, ":fd=", volatile_len);
+ if (!p || strlen(p + 4) == 0)
+ return -EINVAL;
+
+ q = strchrnul(p + 4, ':');
+ fd_str = kstrndup(p + 4, q - p - 4, GFP_NOFS);
+ if (!fd_str)
+ return -ENOMEM;
+ rc = kstrtouint(fd_str, 10, &fd);
+ kfree(fd_str);
+ if (rc)
+ return -EINVAL;
+
+ *ref_file = fget(fd);
+ if (!(*ref_file))
+ return -EINVAL;
+ return 0;
+}
+
/* If this inode has objects allocated to it (lsm != NULL), then the OST
* object(s) determine the file size and mtime. Otherwise, the MDS will
* keep these values until such a time that objects are allocated for it.
if (rc)
GOTO(out, rc);
}
+ /* If encrypted volatile file without the key,
+ * we need to fetch size from reference file,
+ * and set it on OST objects. This happens when
+ * migrating or extending an encrypted file
+ * without the key.
+ */
+ if (filename_is_volatile(dentry->d_name.name,
+ dentry->d_name.len,
+ NULL) &&
+ llcrypt_require_key(inode) == -ENOKEY) {
+ struct file *ref_file;
+ struct inode *ref_inode;
+ struct ll_inode_info *ref_lli;
+ struct cl_object *ref_obj;
+ struct cl_attr ref_attr = { 0 };
+ struct lu_env *env;
+ __u16 refcheck;
+
+ rc = volatile_ref_file(
+ dentry->d_name.name,
+ dentry->d_name.len,
+ &ref_file);
+ if (rc)
+ GOTO(out, rc);
+
+ ref_inode = file_inode(ref_file);
+ if (!ref_inode) {
+ fput(ref_file);
+ GOTO(out, rc = -EINVAL);
+ }
+
+ env = cl_env_get(&refcheck);
+ if (IS_ERR(env))
+ GOTO(out, rc = PTR_ERR(env));
+
+ ref_lli = ll_i2info(ref_inode);
+ ref_obj = ref_lli->lli_clob;
+ cl_object_attr_lock(ref_obj);
+ rc = cl_object_attr_get(env, ref_obj,
+ &ref_attr);
+ cl_object_attr_unlock(ref_obj);
+ cl_env_put(env, &refcheck);
+ fput(ref_file);
+ if (rc)
+ GOTO(out, rc);
+
+ attr->ia_valid |= ATTR_SIZE;
+ attr->ia_size = ref_attr.cat_size;
+ }
}
rc = cl_setattr_ost(lli->lli_clob, attr, xvalid, flags);
}
LPROC_LL_TRUNC : LPROC_LL_SETATTR,
ktime_us_delta(ktime_get(), kstart));
- return rc;
+ RETURN(rc);
}
-int ll_setattr(struct dentry *de, struct iattr *attr)
+int ll_setattr(struct user_namespace *mnt_userns, struct dentry *de,
+ struct iattr *attr)
{
int mode = de->d_inode->i_mode;
enum op_xvalid xvalid = 0;
LASSERT(fid_seq(&lli->lli_fid) != 0);
- lli->lli_attr_valid = body->mbo_valid;
+ /* In case of encrypted file without the key, please do not lose
+ * clear text size stored into lli_lazysize in ll_merge_attr(),
+ * we will need it in ll_prepare_close().
+ */
+ if (lli->lli_attr_valid & OBD_MD_FLLAZYSIZE && lli->lli_lazysize &&
+ llcrypt_require_key(inode) == -ENOKEY)
+ lli->lli_attr_valid = body->mbo_valid | OBD_MD_FLLAZYSIZE;
+ else
+ lli->lli_attr_valid = body->mbo_valid;
if (body->mbo_valid & OBD_MD_FLSIZE) {
i_size_write(inode, body->mbo_size);
return 0;
}
+/* child default LMV is inherited from parent */
+static inline bool ll_default_lmv_inherited(struct lmv_stripe_md *pdmv,
+ struct lmv_stripe_md *cdmv)
+{
+ if (!pdmv || !cdmv)
+ return false;
+
+ if (pdmv->lsm_md_magic != cdmv->lsm_md_magic ||
+ pdmv->lsm_md_stripe_count != cdmv->lsm_md_stripe_count ||
+ pdmv->lsm_md_master_mdt_index != cdmv->lsm_md_master_mdt_index ||
+ pdmv->lsm_md_hash_type != cdmv->lsm_md_hash_type)
+ return false;
+
+ if (cdmv->lsm_md_max_inherit !=
+ lmv_inherit_next(pdmv->lsm_md_max_inherit))
+ return false;
+
+ if (cdmv->lsm_md_max_inherit_rr !=
+ lmv_inherit_rr_next(pdmv->lsm_md_max_inherit_rr))
+ return false;
+
+ return true;
+}
+
/* update directory depth to ROOT, called after LOOKUP lock is fetched. */
void ll_update_dir_depth(struct inode *dir, struct inode *inode)
{
+ struct ll_inode_info *plli;
struct ll_inode_info *lli;
if (!S_ISDIR(inode->i_mode))
if (inode == dir)
return;
+ plli = ll_i2info(dir);
lli = ll_i2info(inode);
- lli->lli_depth = ll_i2info(dir)->lli_depth + 1;
- CDEBUG(D_INODE, DFID" depth %hu\n", PFID(&lli->lli_fid), lli->lli_depth);
+ lli->lli_dir_depth = plli->lli_dir_depth + 1;
+ if (plli->lli_default_lsm_md && lli->lli_default_lsm_md) {
+ down_read(&plli->lli_lsm_sem);
+ down_read(&lli->lli_lsm_sem);
+ if (ll_default_lmv_inherited(plli->lli_default_lsm_md,
+ lli->lli_default_lsm_md))
+ lli->lli_inherit_depth =
+ plli->lli_inherit_depth + 1;
+ else
+ lli->lli_inherit_depth = 0;
+ up_read(&lli->lli_lsm_sem);
+ up_read(&plli->lli_lsm_sem);
+ } else {
+ lli->lli_inherit_depth = 0;
+ }
+
+ CDEBUG(D_INODE, DFID" depth %hu default LMV depth %hu\n",
+ PFID(&lli->lli_fid), lli->lli_dir_depth, lli->lli_inherit_depth);
}
void ll_truncate_inode_pages_final(struct inode *inode)
EXIT;
}
+/* set filesystem-wide default LMV for subdir mount if it's enabled on ROOT. */
+static int ll_fileset_default_lmv_fixup(struct inode *inode,
+ struct lustre_md *md)
+{
+ struct ll_sb_info *sbi = ll_i2sbi(inode);
+ struct ptlrpc_request *req = NULL;
+ union lmv_mds_md *lmm = NULL;
+ int size = 0;
+ int rc;
+
+ LASSERT(is_root_inode(inode));
+ LASSERT(!fid_is_root(&sbi->ll_root_fid));
+ LASSERT(!md->default_lmv);
+
+ rc = ll_dir_get_default_layout(inode, (void **)&lmm, &size, &req,
+ OBD_MD_DEFAULT_MEA,
+ GET_DEFAULT_LAYOUT_ROOT);
+ if (rc && rc != -ENODATA)
+ GOTO(out, rc);
+
+ rc = 0;
+ if (lmm && size) {
+ rc = md_unpackmd(sbi->ll_md_exp, &md->default_lmv, lmm, size);
+ if (rc < 0)
+ GOTO(out, rc);
+
+ rc = 0;
+ }
+ EXIT;
+out:
+ if (req)
+ ptlrpc_req_finished(req);
+ return rc;
+}
+
int ll_prep_inode(struct inode **inode, struct req_capsule *pill,
struct super_block *sb, struct lookup_intent *it)
{
* ll_update_lsm_md() may change md.
*/
if (it && (it->it_op & (IT_LOOKUP | IT_GETATTR)) &&
- S_ISDIR(md.body->mbo_mode) && !md.default_lmv)
- default_lmv_deleted = true;
+ S_ISDIR(md.body->mbo_mode) && !md.default_lmv) {
+ if (unlikely(*inode && is_root_inode(*inode) &&
+ !fid_is_root(&sbi->ll_root_fid))) {
+ rc = ll_fileset_default_lmv_fixup(*inode, &md);
+ if (rc)
+ GOTO(out, rc);
+ }
+
+ if (!md.default_lmv)
+ default_lmv_deleted = true;
+ }
if (*inode) {
rc = ll_update_inode(*inode, &md);
if (namelen != 0)
return ERR_PTR(-EINVAL);
} else {
- if (namelen > ll_i2sbi(i1)->ll_namelen)
+ if ((!IS_ENCRYPTED(i1) ||
+ (opc != LUSTRE_OPC_LOOKUP && opc != LUSTRE_OPC_CREATE)) &&
+ namelen > ll_i2sbi(i1)->ll_namelen)
return ERR_PTR(-ENAMETOOLONG);
/* "/" is not valid name, but it's allowed */
return ERR_PTR(-ENOMEM);
ll_i2gids(op_data->op_suppgids, i1, i2);
- op_data->op_fid1 = *ll_inode2fid(i1);
+ /* If the client is using a subdir mount and looks at what it sees as
+ * /.fscrypt, interpret it as the .fscrypt dir at the root of the fs.
+ */
+ if (unlikely(i1->i_sb && i1->i_sb->s_root && is_root_inode(i1) &&
+ !fid_is_root(ll_inode2fid(i1)) &&
+ name && namelen == strlen(dot_fscrypt_name) &&
+ strncmp(name, dot_fscrypt_name, namelen) == 0))
+ lu_root_fid(&op_data->op_fid1);
+ else
+ op_data->op_fid1 = *ll_inode2fid(i1);
if (S_ISDIR(i1->i_mode)) {
down_read_non_owner(&ll_i2info(i1)->lli_lsm_sem);
if (ll_need_32bit_api(ll_i2sbi(i1)))
op_data->op_cli_flags |= CLI_API32;
- if (opc == LUSTRE_OPC_LOOKUP || opc == LUSTRE_OPC_CREATE) {
+ if ((i2 && is_root_inode(i2)) ||
+ opc == LUSTRE_OPC_LOOKUP || opc == LUSTRE_OPC_CREATE) {
/* In case of lookup, ll_setup_filename() has already been
* called in ll_lookup_it(), so just take provided name.
+ * Also take provided name if we are dealing with root inode.
*/
fname.disk_name.name = (unsigned char *)name;
fname.disk_name.len = namelen;
op_data->op_bias = MDS_FID_OP;
}
if (fname.disk_name.name &&
- fname.disk_name.name != (unsigned char *)name)
+ fname.disk_name.name != (unsigned char *)name) {
/* op_data->op_name must be freed after use */
op_data->op_flags |= MF_OPNAME_KMALLOCED;
+ }
}
- /* In fact LUSTRE_OPC_LOOKUP, LUSTRE_OPC_OPEN, LUSTRE_OPC_MIGR
+ /* In fact LUSTRE_OPC_LOOKUP, LUSTRE_OPC_OPEN
* are LUSTRE_OPC_ANY
*/
- if (opc == LUSTRE_OPC_LOOKUP || opc == LUSTRE_OPC_OPEN ||
- opc == LUSTRE_OPC_MIGR)
+ if (opc == LUSTRE_OPC_LOOKUP || opc == LUSTRE_OPC_OPEN)
op_data->op_code = LUSTRE_OPC_ANY;
else
op_data->op_code = opc;
}
}
+ llcrypt_show_test_dummy_encryption(seq, ',', dentry->d_sb);
+
RETURN(0);
}
RETURN(0);
}
+struct dname_buf {
+ struct work_struct db_work;
+ struct dentry *db_dentry;
+ /* Let's hope the path is not too long, 32 bytes for the work struct
+ * on my kernel
+ */
+ char buf[PAGE_SIZE - sizeof(struct work_struct) - sizeof(void *)];
+};
+
+static void ll_dput_later(struct work_struct *work)
+{
+ struct dname_buf *db = container_of(work, struct dname_buf, db_work);
+
+ dput(db->db_dentry);
+ free_page((unsigned long)db);
+}
+
static char* ll_d_path(struct dentry *dentry, char *buf, int bufsize)
{
char *path = NULL;
return path;
}
-void ll_dirty_page_discard_warn(struct page *page, int ioret)
+void ll_dirty_page_discard_warn(struct inode *inode, int ioret)
{
- char *buf, *path = NULL;
+ struct dname_buf *db;
+ char *path = NULL;
struct dentry *dentry = NULL;
- struct inode *inode = page->mapping->host;
/* this can be called inside spin lock so use GFP_ATOMIC. */
- buf = (char *)__get_free_page(GFP_ATOMIC);
- if (buf != NULL) {
- dentry = d_find_alias(page->mapping->host);
+ db = (struct dname_buf *)__get_free_page(GFP_ATOMIC);
+ if (db != NULL) {
+
+ dentry = d_find_alias(inode);
if (dentry != NULL)
- path = ll_d_path(dentry, buf, PAGE_SIZE);
+ path = ll_d_path(dentry, db->buf, sizeof(db->buf));
}
/* The below message is checked in recovery-small.sh test_24b */
CDEBUG(D_WARNING,
"%s: dirty page discard: %s/fid: "DFID"/%s may get corrupted "
"(rc %d)\n", ll_i2sbi(inode)->ll_fsname,
- s2lsi(page->mapping->host->i_sb)->lsi_lmd->lmd_dev,
+ s2lsi(inode->i_sb)->lsi_lmd->lmd_dev,
PFID(ll_inode2fid(inode)),
(path && !IS_ERR(path)) ? path : "", ioret);
- if (dentry != NULL)
- dput(dentry);
-
- if (buf != NULL)
- free_page((unsigned long)buf);
+ if (dentry != NULL) {
+ /* We cannot dput here since if we happen to be the last holder
+ * then we can end up waiting for page evictions that
+ * in turn wait for RPCs that need this instance of ptlrpcd
+ * (callng brw_interpret->*page_completion*->vmpage_error->here)
+ * LU-15340
+ */
+ INIT_WORK(&db->db_work, ll_dput_later);
+ db->db_dentry = dentry;
+ schedule_work(&db->db_work);
+ } else {
+ if (db != NULL)
+ free_page((unsigned long)db);
+ }
}
ssize_t ll_copy_user_md(const struct lov_user_md __user *md,
struct root_squash_info *squash = &sbi->ll_squash;
int i;
bool matched;
- struct lnet_process_id id;
+ struct lnet_processid id;
/* Update norootsquash flag */
spin_lock(&squash->rsi_lock);
matched = false;
i = 0;
while (LNetGetId(i++, &id) != -ENOENT) {
- if (id.nid == LNET_NID_LO_0)
+ if (nid_is_lo0(&id.nid))
continue;
- if (cfs_match_nid(id.nid, &squash->rsi_nosquash_nids)) {
+ if (cfs_match_nid(lnet_nid_to_nid4(&id.nid),
+ &squash->rsi_nosquash_nids)) {
matched = true;
break;
}