*/
/*
* This file is part of Lustre, http://www.lustre.org/
- * Lustre is a trademark of Sun Microsystems, Inc.
*
* lustre/llite/file.c
*
#include <linux/user_namespace.h>
#include <linux/uidgid.h>
#include <linux/falloc.h>
+#include <linux/ktime.h>
#include <uapi/linux/lustre/lustre_ioctl.h>
-#include <uapi/linux/llcrypt.h>
#include <lustre_swab.h>
#include "cl_object.h"
op_data->op_attr.ia_atime = inode->i_atime;
op_data->op_attr.ia_mtime = inode->i_mtime;
op_data->op_attr.ia_ctime = inode->i_ctime;
- op_data->op_attr.ia_size = i_size_read(inode);
+ /* In case of encrypted file without the key, visible size was rounded
+ * up to next LUSTRE_ENCRYPTION_UNIT_SIZE, and clear text size was
+ * stored into lli_lazysize in ll_merge_attr(), so set proper file size
+ * now that we are closing.
+ */
+ if (llcrypt_require_key(inode) == -ENOKEY &&
+ ll_i2info(inode)->lli_attr_valid & OBD_MD_FLLAZYSIZE)
+ op_data->op_attr.ia_size = ll_i2info(inode)->lli_lazysize;
+ else
+ op_data->op_attr.ia_size = i_size_read(inode);
op_data->op_attr.ia_valid |= (ATTR_MODE | ATTR_ATIME | ATTR_ATIME_SET |
ATTR_MTIME | ATTR_MTIME_SET |
ATTR_CTIME);
op_data->op_xvalid |= OP_XVALID_CTIME_SET;
op_data->op_attr_blocks = inode->i_blocks;
op_data->op_attr_flags = ll_inode_to_ext_flags(inode->i_flags);
- if (ll_file_test_flag(ll_i2info(inode), LLIF_PROJECT_INHERIT))
+ if (test_bit(LLIF_PROJECT_INHERIT, &ll_i2info(inode)->lli_flags))
op_data->op_attr_flags |= LUSTRE_PROJINHERIT_FL;
op_data->op_open_handle = och->och_open_handle;
if (och->och_flags & FMODE_WRITE &&
- ll_file_test_and_clear_flag(ll_i2info(inode), LLIF_DATA_MODIFIED))
+ test_and_clear_bit(LLIF_DATA_MODIFIED, &ll_i2info(inode)->lli_flags))
/* For HSM: if inode data has been modified, pack it so that
* MDT can set data dirty flag in the archive. */
op_data->op_bias |= MDS_DATA_MODIFIED;
op_data->op_attr_blocks += ((struct inode *)data)->i_blocks;
op_data->op_attr.ia_valid |= ATTR_SIZE;
op_data->op_xvalid |= OP_XVALID_BLOCKS;
- /* fallthrough */
+ fallthrough;
case MDS_CLOSE_LAYOUT_SPLIT:
case MDS_CLOSE_LAYOUT_SWAP: {
struct split_param *sp = data;
if (unlikely(fd->fd_flags & LL_FILE_GROUP_LOCKED))
ll_put_grouplock(inode, file, fd->fd_grouplock.lg_gid);
+ mutex_lock(&lli->lli_och_mutex);
if (fd->fd_lease_och != NULL) {
bool lease_broken;
+ struct obd_client_handle *lease_och;
+
+ lease_och = fd->fd_lease_och;
+ fd->fd_lease_och = NULL;
+ mutex_unlock(&lli->lli_och_mutex);
/* Usually the lease is not released when the
* application crashed, we need to release here. */
- rc = ll_lease_close(fd->fd_lease_och, inode, &lease_broken);
- CDEBUG(rc ? D_ERROR : D_INODE, "Clean up lease "DFID" %d/%d\n",
- PFID(&lli->lli_fid), rc, lease_broken);
+ rc = ll_lease_close(lease_och, inode, &lease_broken);
- fd->fd_lease_och = NULL;
+ mutex_lock(&lli->lli_och_mutex);
+
+ CDEBUG_LIMIT(rc ? D_ERROR : D_INODE,
+ "Clean up lease "DFID" %d/%d\n",
+ PFID(&lli->lli_fid), rc, lease_broken);
}
if (fd->fd_och != NULL) {
- rc = ll_close_inode_openhandle(inode, fd->fd_och, 0, NULL);
+ struct obd_client_handle *och;
+
+ och = fd->fd_och;
fd->fd_och = NULL;
+ mutex_unlock(&lli->lli_och_mutex);
+
+ rc = ll_close_inode_openhandle(inode, och, 0, NULL);
GOTO(out, rc);
}
/* Let's see if we have good enough OPEN lock on the file and if
we can skip talking to MDS */
- mutex_lock(&lli->lli_och_mutex);
if (fd->fd_omode & FMODE_WRITE) {
lockmode = LCK_CW;
LASSERT(lli->lli_open_fd_write_count);
lli->lli_async_rc = 0;
}
+ lli->lli_close_fd_time = ktime_get();
+
rc = ll_md_close(inode, file);
if (CFS_FAIL_TIMEOUT_MS(OBD_FAIL_PTLRPC_DUMP_LOG, cfs_fail_val))
static inline int ll_dom_readpage(void *data, struct page *page)
{
+ /* since ll_dom_readpage is a page cache helper, it is safe to assume
+ * mapping and host pointers are set here
+ */
+ struct inode *inode;
struct niobuf_local *lnb = data;
void *kaddr;
int rc = 0;
- struct inode *inode = page2inode(page);
+ inode = page2inode(page);
kaddr = kmap_atomic(page);
memcpy(kaddr, lnb->lnb_data, lnb->lnb_len);
put_page(vmpage);
break;
}
- cl_page_export(env, page, 1);
+ SetPageUptodate(vmpage);
cl_page_put(env, page);
unlock_page(vmpage);
put_page(vmpage);
}
op_data = ll_prep_md_op_data(NULL, parent->d_inode, de->d_inode,
- name, len, 0, LUSTRE_OPC_ANY, NULL);
+ name, len, 0, LUSTRE_OPC_OPEN, NULL);
if (IS_ERR(op_data)) {
kfree(name);
RETURN(PTR_ERR(op_data));
op_data->op_data = lmm;
op_data->op_data_size = lmmsize;
+ OBD_FAIL_TIMEOUT(OBD_FAIL_LLITE_OPEN_DELAY, cfs_fail_val);
+
rc = md_intent_lock(sbi->ll_md_exp, op_data, itp, &req,
&ll_md_blocking_ast, 0);
kfree(name);
GOTO(out, rc);
}
- rc = ll_prep_inode(&de->d_inode, req, NULL, itp);
+ rc = ll_prep_inode(&de->d_inode, &req->rq_pill, NULL, itp);
if (!rc && itp->it_lock_mode) {
__u64 bits = 0;
* of kernel will deal with that later.
*/
ll_set_lock_data(sbi->ll_md_exp, de->d_inode, itp, &bits);
- if (bits & MDS_INODELOCK_LOOKUP)
+ if (bits & MDS_INODELOCK_LOOKUP) {
d_lustre_revalidate(de);
+ ll_update_dir_depth(parent->d_inode, de->d_inode);
+ }
+
/* if DoM bit returned along with LAYOUT bit then there
* can be read-on-open data returned.
*/
ptlrpc_req_finished(req);
ll_intent_drop_lock(itp);
- /* We did open by fid, but by the time we got to the server,
- * the object disappeared. If this is a create, we cannot really
- * tell the userspace that the file it was trying to create
- * does not exist. Instead let's return -ESTALE, and the VFS will
- * retry the create with LOOKUP_REVAL that we are going to catch
- * in ll_revalidate_dentry() and use lookup then.
+ /* We did open by fid, but by the time we got to the server, the object
+ * disappeared. This is possible if the object was unlinked, but it's
+ * also possible if the object was unlinked by a rename. In the case
+ * of an object renamed over our existing one, we can't fail this open.
+ * O_CREAT also goes through this path if we had an existing dentry,
+ * and it's obviously wrong to return ENOENT for O_CREAT.
+ *
+ * Instead let's return -ESTALE, and the VFS will retry the open with
+ * LOOKUP_REVAL, which we catch in ll_revalidate_dentry and fail to
+ * revalidate, causing a lookup. This causes extra lookups in the case
+ * where we had a dentry in cache but the file is being unlinked and we
+ * lose the race with unlink, but this should be very rare.
*/
- if (rc == -ENOENT && itp->it_op & IT_CREAT)
+ if (rc == -ENOENT)
rc = -ESTALE;
RETURN(rc);
file->private_data = fd;
ll_readahead_init(inode, &fd->fd_ras);
fd->fd_omode = it->it_flags & (FMODE_READ | FMODE_WRITE | FMODE_EXEC);
- /* turn off the kernel's read-ahead */
- file->f_ra.ra_pages = 0;
-
- /* ll_cl_context initialize */
- rwlock_init(&fd->fd_lock);
- INIT_LIST_HEAD(&fd->fd_lccs);
RETURN(0);
}
+void ll_track_file_opens(struct inode *inode)
+{
+ struct ll_inode_info *lli = ll_i2info(inode);
+ struct ll_sb_info *sbi = ll_i2sbi(inode);
+
+ /* do not skew results with delays from never-opened inodes */
+ if (ktime_to_ns(lli->lli_close_fd_time))
+ ll_stats_ops_tally(sbi, LPROC_LL_INODE_OPCLTM,
+ ktime_us_delta(ktime_get(), lli->lli_close_fd_time));
+
+ if (ktime_after(ktime_get(),
+ ktime_add_ms(lli->lli_close_fd_time,
+ sbi->ll_oc_max_ms))) {
+ lli->lli_open_fd_count = 1;
+ lli->lli_close_fd_time = ns_to_ktime(0);
+ } else {
+ lli->lli_open_fd_count++;
+ }
+
+ ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_INODE_OCOUNT,
+ lli->lli_open_fd_count);
+}
+
/* Open a file, and (for the very first open) create objects on the OSTs at
* this time. If opened with O_LOV_DELAY_CREATE, then we don't do the object
* creation or open until ll_lov_setstripe() ioctl is called.
file->private_data = NULL; /* prevent ll_local_open assertion */
if (S_ISREG(inode->i_mode)) {
- rc = llcrypt_file_open(inode, file);
- if (rc)
+ rc = ll_file_open_encrypt(inode, file);
+ if (rc) {
+ if (it && it->it_disposition)
+ ll_release_openhandle(file_dentry(file), it);
GOTO(out_nofiledata, rc);
+ }
}
fd = ll_file_data_get();
if (S_ISDIR(inode->i_mode))
ll_authorize_statahead(inode, fd);
+ ll_track_file_opens(inode);
if (is_root_inode(inode)) {
file->private_data = fd;
RETURN(0);
LASSERT(*och_usecount == 0);
if (!it->it_disposition) {
struct dentry *dentry = file_dentry(file);
+ struct ll_sb_info *sbi = ll_i2sbi(inode);
struct ll_dentry_data *ldd;
/* We cannot just request lock handle now, new ELC code
* handle to be returned from LOOKUP|OPEN request,
* for example if the target entry was a symlink.
*
- * Only fetch MDS_OPEN_LOCK if this is in NFS path,
- * marked by a bit set in ll_iget_for_nfs. Clear the
- * bit so that it's not confusing later callers.
+ * In NFS path we know there's pathologic behavior
+ * so we always enable open lock caching when coming
+ * from there. It's detected by setting a flag in
+ * ll_iget_for_nfs.
*
- * NB; when ldd is NULL, it must have come via normal
- * lookup path only, since ll_iget_for_nfs always calls
- * ll_d_init().
+ * After reaching number of opens of this inode
+ * we always ask for an open lock on it to handle
+ * bad userspace actors that open and close files
+ * in a loop for absolutely no good reason
*/
+
ldd = ll_d2d(dentry);
- if (ldd && ldd->lld_nfs_dentry) {
+ if (filename_is_volatile(dentry->d_name.name,
+ dentry->d_name.len,
+ NULL)) {
+ /* There really is nothing here, but this
+ * make this more readable I think.
+ * We do not want openlock for volatile
+ * files under any circumstances
+ */
+ } else if (ldd && ldd->lld_nfs_dentry) {
+ /* NFS path. This also happens to catch
+ * open by fh files I guess
+ */
+ it->it_flags |= MDS_OPEN_LOCK;
+ /* clear the flag for future lookups */
ldd->lld_nfs_dentry = 0;
- if (!filename_is_volatile(dentry->d_name.name,
- dentry->d_name.len,
- NULL))
+ } else if (sbi->ll_oc_thrsh_count > 0) {
+ /* Take MDS_OPEN_LOCK with many opens */
+ if (lli->lli_open_fd_count >=
+ sbi->ll_oc_thrsh_count)
+ it->it_flags |= MDS_OPEN_LOCK;
+
+ /* If this is open after we just closed */
+ else if (ktime_before(ktime_get(),
+ ktime_add_ms(lli->lli_close_fd_time,
+ sbi->ll_oc_thrsh_ms)))
it->it_flags |= MDS_OPEN_LOCK;
}
if (!S_ISREG(inode1->i_mode) || !S_ISREG(inode2->i_mode))
return -EINVAL;
- if (inode_permission(inode1, MAY_WRITE) ||
- inode_permission(inode2, MAY_WRITE))
+ if (inode_permission(&init_user_ns, inode1, MAY_WRITE) ||
+ inode_permission(&init_user_ns, inode2, MAY_WRITE))
return -EPERM;
if (inode1->i_sb != inode2->i_sb)
* POSIX. Solving this problem needs to send an RPC to MDT for each
* read, this will hurt performance.
*/
- if (ll_file_test_and_clear_flag(lli, LLIF_UPDATE_ATIME) ||
+ if (test_and_clear_bit(LLIF_UPDATE_ATIME, &lli->lli_flags) ||
inode->i_atime.tv_sec < lli->lli_atime)
inode->i_atime.tv_sec = lli->lli_atime;
CDEBUG(D_VFSTRACE, DFID" updating i_size %llu\n",
PFID(&lli->lli_fid), attr->cat_size);
+ if (llcrypt_require_key(inode) == -ENOKEY) {
+ /* Without the key, round up encrypted file size to next
+ * LUSTRE_ENCRYPTION_UNIT_SIZE. Clear text size is put in
+ * lli_lazysize for proper file size setting at close time.
+ */
+ lli->lli_attr_valid |= OBD_MD_FLLAZYSIZE;
+ lli->lli_lazysize = attr->cat_size;
+ attr->cat_size = round_up(attr->cat_size,
+ LUSTRE_ENCRYPTION_UNIT_SIZE);
+ }
i_size_write(inode, attr->cat_size);
inode->i_blocks = attr->cat_blocks;
#endif
}
+#ifdef IOCB_NOWAIT
+ io->ci_iocb_nowait = !!(args &&
+ (args->u.normal.via_iocb->ki_flags &
+ IOCB_NOWAIT));
+#endif
+
io->ci_obj = ll_i2info(inode)->lli_clob;
io->ci_lockreq = CILR_MAYBE;
if (ll_file_nolock(file)) {
struct vvp_io *vio = vvp_env_io(env);
struct inode *inode = file_inode(file);
struct ll_inode_info *lli = ll_i2info(inode);
+ struct ll_sb_info *sbi = ll_i2sbi(inode);
struct ll_file_data *fd = file->private_data;
struct range_lock range;
+ bool range_locked = false;
struct cl_io *io;
ssize_t result = 0;
int rc = 0;
+ int rc2 = 0;
unsigned int retried = 0, dio_lock = 0;
bool is_aio = false;
+ bool is_parallel_dio = false;
struct cl_dio_aio *ci_aio = NULL;
+ size_t per_bytes;
+ bool partial_io = false;
+ size_t max_io_pages, max_cached_pages;
ENTRY;
file_dentry(file)->d_name.name,
iot == CIT_READ ? "read" : "write", *ppos, count);
+ max_io_pages = PTLRPC_MAX_BRW_PAGES * OBD_MAX_RIF_DEFAULT;
+ max_cached_pages = sbi->ll_cache->ccc_lru_max;
+ if (max_io_pages > (max_cached_pages >> 2))
+ max_io_pages = max_cached_pages >> 2;
+
io = vvp_env_thread_io(env);
if (file->f_flags & O_DIRECT) {
+ if (file->f_flags & O_APPEND)
+ dio_lock = 1;
if (!is_sync_kiocb(args->u.normal.via_iocb))
is_aio = true;
- ci_aio = cl_aio_alloc(args->u.normal.via_iocb);
+
+ /* the kernel does not support AIO on pipes, and parallel DIO
+ * uses part of the AIO path, so we must not do parallel dio
+ * to pipes
+ */
+ is_parallel_dio = !iov_iter_is_pipe(args->u.normal.via_iter) &&
+ !is_aio;
+
+ if (!ll_sbi_has_parallel_dio(sbi))
+ is_parallel_dio = false;
+
+ ci_aio = cl_aio_alloc(args->u.normal.via_iocb,
+ ll_i2info(inode)->lli_clob, NULL);
if (!ci_aio)
GOTO(out, rc = -ENOMEM);
}
restart:
+ /**
+ * IO block size need be aware of cached page limit, otherwise
+ * if we have small max_cached_mb but large block IO issued, io
+ * could not be finished and blocked whole client.
+ */
+ if (file->f_flags & O_DIRECT)
+ per_bytes = count;
+ else
+ per_bytes = min(max_io_pages << PAGE_SHIFT, count);
+ partial_io = per_bytes < count;
io = vvp_env_thread_io(env);
ll_io_init(io, file, iot, args);
io->ci_aio = ci_aio;
io->ci_dio_lock = dio_lock;
io->ci_ndelay_tried = retried;
+ io->ci_parallel_dio = is_parallel_dio;
- if (cl_io_rw_init(env, io, iot, *ppos, count) == 0) {
- bool range_locked = false;
-
+ if (cl_io_rw_init(env, io, iot, *ppos, per_bytes) == 0) {
if (file->f_flags & O_APPEND)
range_lock_init(&range, 0, LUSTRE_EOF);
else
- range_lock_init(&range, *ppos, *ppos + count - 1);
+ range_lock_init(&range, *ppos, *ppos + per_bytes - 1);
vio->vui_fd = file->private_data;
vio->vui_iter = args->u.normal.via_iter;
range_locked = true;
}
- ll_cl_add(file, env, io, LCC_RW);
+ ll_cl_add(inode, env, io, LCC_RW);
rc = cl_io_loop(env, io);
- ll_cl_remove(file, env);
+ ll_cl_remove(inode, env);
- if (range_locked) {
+ if (range_locked && !is_parallel_dio) {
CDEBUG(D_VFSTRACE, "Range unlock "RL_FMT"\n",
RL_PARA(&range));
range_unlock(&lli->lli_write_tree, &range);
+ range_locked = false;
}
} else {
/* cl_io_rw_init() handled IO */
rc = io->ci_result;
}
+ /* N/B: parallel DIO may be disabled during i/o submission;
+ * if that occurs, async RPCs are resolved before we get here, and this
+ * wait call completes immediately.
+ */
+ if (is_parallel_dio) {
+ struct cl_sync_io *anchor = &io->ci_aio->cda_sync;
+
+ /* for dio, EIOCBQUEUED is an implementation detail,
+ * and we don't return it to userspace
+ */
+ if (rc == -EIOCBQUEUED)
+ rc = 0;
+
+ rc2 = cl_sync_io_wait_recycle(env, anchor, 0, 0);
+ if (rc2 < 0)
+ rc = rc2;
+
+ if (range_locked) {
+ range_unlock(&lli->lli_write_tree, &range);
+ range_locked = false;
+ }
+ }
+
/*
* In order to move forward AIO, ci_nob was increased,
* but that doesn't mean io have been finished, it just
*/
if (io->ci_nob > 0) {
if (!is_aio) {
- result += io->ci_nob;
- *ppos = io->u.ci_wr.wr.crw_pos; /* for splice */
+ if (rc2 == 0) {
+ result += io->ci_nob;
+ *ppos = io->u.ci_wr.wr.crw_pos; /* for splice */
+ } else if (rc2) {
+ result = 0;
+ }
}
count -= io->ci_nob;
/* prepare IO restart */
if (count > 0)
args->u.normal.via_iter = vio->vui_iter;
+
+ if (partial_io) {
+ /**
+ * Reexpand iov count because it was zero
+ * after IO finish.
+ */
+ iov_iter_reexpand(vio->vui_iter, count);
+ if (per_bytes == io->ci_nob)
+ io->ci_need_restart = 1;
+ }
}
out:
cl_io_fini(env, io);
cl_sync_io_note(env, &io->ci_aio->cda_sync,
rc == -EIOCBQUEUED ? 0 : rc);
if (!is_aio) {
- cl_aio_free(io->ci_aio);
+ cl_aio_free(env, io->ci_aio);
io->ci_aio = NULL;
}
}
ktime_t kstart = ktime_get();
bool cached;
+ ENTRY;
+
+ CDEBUG(D_VFSTRACE|D_IOTRACE, "file %s:"DFID", ppos: %lld, count: %zu\n",
+ file_dentry(file)->d_name.name,
+ PFID(ll_inode2fid(file_inode(file))), iocb->ki_pos,
+ iov_iter_count(to));
+
if (!iov_iter_count(to))
- return 0;
+ RETURN(0);
/**
* Currently when PCC read failed, we do not fall back to the
env = cl_env_get(&refcheck);
if (IS_ERR(env))
- return PTR_ERR(env);
+ RETURN(PTR_ERR(env));
args = ll_env_args(env);
args->u.normal.via_iter = to;
ktime_us_delta(ktime_get(), kstart));
}
- return result;
+ CDEBUG(D_IOTRACE,
+ "COMPLETED: file %s:"DFID", ppos: %lld, count: %zu\n",
+ file_dentry(file)->d_name.name,
+ PFID(ll_inode2fid(file_inode(file))), iocb->ki_pos,
+ iov_iter_count(to));
+
+ RETURN(result);
}
/**
if (result > 0) {
ll_heat_add(inode, CIT_WRITE, result);
- ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_WRITE_BYTES,
- result);
- ll_file_set_flag(ll_i2info(inode), LLIF_DATA_MODIFIED);
+ set_bit(LLIF_DATA_MODIFIED, &ll_i2info(inode)->lli_flags);
}
CDEBUG(D_VFSTRACE, "result: %zu, original count %zu\n", result, count);
ENTRY;
+ CDEBUG(D_VFSTRACE|D_IOTRACE, "file %s:"DFID", ppos: %lld, count: %zu\n",
+ file_dentry(file)->d_name.name,
+ PFID(ll_inode2fid(file_inode(file))), iocb->ki_pos,
+ iov_iter_count(from));
+
if (!iov_iter_count(from))
GOTO(out, rc_normal = 0);
env = cl_env_get(&refcheck);
if (IS_ERR(env))
- return PTR_ERR(env);
+ RETURN(PTR_ERR(env));
args = ll_env_args(env);
args->u.normal.via_iter = from;
ktime_us_delta(ktime_get(), kstart));
}
+ CDEBUG(D_IOTRACE,
+ "COMPLETED: file %s:"DFID", ppos: %lld, count: %zu\n",
+ file_dentry(file)->d_name.name,
+ PFID(ll_inode2fid(file_inode(file))), iocb->ki_pos,
+ iov_iter_count(from));
+
RETURN(rc_normal);
}
struct lov_mds_md **lmmp, int *lmm_size,
struct ptlrpc_request **request)
{
- struct ll_sb_info *sbi = ll_i2sbi(inode);
- struct mdt_body *body;
- struct lov_mds_md *lmm = NULL;
- struct ptlrpc_request *req = NULL;
- struct md_op_data *op_data;
- int rc, lmmsize;
+ struct ll_sb_info *sbi = ll_i2sbi(inode);
+ struct mdt_body *body;
+ struct lov_mds_md *lmm = NULL;
+ struct ptlrpc_request *req = NULL;
+ struct md_op_data *op_data;
+ int rc, lmmsize;
+
+ ENTRY;
rc = ll_get_default_mdsize(sbi, &lmmsize);
if (rc)
RETURN(rc);
- op_data = ll_prep_md_op_data(NULL, inode, NULL, filename,
- strlen(filename), lmmsize,
- LUSTRE_OPC_ANY, NULL);
- if (IS_ERR(op_data))
- RETURN(PTR_ERR(op_data));
+ op_data = ll_prep_md_op_data(NULL, inode, NULL, filename,
+ strlen(filename), lmmsize,
+ LUSTRE_OPC_ANY, NULL);
+ if (IS_ERR(op_data))
+ RETURN(PTR_ERR(op_data));
- op_data->op_valid = OBD_MD_FLEASIZE | OBD_MD_FLDIREA;
- rc = md_getattr_name(sbi->ll_md_exp, op_data, &req);
- ll_finish_md_op_data(op_data);
- if (rc < 0) {
- CDEBUG(D_INFO, "md_getattr_name failed "
- "on %s: rc %d\n", filename, rc);
- GOTO(out, rc);
- }
+ op_data->op_valid = OBD_MD_FLEASIZE | OBD_MD_FLDIREA;
+ rc = md_getattr_name(sbi->ll_md_exp, op_data, &req);
+ ll_finish_md_op_data(op_data);
+ if (rc < 0) {
+ CDEBUG(D_INFO, "md_getattr_name failed on %s: rc %d\n",
+ filename, rc);
+ GOTO(out, rc);
+ }
- body = req_capsule_server_get(&req->rq_pill, &RMF_MDT_BODY);
- LASSERT(body != NULL); /* checked by mdc_getattr_name */
+ body = req_capsule_server_get(&req->rq_pill, &RMF_MDT_BODY);
+ LASSERT(body != NULL); /* checked by mdc_getattr_name */
lmmsize = body->mbo_eadatasize;
if (!(body->mbo_valid & (OBD_MD_FLEASIZE | OBD_MD_FLDIREA)) ||
- lmmsize == 0) {
- GOTO(out, rc = -ENODATA);
- }
+ lmmsize == 0)
+ GOTO(out, rc = -ENODATA);
- lmm = req_capsule_server_sized_get(&req->rq_pill, &RMF_MDT_MD, lmmsize);
- LASSERT(lmm != NULL);
+ lmm = req_capsule_server_sized_get(&req->rq_pill, &RMF_MDT_MD, lmmsize);
+ LASSERT(lmm != NULL);
if (lmm->lmm_magic != cpu_to_le32(LOV_MAGIC_V1) &&
lmm->lmm_magic != cpu_to_le32(LOV_MAGIC_V3) &&
/*
* This is coming from the MDS, so is probably in
- * little endian. We convert it to host endian before
+ * little endian. We convert it to host endian before
* passing it to userspace.
*/
- if ((lmm->lmm_magic & __swab32(LOV_MAGIC_MAGIC)) ==
- __swab32(LOV_MAGIC_MAGIC)) {
+ if (cpu_to_le32(LOV_MAGIC) != LOV_MAGIC) {
int stripe_count = 0;
if (lmm->lmm_magic == cpu_to_le32(LOV_MAGIC_V1) ||
if (le32_to_cpu(lmm->lmm_pattern) &
LOV_PATTERN_F_RELEASED)
stripe_count = 0;
- }
-
- lustre_swab_lov_user_md((struct lov_user_md *)lmm, 0);
+ lustre_swab_lov_user_md((struct lov_user_md *)lmm, 0);
- /* if function called for directory - we should
- * avoid swab not existent lsm objects */
- if (lmm->lmm_magic == LOV_MAGIC_V1 && S_ISREG(body->mbo_mode))
- lustre_swab_lov_user_md_objects(
+ /* if function called for directory - we should
+ * avoid swab not existent lsm objects
+ */
+ if (lmm->lmm_magic == LOV_MAGIC_V1 &&
+ S_ISREG(body->mbo_mode))
+ lustre_swab_lov_user_md_objects(
((struct lov_user_md_v1 *)lmm)->lmm_objects,
stripe_count);
- else if (lmm->lmm_magic == LOV_MAGIC_V3 &&
- S_ISREG(body->mbo_mode))
- lustre_swab_lov_user_md_objects(
+ else if (lmm->lmm_magic == LOV_MAGIC_V3 &&
+ S_ISREG(body->mbo_mode))
+ lustre_swab_lov_user_md_objects(
((struct lov_user_md_v3 *)lmm)->lmm_objects,
stripe_count);
+ } else if (lmm->lmm_magic == cpu_to_le32(LOV_MAGIC_COMP_V1)) {
+ lustre_swab_lov_comp_md_v1(
+ (struct lov_comp_md_v1 *)lmm);
+ }
}
+ if (lmm->lmm_magic == LOV_MAGIC_COMP_V1) {
+ struct lov_comp_md_v1 *comp_v1 = NULL;
+ struct lov_comp_md_entry_v1 *ent;
+ struct lov_user_md_v1 *v1;
+ __u32 off;
+ int i = 0;
+
+ comp_v1 = (struct lov_comp_md_v1 *)lmm;
+ /* Dump the striping information */
+ for (; i < comp_v1->lcm_entry_count; i++) {
+ ent = &comp_v1->lcm_entries[i];
+ off = ent->lcme_offset;
+ v1 = (struct lov_user_md_v1 *)((char *)lmm + off);
+ CDEBUG(D_INFO,
+ "comp[%d]: stripe_count=%u, stripe_size=%u\n",
+ i, v1->lmm_stripe_count, v1->lmm_stripe_size);
+ }
+
+ /**
+ * Return valid stripe_count and stripe_size instead of 0 for
+ * DoM files to avoid divide-by-zero for older userspace that
+ * calls this ioctl, e.g. lustre ADIO driver.
+ */
+ if (lmm->lmm_stripe_count == 0)
+ lmm->lmm_stripe_count = 1;
+ if (lmm->lmm_stripe_size == 0) {
+ /* Since the first component of the file data is placed
+ * on the MDT for faster access, the stripe_size of the
+ * second one is always that applications which are
+ * doing large IOs.
+ */
+ if (lmm->lmm_pattern == LOV_PATTERN_MDT)
+ i = comp_v1->lcm_entry_count > 1 ? 1 : 0;
+ else
+ i = comp_v1->lcm_entry_count > 1 ?
+ comp_v1->lcm_entry_count - 1 : 0;
+ ent = &comp_v1->lcm_entries[i];
+ off = ent->lcme_offset;
+ v1 = (struct lov_user_md_v1 *)((char *)lmm + off);
+ lmm->lmm_stripe_size = v1->lmm_stripe_size;
+ }
+ }
out:
*lmmp = lmm;
*lmm_size = lmmsize;
*request = req;
- return rc;
+ RETURN(rc);
}
static int ll_lov_setea(struct inode *inode, struct file *file,
int rc;
ENTRY;
- if (!cfs_capable(CAP_SYS_ADMIN))
+ if (!capable(CAP_SYS_ADMIN))
RETURN(-EPERM);
OBD_ALLOC_LARGE(lump, lum_size);
GOTO(out, rc);
}
- fmkey.lfik_oa.o_valid = OBD_MD_FLID | OBD_MD_FLGROUP;
+ fmkey.lfik_oa.o_valid = OBD_MD_FLID | OBD_MD_FLGROUP | OBD_MD_FLPROJID;
obdo_from_inode(&fmkey.lfik_oa, inode, OBD_MD_FLSIZE);
obdo_set_parent_fid(&fmkey.lfik_oa, &ll_i2info(inode)->lli_fid);
ENTRY;
- if (!cfs_capable(CAP_DAC_READ_SEARCH) &&
- !(ll_i2sbi(inode)->ll_flags & LL_SBI_USER_FID2PATH))
+ if (!capable(CAP_DAC_READ_SEARCH) &&
+ !test_bit(LL_SBI_USER_FID2PATH, ll_i2sbi(inode)->ll_flags))
RETURN(-EPERM);
/* Only need to get the buflen */
struct lu_env *env;
struct obd_client_handle *och = NULL;
__u64 data_version = 0;
- int rc;
__u16 refcheck;
+ int rc;
+
ENTRY;
CDEBUG(D_INODE, "%s: Releasing file "DFID".\n",
GOTO(out, rc = PTR_ERR(och));
/* Grab latest data_version and [am]time values */
- rc = ll_data_version(inode, &data_version, LL_DV_WR_FLUSH);
+ rc = ll_data_version(inode, &data_version,
+ LL_DV_WR_FLUSH | LL_DV_SZ_UPDATE);
if (rc != 0)
GOTO(out, rc);
/* Non-root users are forbidden to set or clear flags which are
* NOT defined in HSM_USER_MASK. */
if (((hss->hss_setmask | hss->hss_clearmask) & ~HSM_USER_MASK) &&
- !cfs_capable(CAP_SYS_ADMIN))
+ !capable(CAP_SYS_ADMIN))
RETURN(-EPERM);
if (!exp_connect_archive_id_array(exp)) {
descr->cld_mode = cl_mode;
/* CEF_MUST is used because we do not want to convert a
* lockahead request to a lockless lock */
- descr->cld_enq_flags = CEF_MUST | CEF_LOCK_NO_EXPAND |
- CEF_NONBLOCK;
+ descr->cld_enq_flags = CEF_MUST | CEF_LOCK_NO_EXPAND;
if (ladvise->lla_peradvice_flags & LF_ASYNC)
descr->cld_enq_flags |= CEF_SPECULATIVE;
ladvise_names[advice], rc);
GOTO(out, rc);
}
- /* fallthrough */
+ fallthrough;
case LU_LADVISE_WILLREAD:
case LU_LADVISE_DONTNEED:
default:
RETURN(-EFAULT);
fsxattr.fsx_xflags = ll_inode_flags_to_xflags(inode->i_flags);
- if (ll_file_test_flag(ll_i2info(inode), LLIF_PROJECT_INHERIT))
+ if (test_bit(LLIF_PROJECT_INHERIT, &ll_i2info(inode)->lli_flags))
fsxattr.fsx_xflags |= FS_XFLAG_PROJINHERIT;
fsxattr.fsx_projid = ll_i2info(inode)->lli_projid;
if (copy_to_user((struct fsxattr __user *)arg,
RETURN(0);
}
-int ll_ioctl_check_project(struct inode *inode, struct fsxattr *fa)
+int ll_ioctl_check_project(struct inode *inode, __u32 xflags,
+ __u32 projid)
{
/*
* Project Quota ID state is only allowed to change from within the init
* namespace. Enforce that restriction only if we are trying to change
* the quota ID state. Everything else is allowed in user namespaces.
*/
- if (current_user_ns() == &init_user_ns)
+ if (current_user_ns() == &init_user_ns) {
+ /*
+ * Caller is allowed to change the project ID. if it is being
+ * changed, make sure that the new value is valid.
+ */
+ if (ll_i2info(inode)->lli_projid != projid &&
+ !projid_valid(make_kprojid(&init_user_ns, projid)))
+ return -EINVAL;
+
return 0;
+ }
- if (ll_i2info(inode)->lli_projid != fa->fsx_projid)
+ if (ll_i2info(inode)->lli_projid != projid)
return -EINVAL;
- if (ll_file_test_flag(ll_i2info(inode), LLIF_PROJECT_INHERIT)) {
- if (!(fa->fsx_xflags & FS_XFLAG_PROJINHERIT))
+ if (test_bit(LLIF_PROJECT_INHERIT, &ll_i2info(inode)->lli_flags)) {
+ if (!(xflags & FS_XFLAG_PROJINHERIT))
return -EINVAL;
} else {
- if (fa->fsx_xflags & FS_XFLAG_PROJINHERIT)
+ if (xflags & FS_XFLAG_PROJINHERIT)
return -EINVAL;
}
return 0;
}
-int ll_ioctl_fssetxattr(struct inode *inode, unsigned int cmd,
- unsigned long arg)
+static int ll_set_project(struct inode *inode, __u32 xflags, __u32 projid)
{
- struct md_op_data *op_data;
struct ptlrpc_request *req = NULL;
- struct fsxattr fsxattr;
+ struct md_op_data *op_data;
struct cl_object *obj;
unsigned int inode_flags;
int rc = 0;
- if (copy_from_user(&fsxattr,
- (const struct fsxattr __user *)arg,
- sizeof(fsxattr)))
- RETURN(-EFAULT);
-
- rc = ll_ioctl_check_project(inode, &fsxattr);
+ CDEBUG(D_QUOTA, DFID" xflags=%x projid=%u\n",
+ PFID(ll_inode2fid(inode)), xflags, projid);
+ rc = ll_ioctl_check_project(inode, xflags, projid);
if (rc)
RETURN(rc);
if (IS_ERR(op_data))
RETURN(PTR_ERR(op_data));
- inode_flags = ll_xflags_to_inode_flags(fsxattr.fsx_xflags);
+ inode_flags = ll_xflags_to_inode_flags(xflags);
op_data->op_attr_flags = ll_inode_to_ext_flags(inode_flags);
- if (fsxattr.fsx_xflags & FS_XFLAG_PROJINHERIT)
+ if (xflags & FS_XFLAG_PROJINHERIT)
op_data->op_attr_flags |= LUSTRE_PROJINHERIT_FL;
- op_data->op_projid = fsxattr.fsx_projid;
+
+ /* pass projid to md_op_data */
+ op_data->op_projid = projid;
+
op_data->op_xvalid |= OP_XVALID_PROJID | OP_XVALID_FLAGS;
rc = md_setattr(ll_i2sbi(inode)->ll_md_exp, op_data, NULL, 0, &req);
ptlrpc_req_finished(req);
ll_update_inode_flags(inode, op_data->op_attr_flags);
/* Avoid OST RPC if this is only ioctl setting project inherit flag */
- if (fsxattr.fsx_xflags == 0 ||
- fsxattr.fsx_xflags == FS_XFLAG_PROJINHERIT)
+ if (xflags == 0 || xflags == FS_XFLAG_PROJINHERIT)
GOTO(out_fsxattr, rc);
obj = ll_i2info(inode)->lli_clob;
if (obj) {
struct iattr attr = { 0 };
- rc = cl_setattr_ost(obj, &attr, OP_XVALID_FLAGS,
- fsxattr.fsx_xflags);
+ rc = cl_setattr_ost(obj, &attr, OP_XVALID_FLAGS, xflags);
}
out_fsxattr:
RETURN(rc);
}
+int ll_ioctl_fssetxattr(struct inode *inode, unsigned int cmd,
+ unsigned long arg)
+{
+ struct fsxattr fsxattr;
+
+ ENTRY;
+
+ if (copy_from_user(&fsxattr,
+ (const struct fsxattr __user *)arg,
+ sizeof(fsxattr)))
+ RETURN(-EFAULT);
+
+ RETURN(ll_set_project(inode, fsxattr.fsx_xflags,
+ fsxattr.fsx_projid));
+}
+
+int ll_ioctl_project(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ struct lu_project lu_project;
+ struct dentry *dentry = file_dentry(file);
+ struct inode *inode = file_inode(file);
+ struct dentry *child_dentry = NULL;
+ int rc = 0, name_len;
+
+ if (copy_from_user(&lu_project,
+ (const struct lu_project __user *)arg,
+ sizeof(lu_project)))
+ RETURN(-EFAULT);
+
+ /* apply child dentry if name is valid */
+ name_len = strnlen(lu_project.project_name, NAME_MAX);
+ if (name_len > 0 && name_len <= NAME_MAX) {
+ inode_lock(inode);
+ child_dentry = lookup_one_len(lu_project.project_name,
+ dentry, name_len);
+ inode_unlock(inode);
+ if (IS_ERR(child_dentry)) {
+ rc = PTR_ERR(child_dentry);
+ goto out;
+ }
+ inode = child_dentry->d_inode;
+ if (!inode) {
+ rc = -ENOENT;
+ goto out;
+ }
+ } else if (name_len > NAME_MAX) {
+ rc = -EINVAL;
+ goto out;
+ }
+
+ switch (lu_project.project_type) {
+ case LU_PROJECT_SET:
+ rc = ll_set_project(inode, lu_project.project_xflags,
+ lu_project.project_id);
+ break;
+ case LU_PROJECT_GET:
+ lu_project.project_xflags =
+ ll_inode_flags_to_xflags(inode->i_flags);
+ if (test_bit(LLIF_PROJECT_INHERIT,
+ &ll_i2info(inode)->lli_flags))
+ lu_project.project_xflags |= FS_XFLAG_PROJINHERIT;
+ lu_project.project_id = ll_i2info(inode)->lli_projid;
+ if (copy_to_user((struct lu_project __user *)arg,
+ &lu_project, sizeof(lu_project))) {
+ rc = -EFAULT;
+ goto out;
+ }
+ break;
+ default:
+ rc = -EINVAL;
+ break;
+ }
+out:
+ if (!IS_ERR_OR_NULL(child_dentry))
+ dput(child_dentry);
+ RETURN(rc);
+}
+
static long ll_file_unlock_lease(struct file *file, struct ll_ioc_lease *ioc,
unsigned long arg)
{
if (!layout_file)
GOTO(out_lease_close, rc = -EBADF);
+ /* if layout_file == file, it means to destroy the mirror */
sp.sp_inode = file_inode(layout_file);
sp.sp_mirror_id = (__u16)mirror_id;
data = &sp;
if (ioc->lil_count != 1)
RETURN(-EINVAL);
+ if (IS_ENCRYPTED(inode))
+ RETURN(-EOPNOTSUPP);
+
arg += sizeof(*ioc);
if (copy_from_user(¶m.pa_archive_id, (void __user *)arg,
sizeof(__u32)))
case LL_LEASE_LAYOUT_SPLIT:
if (layout_file)
fput(layout_file);
+
+ ll_layout_refresh(inode, &fd->fd_layout_version);
break;
case LL_LEASE_PCC_ATTACH:
if (!rc)
RETURN(0);
}
+ case OBD_IOC_GETNAME_OLD:
case OBD_IOC_GETDTNAME:
case OBD_IOC_GETMDNAME:
RETURN(ll_get_obd_name(inode, cmd, arg));
RETURN(rc);
}
case LL_IOC_HSM_ACTION: {
- struct md_op_data *op_data;
- struct hsm_current_action *hca;
- int rc;
+ struct md_op_data *op_data;
+ struct hsm_current_action *hca;
+ const char *action;
+ int rc;
OBD_ALLOC_PTR(hca);
if (hca == NULL)
rc = obd_iocontrol(cmd, ll_i2mdexp(inode), sizeof(*op_data),
op_data, NULL);
+ if (rc < 0)
+ GOTO(skip_copy, rc);
+
+ /* The hsm_current_action retreived from the server could
+ * contain corrupt information. If it is incorrect data collect
+ * debug information. We still send the data even if incorrect
+ * to user land to handle.
+ */
+ action = hsm_user_action2name(hca->hca_action);
+ if (strcmp(action, "UNKNOWN") == 0 ||
+ hca->hca_state > HPS_DONE) {
+ CDEBUG(D_HSM,
+ "HSM current state %s action %s, offset = %llu, length %llu\n",
+ hsm_progress_state2name(hca->hca_state), action,
+ hca->hca_location.offset, hca->hca_location.length);
+ }
if (copy_to_user((char __user *)arg, hca, sizeof(*hca)))
rc = -EFAULT;
-
+skip_copy:
ll_finish_md_op_data(op_data);
OBD_FREE_PTR(hca);
RETURN(rc);
RETURN(ll_ioctl_fsgetxattr(inode, cmd, arg));
case FS_IOC_FSSETXATTR:
RETURN(ll_ioctl_fssetxattr(inode, cmd, arg));
+ case LL_IOC_PROJECT:
+ RETURN(ll_ioctl_project(file, cmd, arg));
case BLKSSZGET:
RETURN(put_user(PAGE_SIZE, (int __user *)arg));
case LL_IOC_HEAT_GET: {
if (!S_ISREG(inode->i_mode))
GOTO(out_detach_free, rc = -EINVAL);
- if (!inode_owner_or_capable(inode))
+ if (!inode_owner_or_capable(&init_user_ns, inode))
GOTO(out_detach_free, rc = -EPERM);
rc = pcc_ioctl_detach(inode, detach->pccd_opt);
}
}
-loff_t ll_lseek(struct inode *inode, loff_t offset, int whence)
+loff_t ll_lseek(struct file *file, loff_t offset, int whence)
{
+ struct inode *inode = file_inode(file);
struct lu_env *env;
struct cl_io *io;
struct cl_lseek_io *lsio;
io = vvp_env_thread_io(env);
io->ci_obj = ll_i2info(inode)->lli_clob;
+ ll_io_set_mirror(io, file);
lsio = &io->u.ci_lseek;
lsio->ls_start = offset;
do {
rc = cl_io_init(env, io, CIT_LSEEK, io->ci_obj);
- if (!rc)
+ if (!rc) {
+ struct vvp_io *vio = vvp_env_io(env);
+
+ vio->vui_fd = file->private_data;
rc = cl_io_loop(env, io);
- else
+ } else {
rc = io->ci_result;
+ }
retval = rc ? : lsio->ls_result;
cl_io_fini(env, io);
} while (unlikely(io->ci_need_restart));
cl_env_put(env, &refcheck);
+ /* Without the key, SEEK_HOLE return value has to be
+ * rounded up to next LUSTRE_ENCRYPTION_UNIT_SIZE.
+ */
+ if (llcrypt_require_key(inode) == -ENOKEY && whence == SEEK_HOLE)
+ retval = round_up(retval, LUSTRE_ENCRYPTION_UNIT_SIZE);
+
RETURN(retval);
}
cl_sync_file_range(inode, offset, OBD_OBJECT_EOF,
CL_FSYNC_LOCAL, 0);
- retval = ll_lseek(inode, offset, origin);
+ retval = ll_lseek(file, offset, origin);
if (retval < 0)
return retval;
retval = vfs_setpos(file, retval, ll_file_maxbytes(inode));
/* fsync's caller has already called _fdata{sync,write}, we want
* that IO to finish before calling the osc and mdc sync methods */
rc = filemap_write_and_wait_range(inode->i_mapping, start, end);
- inode_lock(inode);
/* catch async errors that were recorded back when async writeback
* failed for pages in this mapping. */
fd->fd_write_failed = false;
}
- inode_unlock(inode);
-
if (!rc)
ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_FSYNC,
ktime_us_delta(ktime_get(), kstart));
int namelen, struct lu_fid *fid,
struct inode **inode)
{
- struct md_op_data *op_data = NULL;
- struct mdt_body *body;
- struct ptlrpc_request *req;
- int rc;
+ struct md_op_data *op_data = NULL;
+ struct mdt_body *body;
+ struct ptlrpc_request *req;
+ int rc;
ENTRY;
op_data = ll_prep_md_op_data(NULL, parent, NULL, name, namelen, 0,
*fid = body->mbo_fid1;
if (inode != NULL)
- rc = ll_prep_inode(inode, req, parent->i_sb, NULL);
+ rc = ll_prep_inode(inode, &req->rq_pill, parent->i_sb, NULL);
out_req:
ptlrpc_req_finished(req);
RETURN(rc);
}
int ll_migrate(struct inode *parent, struct file *file, struct lmv_user_md *lum,
- const char *name)
+ const char *name, __u32 flags)
{
struct dentry *dchild = NULL;
struct inode *child_inode = NULL;
op_data->op_data = lum;
op_data->op_data_size = lumlen;
+ /* migrate dirent only for subdirs if MDS_MIGRATE_NSONLY set */
+ if (S_ISDIR(child_inode->i_mode) && (flags & MDS_MIGRATE_NSONLY) &&
+ lmv_dir_layout_changing(ll_i2info(parent)->lli_lsm_md))
+ op_data->op_bias |= MDS_MIGRATE_NSONLY;
+
again:
if (S_ISREG(child_inode->i_mode)) {
och = ll_lease_open(child_inode, NULL, FMODE_WRITE, 0);
spin_unlock(&och->och_mod->mod_open_req->rq_lock);
}
- rc = md_rename(ll_i2sbi(parent)->ll_md_exp, op_data, name, namelen,
- name, namelen, &request);
+ rc = md_rename(ll_i2sbi(parent)->ll_md_exp, op_data,
+ op_data->op_name, op_data->op_namelen,
+ op_data->op_name, op_data->op_namelen, &request);
if (rc == 0) {
LASSERT(request != NULL);
ll_update_times(request, parent);
*/
if (!(fd->fd_flags & LL_FILE_FLOCK_WARNING)) {
fd->fd_flags |= LL_FILE_FLOCK_WARNING;
- CDEBUG_LIMIT(D_TTY | D_CONSOLE,
+ CDEBUG_LIMIT(D_CONSOLE,
"flock disabled, mount with '-o [local]flock' to enable\r\n");
}
RETURN(-ENOSYS);
struct cl_attr attr = { 0 };
int rc;
- LASSERT(lli->lli_lsm_md != NULL);
-
- if (!lmv_dir_striped(lli->lli_lsm_md))
+ if (!lli->lli_lsm_md)
RETURN(0);
down_read(&lli->lli_lsm_sem);
+ if (!lmv_dir_striped(lli->lli_lsm_md)) {
+ up_read(&lli->lli_lsm_sem);
+ RETURN(0);
+ }
rc = md_merge_attr(ll_i2mdexp(inode), ll_i2info(inode)->lli_lsm_md,
&attr, ll_md_blocking_ast);
up_read(&lli->lli_lsm_sem);
if (rc != 0)
RETURN(rc);
+ spin_lock(&inode->i_lock);
set_nlink(inode, attr.cat_nlink);
+ spin_unlock(&inode->i_lock);
+
inode->i_blocks = attr.cat_blocks;
i_size_write(inode, attr.cat_size);
* restore the MDT holds the layout lock so the glimpse will
* block up to the end of restore (getattr will block)
*/
- if (!ll_file_test_flag(lli, LLIF_FILE_RESTORING)) {
+ if (!test_bit(LLIF_FILE_RESTORING, &lli->lli_flags)) {
rc = ll_glimpse_size(inode);
if (rc < 0)
RETURN(rc);
stat->size = i_size_read(inode);
stat->blocks = inode->i_blocks;
-#ifdef HAVE_INODEOPS_ENHANCED_GETATTR
+#if defined(HAVE_USER_NAMESPACE_ARG) || defined(HAVE_INODEOPS_ENHANCED_GETATTR)
if (flags & AT_STATX_DONT_SYNC) {
if (stat->size == 0 &&
lli->lli_attr_valid & OBD_MD_FLLAZYSIZE)
return 0;
}
-#ifdef HAVE_INODEOPS_ENHANCED_GETATTR
-int ll_getattr(const struct path *path, struct kstat *stat,
- u32 request_mask, unsigned int flags)
+#if defined(HAVE_USER_NAMESPACE_ARG) || defined(HAVE_INODEOPS_ENHANCED_GETATTR)
+int ll_getattr(struct user_namespace *mnt_userns, const struct path *path,
+ struct kstat *stat, u32 request_mask, unsigned int flags)
{
return ll_getattr_dentry(path->dentry, stat, request_mask, flags,
false);
}
#endif
-int cl_falloc(struct inode *inode, int mode, loff_t offset, loff_t len)
+int cl_falloc(struct file *file, struct inode *inode, int mode, loff_t offset,
+ loff_t len)
{
+ loff_t size = i_size_read(inode);
struct lu_env *env;
struct cl_io *io;
__u16 refcheck;
- int rc; loff_t sa_falloc_end;
- loff_t size = i_size_read(inode);
+ int rc;
ENTRY;
io = vvp_env_thread_io(env);
io->ci_obj = ll_i2info(inode)->lli_clob;
+ ll_io_set_mirror(io, file);
+
io->ci_verify_layout = 1;
io->u.ci_setattr.sa_parent_fid = lu_object_fid(&io->ci_obj->co_lu);
io->u.ci_setattr.sa_falloc_mode = mode;
io->u.ci_setattr.sa_falloc_offset = offset;
- io->u.ci_setattr.sa_falloc_len = len;
- io->u.ci_setattr.sa_falloc_end = io->u.ci_setattr.sa_falloc_offset +
- io->u.ci_setattr.sa_falloc_len;
+ io->u.ci_setattr.sa_falloc_end = offset + len;
io->u.ci_setattr.sa_subtype = CL_SETATTR_FALLOCATE;
- sa_falloc_end = io->u.ci_setattr.sa_falloc_end;
- if (sa_falloc_end > size) {
+
+ CDEBUG(D_INODE, "UID %u GID %u PRJID %u\n",
+ from_kuid(&init_user_ns, inode->i_uid),
+ from_kgid(&init_user_ns, inode->i_gid),
+ ll_i2info(inode)->lli_projid);
+
+ io->u.ci_setattr.sa_falloc_uid = from_kuid(&init_user_ns, inode->i_uid);
+ io->u.ci_setattr.sa_falloc_gid = from_kgid(&init_user_ns, inode->i_gid);
+ io->u.ci_setattr.sa_falloc_projid = ll_i2info(inode)->lli_projid;
+
+ if (io->u.ci_setattr.sa_falloc_end > size) {
+ loff_t newsize = io->u.ci_setattr.sa_falloc_end;
+
/* Check new size against VFS/VM file size limit and rlimit */
- rc = inode_newsize_ok(inode, sa_falloc_end);
+ rc = inode_newsize_ok(inode, newsize);
if (rc)
goto out;
- if (sa_falloc_end > ll_file_maxbytes(inode)) {
+ if (newsize > ll_file_maxbytes(inode)) {
CDEBUG(D_INODE, "file size too large %llu > %llu\n",
- (unsigned long long)(sa_falloc_end),
+ (unsigned long long)newsize,
ll_file_maxbytes(inode));
rc = -EFBIG;
goto out;
}
- io->u.ci_setattr.sa_attr.lvb_size = sa_falloc_end;
- if (!(mode & FALLOC_FL_KEEP_SIZE))
- io->u.ci_setattr.sa_avalid |= ATTR_SIZE;
- } else {
- io->u.ci_setattr.sa_attr.lvb_size = size;
}
-again:
- if (cl_io_init(env, io, CIT_SETATTR, io->ci_obj) == 0)
- rc = cl_io_loop(env, io);
- else
- rc = io->ci_result;
-
- cl_io_fini(env, io);
- if (unlikely(io->ci_need_restart))
- goto again;
+ do {
+ rc = cl_io_init(env, io, CIT_SETATTR, io->ci_obj);
+ if (!rc)
+ rc = cl_io_loop(env, io);
+ else
+ rc = io->ci_result;
+ cl_io_fini(env, io);
+ } while (unlikely(io->ci_need_restart));
out:
cl_env_put(env, &refcheck);
long ll_fallocate(struct file *filp, int mode, loff_t offset, loff_t len)
{
- struct inode *inode = filp->f_path.dentry->d_inode;
+ struct inode *inode = file_inode(filp);
int rc;
+ if (offset < 0 || len <= 0)
+ RETURN(-EINVAL);
/*
* Encrypted inodes can't handle collapse range or zero range or insert
* range since we would need to re-encrypt blocks with a different IV or
RETURN(-EOPNOTSUPP);
/*
- * Only mode == 0 (which is standard prealloc) is supported now.
- * Punch is not supported yet.
+ * mode == 0 (which is standard prealloc) and PUNCH is supported
+ * Rest of mode options are not supported yet.
*/
- if (mode & ~FALLOC_FL_KEEP_SIZE)
+ if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE))
RETURN(-EOPNOTSUPP);
ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_FALLOCATE, 1);
- rc = cl_falloc(inode, mode, offset, len);
+ rc = cl_falloc(filp, inode, mode, offset, len);
/*
* ENOTSUPP (524) is an NFSv3 specific error code erroneously
* used by Lustre in several places. Retuning it here would
return rc;
}
-int ll_inode_permission(struct inode *inode, int mask)
+int ll_inode_permission(struct user_namespace *mnt_userns, struct inode *inode,
+ int mask)
{
int rc = 0;
struct ll_sb_info *sbi;
struct root_squash_info *squash;
struct cred *cred = NULL;
const struct cred *old_cred = NULL;
- cfs_cap_t cap;
bool squash_id = false;
ktime_t kstart = ktime_get();
squash = &sbi->ll_squash;
if (unlikely(squash->rsi_uid != 0 &&
uid_eq(current_fsuid(), GLOBAL_ROOT_UID) &&
- !(sbi->ll_flags & LL_SBI_NOROOTSQUASH))) {
+ !test_bit(LL_SBI_NOROOTSQUASH, sbi->ll_flags))) {
squash_id = true;
}
if (squash_id) {
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 (BIT(cap) & CFS_CAP_FS_MASK)
- cap_lower(cred->cap_effective, cap);
- }
+ cred->cap_effective = cap_drop_nfsd_set(cred->cap_effective);
+ cred->cap_effective = cap_drop_fs_set(cred->cap_effective);
+
old_cred = override_creds(cred);
}
- rc = generic_permission(inode, mask);
+ rc = generic_permission(mnt_userns, inode, mask);
/* restore current process's credentials and FS capability */
if (squash_id) {
revert_creds(old_cred);
}
/* -o localflock - only provides locally consistent flock locks */
-const struct file_operations ll_file_operations = {
+static const struct file_operations ll_file_operations = {
#ifdef HAVE_FILE_OPERATIONS_READ_WRITE_ITER
# ifdef HAVE_SYNC_READ_WRITE
.read = new_sync_read,
.fallocate = ll_fallocate,
};
-const struct file_operations ll_file_operations_flock = {
+static const struct file_operations ll_file_operations_flock = {
#ifdef HAVE_FILE_OPERATIONS_READ_WRITE_ITER
# ifdef HAVE_SYNC_READ_WRITE
.read = new_sync_read,
};
/* These are for -o noflock - to return ENOSYS on flock calls */
-const struct file_operations ll_file_operations_noflock = {
+static const struct file_operations ll_file_operations_noflock = {
#ifdef HAVE_FILE_OPERATIONS_READ_WRITE_ITER
# ifdef HAVE_SYNC_READ_WRITE
.read = new_sync_read,
#endif
};
+const struct file_operations *ll_select_file_operations(struct ll_sb_info *sbi)
+{
+ const struct file_operations *fops = &ll_file_operations_noflock;
+
+ if (test_bit(LL_SBI_FLOCK, sbi->ll_flags))
+ fops = &ll_file_operations_flock;
+ else if (test_bit(LL_SBI_LOCALFLOCK, sbi->ll_flags))
+ fops = &ll_file_operations;
+
+ return fops;
+}
+
int ll_layout_conf(struct inode *inode, const struct cl_object_conf *conf)
{
struct ll_inode_info *lli = ll_i2info(inode);
lock = ldlm_handle2lock(lockh);
LASSERT(lock != NULL);
- LASSERT(ldlm_has_layout(lock));
+
+ if (!ldlm_has_layout(lock))
+ GOTO(out, rc = -EAGAIN);
LDLM_DEBUG(lock, "file "DFID"(%p) being reconfigured",
PFID(&lli->lli_fid), inode);
ENTRY;
*gen = ll_layout_version_get(lli);
- if (!(sbi->ll_flags & LL_SBI_LAYOUT_LOCK) || *gen != CL_LAYOUT_GEN_NONE)
+ if (!test_bit(LL_SBI_LAYOUT_LOCK, sbi->ll_flags) ||
+ *gen != CL_LAYOUT_GEN_NONE)
RETURN(0);
/* sanity checks */