Add ablity to get/set non-dir/file's project ID and state.
Signed-off-by: Wang Shilong <wshilong@ddn.com>
Change-Id: Ib8eee09254f9751797b5deb7f753c34eb2c0d5a5
Reviewed-on: https://review.whamcloud.com/44006
Tested-by: jenkins <devops@whamcloud.com>
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
Reviewed-by: Alexander Zarochentsev <alexander.zarochentsev@hpe.com>
Tested-by: Maloo <maloo@whamcloud.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
#define LL_IOC_PCC_DETACH _IOW('f', 252, struct lu_pcc_detach)
#define LL_IOC_PCC_DETACH_BY_FID _IOW('f', 252, struct lu_pcc_detach_fid)
#define LL_IOC_PCC_STATE _IOR('f', 252, struct lu_pcc_state)
+#define LL_IOC_PROJECT _IOW('f', 253, struct lu_project)
#ifndef FS_IOC_FSGETXATTR
/*
char pccs_path[PATH_MAX];
};
+enum lu_project_type {
+ LU_PROJECT_NONE = 0,
+ LU_PROJECT_SET,
+ LU_PROJECT_GET,
+ LU_PROJECT_MAX
+};
+
+struct lu_project {
+ __u32 project_type; /* enum lu_project_type */
+ __u32 project_id;
+ __u32 project_xflags;
+ __u32 project_reserved;
+ char project_name[NAME_MAX + 1];
+};
+
struct fid_array {
__u32 fa_nr;
/* make header's size equal lu_fid */
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 LL_IOC_PCC_DETACH_BY_FID: {
struct lu_pcc_detach_fid *detach;
struct lu_fid *fid;
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
if (current_user_ns() == &init_user_ns)
return 0;
- if (ll_i2info(inode)->lli_projid != fa->fsx_projid)
+ if (ll_i2info(inode)->lli_projid != projid)
return -EINVAL;
if (test_bit(LLIF_PROJECT_INHERIT, &ll_i2info(inode)->lli_flags)) {
- if (!(fa->fsx_xflags & FS_XFLAG_PROJINHERIT))
+ 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 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);
+ 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;
+ 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)
{
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: {
int ll_get_fid_by_name(struct inode *parent, const char *name,
int namelen, struct lu_fid *fid, struct inode **inode);
int ll_inode_permission(struct inode *inode, int mask);
-int ll_ioctl_check_project(struct inode *inode, struct fsxattr *fa);
+int ll_ioctl_check_project(struct inode *inode, __u32 xflags, __u32 projid);
int ll_ioctl_fsgetxattr(struct inode *inode, unsigned int cmd,
unsigned long arg);
int ll_ioctl_fssetxattr(struct inode *inode, unsigned int cmd,
unsigned long arg);
+int ll_ioctl_project(struct file *file, unsigned int cmd,
+ unsigned long arg);
int ll_lov_setstripe_ea_info(struct inode *inode, struct dentry *dentry,
__u64 flags, struct lov_user_md *lum,
if (flags & LUSTRE_PROJINHERIT_FL)
fa.fsx_xflags = FS_XFLAG_PROJINHERIT;
- rc = ll_ioctl_check_project(inode, &fa);
+ rc = ll_ioctl_check_project(inode, fa.fsx_xflags,
+ fa.fsx_projid);
if (rc)
RETURN(rc);
local dir="$DIR/$tdir/dir"
mkdir -p $dir
mkfifo $dir/pipe
- #try to change pipe file should not hang and return failure
- wait_update_facet client "$LFS project -sp 1 $dir/pipe 2>&1 |
- awk -F ':' '{ print \\\$2 }'" \
- " unable to get xattr for fifo '$dir/pipe'" || return 1
#command can process further if it hit some errors
+ $LFS project -sp 1 $dir/pipe
touch $dir/aaa $dir/bbb
mkdir $dir/subdir -p
touch $dir/subdir/aaa $dir/subdir/bbb
#create one invalid link file
ln -s $dir/not_exist_file $dir/ccc
local cnt=$(lfs project -r $dir 2>/dev/null | wc -l)
- [ $cnt -eq 5 ] || error "expected 5 got $cnt"
+ [ $cnt -eq 7 ] || error "expected 7 got $cnt"
cleanup_quota_test
}
touch $dir1/file
ln -s $dir1/file $dir1/file_link
+ mkfifo $dir1/fifo
- $LFS project -sp $TSTPRJID $dir1/file_link >&/dev/null &&
- error "set symlink file's project should fail"
+ $LFS project -srp $TSTPRJID $dir1 >&/dev/null ||
+ error "set project should succeed"
- $LFS project $TSTPRJID $dir1/file_link >&/dev/null &&
- error "get symlink file's project should fail"
+ used=$(getquota -p $TSTPRJID global curinodes)
+ [ $used -eq 4 ] || error "expected 4 got $used"
+ $LFS project -rC $dir1 >&/dev/null ||
+ error "clear project should succeed"
+
+ used=$(getquota -p $TSTPRJID global curinodes)
+ [ $used -eq 0 ] || error "expected 0 got $used"
cleanup_quota_test
}
-run_test 64 "lfs project on symlink files should fail"
+run_test 64 "lfs project on non dir/files should succeed"
test_65() {
local SIZE=10 # MB
#include <libcfs/util/list.h>
#include <libcfs/util/ioctl.h>
#include <sys/ioctl.h>
+#include <libgen.h>
#include "lfs_project.h"
#include <lustre/lustreapi.h>
return 0;
}
-static const char *mode_to_type(mode_t mode)
+static int project_get_fsxattr(const char *pathname, struct fsxattr *fsx,
+ struct stat *st, char *ret_bname)
{
- switch (mode & S_IFMT) {
- case S_IFDIR: return "dir";
- case S_IFREG: return "regular";
- case S_IFLNK: return "symlink";
- case S_IFCHR: return "char device";
- case S_IFBLK: return "block device";
- case S_IFIFO: return "fifo";
- case S_IFSOCK: return "sock";
- }
-
- return "unknown";
-}
-
-static int project_get_xattr(const char *pathname, struct fsxattr *fsx,
- struct stat *st)
-{
- int ret, fd;
+ int ret = 0, fd = -1;
+ char dname_path[PATH_MAX + 1] = { 0 };
+ char bname_path[PATH_MAX + 1] = { 0 };
+ char *dname, *bname;
+ struct lu_project lu_project = { 0 };
ret = lstat(pathname, st);
if (ret) {
fprintf(stderr, "%s: failed to stat '%s': %s\n",
progname, pathname, strerror(errno));
- return -errno;
+ ret = -errno;
+ goto out;
}
/* currently, only file and dir supported */
- if (!S_ISREG(st->st_mode) && !S_ISDIR(st->st_mode)) {
- errno = ENOTSUP;
- fprintf(stderr, "%s: unable to get xattr for %s '%s': %s\n",
- progname, mode_to_type(st->st_mode), pathname,
- strerror(errno));
- return -errno;
- }
+ if (!S_ISREG(st->st_mode) && !S_ISDIR(st->st_mode))
+ goto new_api;
fd = open(pathname, O_RDONLY | O_NOCTTY | O_NDELAY);
if (fd < 0) {
fprintf(stderr, "%s: failed to open '%s': %s\n",
progname, pathname, strerror(errno));
- return -errno;
+ ret = -errno;
+ goto out;
}
ret = ioctl(fd, FS_IOC_FSGETXATTR, fsx);
if (ret) {
fprintf(stderr, "%s: failed to get xattr for '%s': %s\n",
progname, pathname, strerror(errno));
- close(fd);
- return -errno;
+ ret = -errno;
+ }
+ goto out;
+new_api:
+ strncpy(dname_path, pathname, PATH_MAX);
+ strncpy(bname_path, pathname, PATH_MAX);
+ dname = dirname(dname_path);
+ bname = basename(bname_path);
+ fd = open(dname, O_RDONLY | O_NOCTTY | O_NDELAY);
+ if (fd < 0) {
+ ret = -errno;
+ goto out;
+ }
+ lu_project.project_type = LU_PROJECT_GET;
+ if (bname) {
+ strncpy(lu_project.project_name, bname, NAME_MAX);
+ if (ret_bname)
+ strncpy(ret_bname, bname, NAME_MAX);
+ }
+ ret = ioctl(fd, LL_IOC_PROJECT, &lu_project);
+ if (ret) {
+ fprintf(stderr, "%s: failed to get xattr for '%s': %s\n",
+ progname, pathname, strerror(errno));
+ ret = -errno;
+ } else {
+ fsx->fsx_xflags = lu_project.project_xflags;
+ fsx->fsx_projid = lu_project.project_id;
}
- return fd;
+out:
+ if (ret && fd >= 0)
+ close(fd);
+ return ret ? ret : fd;
}
static int
int ret;
struct stat st;
- ret = project_get_xattr(pathname, &fsx, &st);
+ ret = project_get_fsxattr(pathname, &fsx, &st, NULL);
if (ret < 0)
return ret;
struct stat st;
int ret;
- ret = project_get_xattr(pathname, &fsx, &st);
+ ret = project_get_fsxattr(pathname, &fsx, &st, NULL);
if (ret < 0)
return ret;
struct fsxattr fsx;
struct stat st;
int fd, ret = 0;
+ char bname[NAME_MAX + 1] = { 0 };
+ struct lu_project lp = { 0 };
- fd = project_get_xattr(pathname, &fsx, &st);
+ fd = project_get_fsxattr(pathname, &fsx, &st, bname);
if (fd < 0)
return fd;
if (phc->set_projid)
fsx.fsx_projid = phc->projid;
- ret = ioctl(fd, FS_IOC_FSSETXATTR, &fsx);
+ if (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode)) {
+ ret = ioctl(fd, FS_IOC_FSSETXATTR, &fsx);
+ } else {
+ lp.project_xflags = fsx.fsx_xflags;
+ lp.project_id = fsx.fsx_projid;
+ lp.project_type = LU_PROJECT_SET;
+ strncpy(lp.project_name, bname, NAME_MAX);
+ lp.project_name[NAME_MAX] = '\0';
+ ret = ioctl(fd, LL_IOC_PROJECT, &lp);
+ }
+out:
if (ret)
fprintf(stderr, "%s: failed to set xattr for '%s': %s\n",
progname, pathname, strerror(errno));
-out:
close(fd);
return ret;
}
struct fsxattr fsx;
struct stat st;
int ret = 0, fd;
+ char bname[NAME_MAX + 1] = { 0 };
+ struct lu_project lp = { 0 };
- fd = project_get_xattr(pathname, &fsx, &st);
+ fd = project_get_fsxattr(pathname, &fsx, &st, bname);
if (fd < 0)
return fd;
if (!phc->keep_projid)
fsx.fsx_projid = 0;
- ret = ioctl(fd, FS_IOC_FSSETXATTR, &fsx);
+ if (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode)) {
+ ret = ioctl(fd, FS_IOC_FSSETXATTR, &fsx);
+ } else {
+ lp.project_xflags = fsx.fsx_xflags;
+ lp.project_id = fsx.fsx_projid;
+ lp.project_type = LU_PROJECT_SET;
+ strncpy(lp.project_name, bname, NAME_MAX);
+ lp.project_name[NAME_MAX] = '\0';
+ ret = ioctl(fd, LL_IOC_PROJECT, &lp);
+ }
if (ret)
fprintf(stderr, "%s: failed to set xattr for '%s': %s\n",
progname, pathname, strerror(errno));