#include <linux/falloc.h>
#include <uapi/linux/lustre/lustre_ioctl.h>
+#include <uapi/linux/llcrypt.h>
#include <lustre_swab.h>
#include "cl_object.h"
{
struct niobuf_local *lnb = data;
void *kaddr;
+ int rc = 0;
+
+ struct inode *inode = page2inode(page);
kaddr = kmap_atomic(page);
memcpy(kaddr, lnb->lnb_data, lnb->lnb_len);
flush_dcache_page(page);
SetPageUptodate(page);
kunmap_atomic(kaddr);
+
+ if (inode && IS_ENCRYPTED(inode) && S_ISREG(inode->i_mode)) {
+ if (!llcrypt_has_encryption_key(inode))
+ CDEBUG(D_SEC, "no enc key for "DFID"\n",
+ PFID(ll_inode2fid(inode)));
+ /* decrypt only if page is not empty */
+ else if (memcmp(page_address(page),
+ page_address(ZERO_PAGE(0)),
+ PAGE_SIZE) != 0)
+ rc = llcrypt_decrypt_pagecache_blocks(page,
+ PAGE_SIZE,
+ 0);
+ }
unlock_page(page);
- return 0;
+ return rc;
}
void ll_dom_finish_open(struct inode *inode, struct ptlrpc_request *req,
* buffer, in both cases total size should be equal to the file size.
*/
body = req_capsule_server_get(&req->rq_pill, &RMF_MDT_BODY);
- if (rnb->rnb_offset + rnb->rnb_len != body->mbo_dom_size) {
+ if (rnb->rnb_offset + rnb->rnb_len != body->mbo_dom_size &&
+ !(inode && IS_ENCRYPTED(inode))) {
CERROR("%s: server returns off/len %llu/%u but size %llu\n",
ll_i2sbi(inode)->ll_fsname, rnb->rnb_offset,
rnb->rnb_len, body->mbo_dom_size);
it = file->private_data; /* XXX: compat macro */
file->private_data = NULL; /* prevent ll_local_open assertion */
+ if (S_ISREG(inode->i_mode)) {
+ rc = llcrypt_file_open(inode, file);
+ if (rc)
+ GOTO(out_nofiledata, rc);
+ }
+
fd = ll_file_data_get();
if (fd == NULL)
GOTO(out_nofiledata, rc = -ENOMEM);
struct file *file, enum cl_io_type iot,
loff_t *ppos, size_t count)
{
- struct vvp_io *vio = vvp_env_io(env);
- struct inode *inode = file_inode(file);
- struct ll_inode_info *lli = ll_i2info(inode);
- struct ll_file_data *fd = file->private_data;
- struct range_lock range;
- struct cl_io *io;
- ssize_t result = 0;
- int rc = 0;
- unsigned retried = 0;
- unsigned ignore_lockless = 0;
+ struct vvp_io *vio = vvp_env_io(env);
+ struct inode *inode = file_inode(file);
+ struct ll_inode_info *lli = ll_i2info(inode);
+ struct ll_file_data *fd = file->private_data;
+ struct range_lock range;
+ struct cl_io *io;
+ ssize_t result = 0;
+ int rc = 0;
+ unsigned int retried = 0, ignore_lockless = 0;
+ bool is_aio = false;
ENTRY;
case IO_NORMAL:
vio->vui_iter = args->u.normal.via_iter;
vio->vui_iocb = args->u.normal.via_iocb;
+ if (file->f_flags & O_DIRECT) {
+ if (!is_sync_kiocb(vio->vui_iocb))
+ is_aio = true;
+ io->ci_aio = cl_aio_alloc(vio->vui_iocb);
+ if (!io->ci_aio)
+ GOTO(out, rc = -ENOMEM);
+ }
/* Direct IO reads must also take range lock,
* or multiple reads will try to work on the same pages
* See LU-6227 for details. */
rc = io->ci_result;
}
- if (io->ci_nob > 0) {
+ /*
+ * In order to move forward AIO, ci_nob was increased,
+ * but that doesn't mean io have been finished, it just
+ * means io have been submited, we will always return
+ * EIOCBQUEUED to the caller, So we could only return
+ * number of bytes in non-AIO case.
+ */
+ if (io->ci_nob > 0 && !is_aio) {
result += io->ci_nob;
count -= io->ci_nob;
*ppos = io->u.ci_wr.wr.crw_pos; /* for splice */
args->u.normal.via_iter = vio->vui_iter;
}
out:
+ if (io->ci_aio) {
+ /**
+ * Drop one extra reference so that end_io() could be
+ * called for this IO context, we could call it after
+ * we make sure all AIO requests have been proceed.
+ */
+ cl_sync_io_note(env, &io->ci_aio->cda_sync,
+ rc == -EIOCBQUEUED ? 0 : rc);
+ if (!is_aio) {
+ cl_aio_free(io->ci_aio);
+ io->ci_aio = NULL;
+ }
+ }
cl_io_fini(env, io);
CDEBUG(D_VFSTRACE,
GOTO(out, rc);
rc = ll_file_getstripe(inode, arg, lum_size);
+ if (S_ISREG(inode->i_mode) && IS_ENCRYPTED(inode) &&
+ ll_i2info(inode)->lli_clob) {
+ struct iattr attr = { 0 };
+
+ rc = cl_setattr_ost(ll_i2info(inode)->lli_clob, &attr,
+ OP_XVALID_FLAGS, LUSTRE_ENCRYPT_FL);
+ }
}
cl_lov_delay_create_clear(&file->f_flags);
ENTRY;
- CDEBUG(D_VFSTRACE, "Lock request: file=%.*s, inode=%p, mode=%s "
- "start=%llu, end=%llu\n", dentry->d_name.len,
- dentry->d_name.name, dentry->d_inode,
+ CDEBUG(D_VFSTRACE,
+ "Lock request: file=%pd, inode=%p, mode=%s start=%llu, end=%llu\n",
+ dentry, dentry->d_inode,
user_lockname[ladvise->lla_lockahead_mode], (__u64) start,
(__u64) end);
fd->fd_designated_mirror = (__u32)arg;
RETURN(0);
}
- case LL_IOC_FSGETXATTR:
+ case FS_IOC_FSGETXATTR:
RETURN(ll_ioctl_fsgetxattr(inode, cmd, arg));
- case LL_IOC_FSSETXATTR:
+ case FS_IOC_FSSETXATTR:
RETURN(ll_ioctl_fssetxattr(inode, cmd, arg));
case BLKSSZGET:
RETURN(put_user(PAGE_SIZE, (int __user *)arg));
OBD_FREE_PTR(state);
RETURN(rc);
}
+#ifdef HAVE_LUSTRE_CRYPTO
+ case LL_IOC_SET_ENCRYPTION_POLICY:
+ if (!ll_sbi_has_encrypt(ll_i2sbi(inode)))
+ return -EOPNOTSUPP;
+ return llcrypt_ioctl_set_policy(file, (const void __user *)arg);
+ case LL_IOC_GET_ENCRYPTION_POLICY_EX:
+ if (!ll_sbi_has_encrypt(ll_i2sbi(inode)))
+ return -EOPNOTSUPP;
+ return llcrypt_ioctl_get_policy_ex(file, (void __user *)arg);
+ case LL_IOC_ADD_ENCRYPTION_KEY:
+ if (!ll_sbi_has_encrypt(ll_i2sbi(inode)))
+ return -EOPNOTSUPP;
+ return llcrypt_ioctl_add_key(file, (void __user *)arg);
+ case LL_IOC_REMOVE_ENCRYPTION_KEY:
+ if (!ll_sbi_has_encrypt(ll_i2sbi(inode)))
+ return -EOPNOTSUPP;
+ return llcrypt_ioctl_remove_key(file, (void __user *)arg);
+ case LL_IOC_REMOVE_ENCRYPTION_KEY_ALL_USERS:
+ if (!ll_sbi_has_encrypt(ll_i2sbi(inode)))
+ return -EOPNOTSUPP;
+ return llcrypt_ioctl_remove_key_all_users(file,
+ (void __user *)arg);
+ case LL_IOC_GET_ENCRYPTION_KEY_STATUS:
+ if (!ll_sbi_has_encrypt(ll_i2sbi(inode)))
+ return -EOPNOTSUPP;
+ return llcrypt_ioctl_get_key_status(file, (void __user *)arg);
+#endif
default:
RETURN(obd_iocontrol(cmd, ll_i2dtexp(inode), 0, NULL,
(void __user *)arg));
flags = LDLM_FL_BLOCK_GRANTED | LDLM_FL_CBPENDING | LDLM_FL_TEST_LOCK;
for (i = 0; i < MDS_INODELOCK_NUMBITS && *bits != 0; i++) {
- policy.l_inodebits.bits = *bits & (1 << i);
+ policy.l_inodebits.bits = *bits & BIT(i);
if (policy.l_inodebits.bits == 0)
continue;
- if (md_lock_match(ll_i2mdexp(inode), flags, fid, LDLM_IBITS,
- &policy, mode, &lockh)) {
- struct ldlm_lock *lock;
-
- lock = ldlm_handle2lock(&lockh);
- if (lock) {
- *bits &=
- ~(lock->l_policy_data.l_inodebits.bits);
- LDLM_LOCK_PUT(lock);
- } else {
- *bits &= ~policy.l_inodebits.bits;
- }
- }
- }
+ if (md_lock_match(ll_i2mdexp(inode), flags, fid, LDLM_IBITS,
+ &policy, mode, &lockh)) {
+ struct ldlm_lock *lock;
+
+ lock = ldlm_handle2lock(&lockh);
+ if (lock) {
+ *bits &=
+ ~(lock->l_policy_data.l_inodebits.bits);
+ LDLM_LOCK_PUT(lock);
+ } else {
+ *bits &= ~policy.l_inodebits.bits;
+ }
+ }
+ }
RETURN(*bits == 0);
}
PFID(ll_inode2fid(inode)), inode, dentry->d_name.name);
/* Call getattr by fid, so do not provide name at all. */
- op_data = ll_prep_md_op_data(NULL, inode, inode, NULL, 0, 0,
- LUSTRE_OPC_ANY, NULL);
+ op_data = ll_prep_md_op_data(NULL, dentry->d_parent->d_inode, inode,
+ NULL, 0, 0, LUSTRE_OPC_ANY, NULL);
if (IS_ERR(op_data))
RETURN(PTR_ERR(op_data));
RETURN(0);
down_read(&lli->lli_lsm_sem);
- rc = md_merge_attr(ll_i2mdexp(inode), ll_i2info(inode)->lli_lsm_md,
+ rc = md_merge_attr(ll_i2mdexp(inode), &lli->lli_fid, lli->lli_lsm_md,
&attr, ll_md_blocking_ast);
up_read(&lli->lli_lsm_sem);
if (rc != 0)
RETURN(0);
}
-int ll_getattr_dentry(struct dentry *de, struct kstat *stat)
+int ll_getattr_dentry(struct dentry *de, struct kstat *stat, u32 request_mask,
+ unsigned int flags)
{
struct inode *inode = de->d_inode;
struct ll_sb_info *sbi = ll_i2sbi(inode);
struct ll_inode_info *lli = ll_i2info(inode);
+ struct inode *dir = de->d_parent->d_inode;
+ bool need_glimpse = true;
ktime_t kstart = ktime_get();
int rc;
+ /* The OST object(s) determine the file size, blocks and mtime. */
+ if (!(request_mask & STATX_SIZE || request_mask & STATX_BLOCKS ||
+ request_mask & STATX_MTIME))
+ need_glimpse = false;
+
+ if (dentry_may_statahead(dir, de))
+ ll_start_statahead(dir, de, need_glimpse &&
+ !(flags & AT_STATX_DONT_SYNC));
+
+ if (flags & AT_STATX_DONT_SYNC)
+ GOTO(fill_attr, rc = 0);
+
rc = ll_inode_revalidate(de, IT_GETATTR);
if (rc < 0)
RETURN(rc);
if (S_ISREG(inode->i_mode)) {
bool cached;
- rc = pcc_inode_getattr(inode, &cached);
+ if (!need_glimpse)
+ GOTO(fill_attr, rc);
+
+ rc = pcc_inode_getattr(inode, request_mask, flags, &cached);
if (cached && rc < 0)
RETURN(rc);
+ if (cached)
+ GOTO(fill_attr, rc);
+
+ /*
+ * If the returned attr is masked with OBD_MD_FLSIZE &
+ * OBD_MD_FLBLOCKS & OBD_MD_FLMTIME, it means that the file size
+ * or blocks obtained from MDT is strictly correct, and the file
+ * is usually not being modified by clients, and the [a|m|c]time
+ * got from MDT is also strictly correct.
+ * Under this circumstance, it does not need to send glimpse
+ * RPCs to OSTs for file attributes such as the size and blocks.
+ */
+ if (lli->lli_attr_valid & OBD_MD_FLSIZE &&
+ lli->lli_attr_valid & OBD_MD_FLBLOCKS &&
+ lli->lli_attr_valid & OBD_MD_FLMTIME) {
+ inode->i_mtime.tv_sec = lli->lli_mtime;
+ if (lli->lli_attr_valid & OBD_MD_FLATIME)
+ inode->i_atime.tv_sec = lli->lli_atime;
+ if (lli->lli_attr_valid & OBD_MD_FLCTIME)
+ inode->i_ctime.tv_sec = lli->lli_ctime;
+ GOTO(fill_attr, rc);
+ }
+
/* In case of restore, the MDT has the right size and has
* already send it back without granting the layout lock,
* inode is up-to-date so glimpse is useless.
* restore the MDT holds the layout lock so the glimpse will
* block up to the end of restore (getattr will block)
*/
- if (!cached && !ll_file_test_flag(lli, LLIF_FILE_RESTORING)) {
+ if (!ll_file_test_flag(lli, LLIF_FILE_RESTORING)) {
rc = ll_glimpse_size(inode);
if (rc < 0)
RETURN(rc);
RETURN(rc);
}
- inode->i_atime.tv_sec = lli->lli_atime;
- inode->i_mtime.tv_sec = lli->lli_mtime;
- inode->i_ctime.tv_sec = lli->lli_ctime;
+ if (lli->lli_attr_valid & OBD_MD_FLATIME)
+ inode->i_atime.tv_sec = lli->lli_atime;
+ if (lli->lli_attr_valid & OBD_MD_FLMTIME)
+ inode->i_mtime.tv_sec = lli->lli_mtime;
+ if (lli->lli_attr_valid & OBD_MD_FLCTIME)
+ inode->i_ctime.tv_sec = lli->lli_ctime;
}
+fill_attr:
OBD_FAIL_TIMEOUT(OBD_FAIL_GETATTR_DELAY, 30);
if (ll_need_32bit_api(sbi)) {
stat->size = i_size_read(inode);
stat->blocks = inode->i_blocks;
+#ifdef HAVE_INODEOPS_ENHANCED_GETATTR
+ if (flags & AT_STATX_DONT_SYNC) {
+ if (stat->size == 0 &&
+ lli->lli_attr_valid & OBD_MD_FLLAZYSIZE)
+ stat->size = lli->lli_lazysize;
+ if (stat->blocks == 0 &&
+ lli->lli_attr_valid & OBD_MD_FLLAZYBLOCKS)
+ stat->blocks = lli->lli_lazyblocks;
+ }
+
+ if (lli->lli_attr_valid & OBD_MD_FLBTIME) {
+ stat->result_mask |= STATX_BTIME;
+ stat->btime.tv_sec = lli->lli_btime;
+ }
+
+ stat->attributes_mask = STATX_ATTR_IMMUTABLE | STATX_ATTR_APPEND;
+ stat->attributes |= ll_inode_to_ext_flags(inode->i_flags);
+ stat->result_mask &= request_mask;
+#endif
+
ll_stats_ops_tally(sbi, LPROC_LL_GETATTR,
ktime_us_delta(ktime_get(), kstart));
int ll_getattr(const struct path *path, struct kstat *stat,
u32 request_mask, unsigned int flags)
{
- struct dentry *de = path->dentry;
+ return ll_getattr_dentry(path->dentry, stat, request_mask, flags);
+}
#else
int ll_getattr(struct vfsmount *mnt, struct dentry *de, struct kstat *stat)
{
-#endif
- return ll_getattr_dentry(de, stat);
+ return ll_getattr_dentry(de, stat, STATX_BASIC_STATS,
+ AT_STATX_SYNC_AS_STAT);
}
+#endif
int cl_falloc(struct inode *inode, int mode, loff_t offset, loff_t len)
{
cred->fsuid = make_kuid(&init_user_ns, squash->rsi_uid);
cred->fsgid = make_kgid(&init_user_ns, squash->rsi_gid);
for (cap = 0; cap < sizeof(cfs_cap_t) * 8; cap++) {
- if ((1 << cap) & CFS_CAP_FS_MASK)
+ if (BIT(cap) & CFS_CAP_FS_MASK)
cap_lower(cred->cap_effective, cap);
}
old_cred = override_creds(cred);