#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>
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);
OBD_CONNECT2_LSOM |
OBD_CONNECT2_ASYNC_DISCARD |
OBD_CONNECT2_PCC |
- OBD_CONNECT2_CRUSH;
+ OBD_CONNECT2_CRUSH | OBD_CONNECT2_LSEEK |
+ 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();
OBD_CONNECT_BULK_MBITS | OBD_CONNECT_SHORTIO |
OBD_CONNECT_FLAGS2 | OBD_CONNECT_GRANT_SHRINK;
data->ocd_connect_flags2 = OBD_CONNECT2_LOCKAHEAD |
- OBD_CONNECT2_INC_XID;
+ OBD_CONNECT2_INC_XID | OBD_CONNECT2_LSEEK;
if (!OBD_FAIL_CHECK(OBD_FAIL_OSC_CONNECT_GRANT_PARAM))
data->ocd_connect_flags |= OBD_CONNECT_GRANT_PARAM;
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",
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);
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))
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);
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);
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;
}
}
if (namelen > ll_i2sbi(i1)->ll_namelen)
return ERR_PTR(-ENAMETOOLONG);
- if (!lu_name_is_valid_2(name, namelen))
+ /* "/" is not valid name, but it's allowed */
+ if (!lu_name_is_valid_2(name, namelen) &&
+ strncmp("/", name, namelen) != 0)
return ERR_PTR(-EINVAL);
}
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)