#include <linux/delay.h>
#include <linux/uidgid.h>
#include <linux/security.h>
+#include <linux/fs_struct.h>
#ifndef HAVE_CPUS_READ_LOCK
#include <libcfs/linux/linux-cpu.h>
static struct ll_sb_info *ll_init_sbi(void)
{
- struct workqueue_attrs attrs = { };
- cpumask_var_t *mask;
struct ll_sb_info *sbi = NULL;
unsigned long pages;
unsigned long lru_page_max;
sbi->ll_ra_info.ra_async_max_active = ll_get_ra_async_max_active();
sbi->ll_ra_info.ll_readahead_wq =
- alloc_workqueue("ll-readahead-wq", WQ_UNBOUND,
- sbi->ll_ra_info.ra_async_max_active);
- if (!sbi->ll_ra_info.ll_readahead_wq)
- GOTO(out_pcc, rc = -ENOMEM);
-
- mask = cfs_cpt_cpumask(cfs_cpt_tab, CFS_CPT_ANY);
- if (mask && alloc_cpumask_var(&attrs.cpumask, GFP_KERNEL)) {
- cpumask_copy(attrs.cpumask, *mask);
- cpus_read_lock();
- cfs_apply_workqueue_attrs(sbi->ll_ra_info.ll_readahead_wq,
- &attrs);
- cpus_read_unlock();
- free_cpumask_var(attrs.cpumask);
- }
+ cfs_cpt_bind_workqueue("ll-readahead-wq", cfs_cpt_tab,
+ 0, CFS_CPT_ANY,
+ sbi->ll_ra_info.ra_async_max_active);
+ if (IS_ERR(sbi->ll_ra_info.ll_readahead_wq))
+ GOTO(out_pcc, rc = PTR_ERR(sbi->ll_ra_info.ll_readahead_wq));
/* initialize ll_cache data */
sbi->ll_cache = cl_cache_init(lru_page_max);
if (sbi->ll_cache == NULL)
GOTO(out_destroy_ra, rc = -ENOMEM);
- sbi->ll_ra_info.ra_max_pages_per_file = min(pages / 32,
- SBI_DEFAULT_READ_AHEAD_MAX);
+ sbi->ll_ra_info.ra_max_pages =
+ min(pages / 32, SBI_DEFAULT_READ_AHEAD_MAX);
+ sbi->ll_ra_info.ra_max_pages_per_file =
+ min(sbi->ll_ra_info.ra_max_pages / 4,
+ SBI_DEFAULT_READ_AHEAD_PER_FILE_MAX);
sbi->ll_ra_info.ra_async_pages_per_file_threshold =
sbi->ll_ra_info.ra_max_pages_per_file;
- sbi->ll_ra_info.ra_max_pages = sbi->ll_ra_info.ra_max_pages_per_file;
sbi->ll_ra_info.ra_max_read_ahead_whole_pages = -1;
atomic_set(&sbi->ll_ra_info.ra_async_inflight, 0);
sbi->ll_flags |= LL_SBI_AGL_ENABLED;
sbi->ll_flags |= LL_SBI_FAST_READ;
sbi->ll_flags |= LL_SBI_TINY_WRITE;
+ ll_sbi_set_encrypt(sbi, true);
/* root squash */
sbi->ll_squash.rsi_uid = 0;
OBD_CONNECT2_LSOM |
OBD_CONNECT2_ASYNC_DISCARD |
OBD_CONNECT2_PCC |
- OBD_CONNECT2_CRUSH;
+ OBD_CONNECT2_CRUSH |
+ OBD_CONNECT2_GETATTR_PFID;
#ifdef HAVE_LRU_RESIZE_SUPPORT
if (sbi->ll_flags & LL_SBI_LRU_RESIZE)
data->ocd_connect_flags |= OBD_CONNECT_LRU_RESIZE;
#endif
-#ifdef CONFIG_LUSTRE_FS_POSIX_ACL
- data->ocd_connect_flags |= OBD_CONNECT_ACL | OBD_CONNECT_UMASK |
- OBD_CONNECT_LARGE_ACL;
-#endif
+ data->ocd_connect_flags |= OBD_CONNECT_ACL_FLAGS;
data->ocd_cksum_types = obd_cksum_types_supported_client();
data->ocd_connect_flags &= ~OBD_CONNECT_PINGLESS;
obd_connect_set_secctx(data);
+ if (ll_sbi_has_encrypt(sbi))
+ obd_connect_set_enc(data);
#if defined(CONFIG_SECURITY)
data->ocd_connect_flags2 |= OBD_CONNECT2_SELINUX_POLICY;
if (obd_connect_has_secctx(data))
sbi->ll_flags |= LL_SBI_FILE_SECCTX;
+ if (ll_sbi_has_encrypt(sbi) && !obd_connect_has_enc(data)) {
+ if (ll_sbi_has_test_dummy_encryption(sbi))
+ 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 (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 (sbi->ll_flags & LL_SBI_ALWAYS_PING)
data->ocd_connect_flags &= ~OBD_CONNECT_PINGLESS;
+ if (ll_sbi_has_encrypt(sbi))
+ obd_connect_set_enc(data);
+
CDEBUG(D_RPCTRACE, "ocd_connect_flags: %#llx ocd_version: %d "
"ocd_grant: %d\n", data->ocd_connect_flags,
data->ocd_version, data->ocd_grant);
GOTO(out_md, err);
}
+ 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))
+ 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)) {
+ LCONSOLE_WARN("Test dummy encryption mode enabled\n");
+ }
+
sbi->ll_dt_exp->exp_connect_data = *data;
/* Don't change value if it was specified in the config log */
#if THREAD_SIZE >= 8192 /*b=17630*/
sb->s_export_op = &lustre_export_operations;
#endif
+#ifdef HAVE_LUSTRE_CRYPTO
+ llcrypt_set_ops(sb, &lustre_cryptops);
+#endif
/* make root inode
* XXX: move this to after cbd setup? */
ptlrpc_req_finished(request);
if (IS_ERR(root)) {
-#ifdef CONFIG_LUSTRE_FS_POSIX_ACL
- if (lmd.posix_acl) {
- posix_acl_release(lmd.posix_acl);
- lmd.posix_acl = NULL;
- }
-#endif
+ lmd_clear_acl(&lmd);
err = IS_ERR(root) ? PTR_ERR(root) : -EBADF;
root = NULL;
CERROR("%s: bad ll_iget() for root: rc = %d\n",
*flags |= tmp;
goto next;
}
+ tmp = ll_set_opt("test_dummy_encryption", s1,
+ LL_SBI_TEST_DUMMY_ENCRYPTION);
+ if (tmp) {
+#ifdef HAVE_LUSTRE_CRYPTO
+ *flags |= tmp;
+#else
+ LCONSOLE_WARN("Test dummy encryption mount option ignored: encryption not supported\n");
+#endif
+ goto next;
+ }
+ tmp = ll_set_opt("noencrypt", s1, LL_SBI_ENCRYPT);
+ if (tmp) {
+#ifdef HAVE_LUSTRE_CRYPTO
+ *flags &= ~tmp;
+#else
+ LCONSOLE_WARN("noencrypt mount option ignored: encryption not supported\n");
+#endif
+ goto next;
+ }
LCONSOLE_ERROR_MSG(0x152, "Unknown option '%s', won't mount.\n",
s1);
RETURN(-EINVAL);
init_rwsem(&lli->lli_lsm_sem);
} else {
mutex_init(&lli->lli_size_mutex);
+ mutex_init(&lli->lli_setattr_mutex);
lli->lli_symlink_name = NULL;
ll_trunc_sem_init(&lli->lli_trunc_sem);
range_lock_tree_init(&lli->lli_write_tree);
/* UUID handling */
generate_random_uuid(uuid.b);
- snprintf(sbi->ll_sb_uuid.uuid, UUID_SIZE, "%pU", uuid.b);
+ snprintf(sbi->ll_sb_uuid.uuid, sizeof(sbi->ll_sb_uuid), "%pU", uuid.b);
CDEBUG(D_CONFIG, "llite sb uuid: %s\n", sbi->ll_sb_uuid.uuid);
GOTO(unlock, rc = -ENOMEM);
/* validate the lsm */
- rc = md_merge_attr(ll_i2mdexp(inode), lli->lli_lsm_md, attr,
- ll_md_blocking_ast);
+ rc = md_merge_attr(ll_i2mdexp(inode), &lli->lli_fid, lli->lli_lsm_md,
+ attr, ll_md_blocking_ast);
if (!rc) {
if (md->body->mbo_valid & OBD_MD_FLNLINK)
md->body->mbo_nlink = attr->cat_nlink;
ll_xattr_cache_destroy(inode);
-#ifdef CONFIG_LUSTRE_FS_POSIX_ACL
forget_all_cached_acls(inode);
- if (lli->lli_posix_acl) {
- posix_acl_release(lli->lli_posix_acl);
- lli->lli_posix_acl = NULL;
- }
-#endif
+ lli_clear_acl(lli);
lli->lli_inode_magic = LLI_INODE_DEAD;
if (S_ISDIR(inode->i_mode))
*/
cl_inode_fini(inode);
+ llcrypt_put_encryption_info(inode);
+
EXIT;
}
RETURN(rc);
}
+/**
+ * Zero portion of page that is part of @inode.
+ * This implies, if necessary:
+ * - taking cl_lock on range corresponding to concerned page
+ * - grabbing vm page
+ * - associating cl_page
+ * - proceeding to clio read
+ * - zeroing range in page
+ * - proceeding to cl_page flush
+ * - releasing cl_lock
+ *
+ * \param[in] inode inode
+ * \param[in] index page index
+ * \param[in] offset offset in page to start zero from
+ * \param[in] len len to zero
+ *
+ * \retval 0 on success
+ * \retval negative errno on failure
+ */
+int ll_io_zero_page(struct inode *inode, pgoff_t index, pgoff_t offset,
+ unsigned len)
+{
+ struct ll_inode_info *lli = ll_i2info(inode);
+ struct cl_object *clob = lli->lli_clob;
+ __u16 refcheck;
+ struct lu_env *env = NULL;
+ struct cl_io *io = NULL;
+ struct cl_page *clpage = NULL;
+ struct page *vmpage = NULL;
+ unsigned from = index << PAGE_SHIFT;
+ struct cl_lock *lock = NULL;
+ struct cl_lock_descr *descr = NULL;
+ struct cl_2queue *queue = NULL;
+ struct cl_sync_io *anchor = NULL;
+ bool holdinglock = false;
+ bool lockedbymyself = true;
+ int rc;
+
+ ENTRY;
+
+ env = cl_env_get(&refcheck);
+ if (IS_ERR(env))
+ RETURN(PTR_ERR(env));
+
+ io = vvp_env_thread_io(env);
+ io->ci_obj = clob;
+ rc = cl_io_rw_init(env, io, CIT_WRITE, from, PAGE_SIZE);
+ if (rc)
+ GOTO(putenv, rc);
+
+ lock = vvp_env_lock(env);
+ descr = &lock->cll_descr;
+ descr->cld_obj = io->ci_obj;
+ descr->cld_start = cl_index(io->ci_obj, from);
+ descr->cld_end = cl_index(io->ci_obj, from + PAGE_SIZE - 1);
+ descr->cld_mode = CLM_WRITE;
+ descr->cld_enq_flags = CEF_MUST | CEF_NONBLOCK;
+
+ /* request lock for page */
+ rc = cl_lock_request(env, io, lock);
+ /* -ECANCELED indicates a matching lock with a different extent
+ * was already present, and -EEXIST indicates a matching lock
+ * on exactly the same extent was already present.
+ * In both cases it means we are covered.
+ */
+ if (rc == -ECANCELED || rc == -EEXIST)
+ rc = 0;
+ else if (rc < 0)
+ GOTO(iofini, rc);
+ else
+ holdinglock = true;
+
+ /* grab page */
+ vmpage = grab_cache_page_nowait(inode->i_mapping, index);
+ if (vmpage == NULL)
+ GOTO(rellock, rc = -EOPNOTSUPP);
+
+ if (!PageDirty(vmpage)) {
+ /* associate cl_page */
+ clpage = cl_page_find(env, clob, vmpage->index,
+ vmpage, CPT_CACHEABLE);
+ if (IS_ERR(clpage))
+ GOTO(pagefini, rc = PTR_ERR(clpage));
+
+ cl_page_assume(env, io, clpage);
+ }
+
+ if (!PageUptodate(vmpage) && !PageDirty(vmpage) &&
+ !PageWriteback(vmpage)) {
+ /* read page */
+ /* set PagePrivate2 to detect special case of empty page
+ * in osc_brw_fini_request()
+ */
+ SetPagePrivate2(vmpage);
+ rc = ll_io_read_page(env, io, clpage, NULL);
+ 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.
+ */
+ 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 */
+ zero_user(vmpage, offset, len);
+
+ if (holdinglock && clpage) {
+ /* explicitly write newly modified page */
+ queue = &io->ci_queue;
+ cl_2queue_init(queue);
+ anchor = &vvp_env_info(env)->vti_anchor;
+ cl_sync_io_init(anchor, 1);
+ clpage->cp_sync_io = anchor;
+ cl_2queue_add(queue, clpage);
+ rc = cl_io_submit_rw(env, io, CRT_WRITE, queue);
+ if (rc)
+ GOTO(queuefini1, rc);
+ rc = cl_sync_io_wait(env, anchor, 0);
+ if (rc)
+ GOTO(queuefini2, rc);
+ cl_page_assume(env, io, clpage);
+
+queuefini2:
+ cl_2queue_discard(env, io, queue);
+queuefini1:
+ cl_2queue_disown(env, io, queue);
+ cl_2queue_fini(env, queue);
+ }
+
+clpfini:
+ if (clpage)
+ cl_page_put(env, clpage);
+pagefini:
+ if (lockedbymyself) {
+ unlock_page(vmpage);
+ put_page(vmpage);
+ }
+rellock:
+ if (holdinglock)
+ cl_lock_release(env, lock);
+iofini:
+ cl_io_fini(env, io);
+putenv:
+ if (env)
+ cl_env_put(env, &refcheck);
+
+ RETURN(rc);
+}
+
/* 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.
GOTO(out, rc);
}
} else {
+ unsigned int flags = 0;
+
/* For truncate and utimes sending attributes to OSTs,
* setting mtime/atime to the past will be performed
* under PW [0:EOF] extent lock (new_size:EOF for
* it is necessary due to possible time
* de-synchronization between MDT inode and OST objects
*/
- rc = cl_setattr_ost(lli->lli_clob, attr, xvalid, 0);
+ if (S_ISREG(inode->i_mode) && IS_ENCRYPTED(inode) &&
+ attr->ia_valid & ATTR_SIZE) {
+ xvalid |= OP_XVALID_FLAGS;
+ flags = LUSTRE_ENCRYPT_FL;
+ /* Call to ll_io_zero_page is not necessary if
+ * truncating on PAGE_SIZE boundary, because
+ * whole pages will be wiped.
+ * In case of Direct IO, all we need is to set
+ * new size.
+ */
+ if (attr->ia_size & ~PAGE_MASK &&
+ !(attr->ia_valid & ATTR_FILE &&
+ attr->ia_file->f_flags & O_DIRECT)) {
+ pgoff_t offset =
+ attr->ia_size & (PAGE_SIZE - 1);
+
+ rc = ll_io_zero_page(inode,
+ attr->ia_size >> PAGE_SHIFT,
+ offset, PAGE_SIZE - offset);
+ if (rc)
+ GOTO(out, rc);
+ }
+ }
+ rc = cl_setattr_ost(lli->lli_clob, attr, xvalid, flags);
}
}
{
int mode = de->d_inode->i_mode;
enum op_xvalid xvalid = 0;
+ int rc;
+
+ rc = llcrypt_prepare_setattr(de, attr);
+ if (rc)
+ return rc;
if ((attr->ia_valid & (ATTR_CTIME|ATTR_SIZE|ATTR_MODE)) ==
(ATTR_CTIME|ATTR_SIZE|ATTR_MODE))
CDEBUG(D_SUPER, "MDC blocks %llu/%llu objects %llu/%llu\n",
osfs->os_bavail, osfs->os_blocks, osfs->os_ffree, osfs->os_files);
- if (osfs->os_state & OS_STATE_SUM)
+ if (osfs->os_state & OS_STATFS_SUM)
GOTO(out, rc);
rc = obd_statfs(NULL, sbi->ll_dt_exp, &obd_osfs, max_age, flags);
void ll_update_inode_flags(struct inode *inode, int ext_flags)
{
+ /* do not clear encryption flag */
+ ext_flags |= ll_inode_to_ext_flags(inode->i_flags) & LUSTRE_ENCRYPT_FL;
inode->i_flags = ll_ext_to_inode_flags(ext_flags);
if (ext_flags & LUSTRE_PROJINHERIT_FL)
ll_file_set_flag(ll_i2info(inode), LLIF_PROJECT_INHERIT);
return rc;
}
-#ifdef CONFIG_LUSTRE_FS_POSIX_ACL
- if (body->mbo_valid & OBD_MD_FLACL) {
- spin_lock(&lli->lli_lock);
- if (lli->lli_posix_acl)
- posix_acl_release(lli->lli_posix_acl);
- lli->lli_posix_acl = md->posix_acl;
- spin_unlock(&lli->lli_lock);
- }
-#endif
+ if (body->mbo_valid & OBD_MD_FLACL)
+ lli_replace_acl(lli, md);
+
inode->i_ino = cl_fid_build_ino(&body->mbo_fid1,
sbi->ll_flags & LL_SBI_32BIT_API);
inode->i_generation = cl_fid_build_gen(&body->mbo_fid1);
lli->lli_ctime = body->mbo_ctime;
}
+ if (body->mbo_valid & OBD_MD_FLBTIME)
+ lli->lli_btime = body->mbo_btime;
+
/* Clear i_flags to remove S_NOSEC before permissions are updated */
if (body->mbo_valid & OBD_MD_FLFLAGS)
ll_update_inode_flags(inode, body->mbo_flags);
LASSERT(fid_seq(&lli->lli_fid) != 0);
+ lli->lli_attr_valid = body->mbo_valid;
if (body->mbo_valid & OBD_MD_FLSIZE) {
i_size_write(inode, body->mbo_size);
if (body->mbo_valid & OBD_MD_FLBLOCKS)
inode->i_blocks = body->mbo_blocks;
+ } else {
+ if (body->mbo_valid & OBD_MD_FLLAZYSIZE)
+ lli->lli_lazysize = body->mbo_size;
+ if (body->mbo_valid & OBD_MD_FLLAZYBLOCKS)
+ lli->lli_lazyblocks = body->mbo_blocks;
}
if (body->mbo_valid & OBD_MD_TSTATE) {
sbi->ll_flags & LL_SBI_32BIT_API),
&md);
if (IS_ERR(*inode)) {
-#ifdef CONFIG_LUSTRE_FS_POSIX_ACL
- if (md.posix_acl) {
- posix_acl_release(md.posix_acl);
- md.posix_acl = NULL;
- }
-#endif
+ lmd_clear_acl(&md);
rc = IS_ERR(*inode) ? PTR_ERR(*inode) : -ENOMEM;
*inode = NULL;
CERROR("new_inode -fatal: rc %d\n", rc);
void ll_unlock_md_op_lsm(struct md_op_data *op_data)
{
if (op_data->op_mea2_sem) {
- up_read(op_data->op_mea2_sem);
+ up_read_non_owner(op_data->op_mea2_sem);
op_data->op_mea2_sem = NULL;
}
if (op_data->op_mea1_sem) {
- up_read(op_data->op_mea1_sem);
+ up_read_non_owner(op_data->op_mea1_sem);
op_data->op_mea1_sem = NULL;
}
}
op_data->op_code = opc;
if (S_ISDIR(i1->i_mode)) {
- down_read(&ll_i2info(i1)->lli_lsm_sem);
+ down_read_non_owner(&ll_i2info(i1)->lli_lsm_sem);
op_data->op_mea1_sem = &ll_i2info(i1)->lli_lsm_sem;
op_data->op_mea1 = ll_i2info(i1)->lli_lsm_md;
op_data->op_default_mea1 = ll_i2info(i1)->lli_default_lsm_md;
op_data->op_fid2 = *ll_inode2fid(i2);
if (S_ISDIR(i2->i_mode)) {
if (i2 != i1) {
- down_read(&ll_i2info(i2)->lli_lsm_sem);
+ /* i2 is typically a child of i1, and MUST be
+ * further from the root to avoid deadlocks.
+ */
+ down_read_non_owner(&ll_i2info(i2)->lli_lsm_sem);
op_data->op_mea2_sem =
&ll_i2info(i2)->lli_lsm_sem;
}
ll_unlock_md_op_lsm(op_data);
security_release_secctx(op_data->op_file_secctx,
op_data->op_file_secctx_size);
- OBD_FREE_PTR(op_data);
+ llcrypt_free_ctx(op_data->op_file_encctx, op_data->op_file_encctx_size);
+ OBD_FREE_PTR(op_data);
}
int ll_show_options(struct seq_file *seq, struct dentry *dentry)
if (sbi->ll_flags & LL_SBI_ALWAYS_PING)
seq_puts(seq, ",always_ping");
+ if (ll_sbi_has_test_dummy_encryption(sbi))
+ seq_puts(seq, ",test_dummy_encryption");
+
+ if (ll_sbi_has_encrypt(sbi))
+ seq_puts(seq, ",encrypt");
+ else
+ seq_puts(seq, ",noencrypt");
+
RETURN(0);
}