static int cobd_md_getattr(struct obd_export *exp, struct lustre_id *id,
__u64 valid, const char *xattr_name,
- unsigned int ea_size, struct ptlrpc_request **request)
+ const void *xattr_data, unsigned int xattr_datalen,
+ unsigned int ea_size,
+ struct ptlrpc_request **request)
{
struct obd_device *obd = class_exp2obd(exp);
struct obd_export *cobd_exp;
return -EINVAL;
}
cobd_exp = cobd_get_exp(obd);
- return md_getattr(cobd_exp, id, valid, xattr_name, ea_size, request);
+ return md_getattr(cobd_exp, id, valid, xattr_name,
+ xattr_data, xattr_datalen, ea_size, request);
}
static int cobd_md_req2lustre_md(struct obd_export *mdc_exp,
#ifndef _LUSTRE_ACL_H_
#define _LUSTRE_ACL_H_
+#ifdef __KERNEL__
#include <linux/xattr_acl.h>
+#endif
/*
* the value of LL_ACL_MAX_ENTRIES and LL_ACL_NOT_CACHED should be
#define LL_ACL_MAX_ENTRIES 32 // EXT3_ACL_MAX_ENTRIES
#define LL_ACL_NOT_CACHED ((void *)-1) //EXT3_ACL_NOT_CACHED
+/* remote acl */
+#define XATTR_NAME_LUSTRE_ACL "system.lustre_acl"
+#define LUSTRE_ACL_SIZE_MAX (4096)
+
#endif
struct lsd_permission *perms;
};
+/* remote acl upcall */
+struct rmtacl_upcall_desc {
+ int status; /* helper execution status */
+ int upcall_status; /* error in upcall itself */
+ int get; /* is getfacl */
+ char *cmd; /* cmdline (up) */
+ __u32 cmdlen; /* cmdline length (up) */
+ char *res; /* output (down) */
+ __u32 reslen; /* output length (down) */
+ /* upcall internal use */
+ uid_t uid;
+ char *root;
+};
+
+struct rmtacl_upcall_entry {
+ struct upcall_cache_entry base;
+ struct rmtacl_upcall_desc *desc;
+};
+
+struct rmtacl_downcall_args {
+ __u64 key;
+ char *res; /* output text */
+ __u32 reslen; /* output text length */
+ int status; /* helper exit code */
+};
+
/* mds/mds_reint.c */
int mds_reint_rec(struct mds_update_record *r, int offset,
struct ptlrpc_request *req, struct lustre_handle *);
struct lustre_md *md);
int mdc_getstatus(struct obd_export *exp, struct lustre_id *rootid);
int mdc_getattr(struct obd_export *exp, struct lustre_id *id,
- __u64 valid, const char *xattr_name, unsigned int ea_size,
- struct ptlrpc_request **request);
+ __u64 valid, const char *xattr_name,
+ const void *xattr_data, unsigned int xattr_datalen,
+ unsigned int ea_size, struct ptlrpc_request **request);
int mdc_getattr_lock(struct obd_export *exp, struct lustre_id *id,
char *filename, int namelen, __u64 valid,
unsigned int ea_size, struct ptlrpc_request **request);
void *, int, ldlm_completion_callback,
ldlm_blocking_callback, void *);
int (*m_getattr)(struct obd_export *, struct lustre_id *,
- __u64, const char *, unsigned int,
- struct ptlrpc_request **);
+ __u64, const char *, const void *, unsigned int,
+ unsigned int, struct ptlrpc_request **);
int (*m_access_check)(struct obd_export *, struct lustre_id *,
struct ptlrpc_request **);
int (*m_getattr_lock)(struct obd_export *, struct lustre_id *,
static inline int md_getattr(struct obd_export *exp, struct lustre_id *id,
__u64 valid, const char *xattr_name,
+ const void *xattr_data, unsigned int xattr_datalen,
unsigned int ea_size,
struct ptlrpc_request **request)
{
EXP_CHECK_MD_OP(exp, getattr);
MD_COUNTER_INCREMENT(exp->exp_obd, getattr);
rc = MDP(exp->exp_obd, getattr)(exp, id, valid, xattr_name,
+ xattr_data, xattr_datalen,
ea_size, request);
RETURN(rc);
}
extern int llapi_catinfo(char *dir, char *keyword, char *node_name);
extern int llapi_lov_get_uuids(int fd, struct obd_uuid *uuidp, int *ost_count);
extern int llapi_is_lustre_mnttype(char *type);
+extern int llapi_getfacl(char *dir, char *cmd);
+extern int llapi_setfacl(char *dir, char *cmd);
#endif
#define LL_IOC_MDC_MKDIRSTRIPE _IOW ('f', 160, long)
#define LL_IOC_GROUP_LOCK _IOW ('f', 161, long)
#define LL_IOC_GROUP_UNLOCK _IOW ('f', 162, long)
+#define LL_IOC_GETFACL _IOW ('f', 163, long)
+#define LL_IOC_SETFACL _IOW ('f', 164, long)
#define LL_IOC_FLUSH_CRED _IOW ('f', 170, long)
uuid->uuid[sizeof(*uuid) - 1] = '\0';
}
+/* remote acl ioctl */
+struct ll_acl_ioctl_data {
+ char *cmd; /* IN */
+ unsigned long cmd_len;
+ char *res; /* OUT */
+ unsigned long res_len;
+ int status; /* OUT */
+};
+
#endif /* _LUSTRE_USER_H */
/* filemap.c */
extern unsigned long page_unuse(struct page *);
extern void truncate_inode_pages(struct address_space *, loff_t);
+Index: linux-2.6.10/fs/namespace.c
+===================================================================
+--- linux-2.6.10/fs/namespace.c.symbol 2005-07-28 13:16:56.000000000 -0600
++++ linux-2.6.10/fs/namespace.c 2005-07-28 13:17:24.000000000 -0600
+@@ -38,6 +38,7 @@ static inline int sysfs_init(void)
+
+ /* spinlock for vfsmount related operations, inplace of dcache_lock */
+ spinlock_t vfsmount_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
++EXPORT_SYMBOL(vfsmount_lock);
+
+ static struct list_head *mount_hashtable;
+ static int hash_mask, hash_bits;
}
ll_inode2id(&id, inode);
rc = mdc_getattr(sbi->ll_md_exp, &id, valid, NULL, 0,
- ealen, &req);
+ NULL, ealen, &req);
if (rc) {
CERROR("failure %d inode %lu\n", rc, lli->lli_st_ino);
RETURN(-abs(rc));
ll_inode2id(&id, inode);
rc = mdc_getattr(sbi->ll_md_exp, &id,
- OBD_MD_LINKNAME, NULL, 0, symlen, request);
+ OBD_MD_LINKNAME, NULL, 0, NULL, symlen, request);
if (rc) {
CERROR("inode %lu: rc = %d\n", lli->lli_st_ino, rc);
RETURN(rc);
/* fetch attr of root inode */
err = mdc_getattr(sbi->ll_md_exp, &rootid,
OBD_MD_FLNOTOBD|OBD_MD_FLBLOCKS, NULL, 0,
- 0, &request);
+ NULL, 0, &request);
if (err) {
CERROR("mdc_getattr failed for root: rc = %d\n", err);
GOTO(out_lov, err);
#include <linux/lustre_lite.h>
#include <linux/lustre_dlm.h>
#include <linux/lustre_sec.h>
+#include <linux/lustre_acl.h>
#include "llite_internal.h"
typedef struct ext2_dir_entry_2 ext2_dirent;
return err;
}
+/*
+ * we don't call getxattr_internal/setxattr_internal because we
+ * need more precisely control.
+ */
+static int ll_ioctl_getfacl(struct inode *inode,
+ struct file *file,
+ struct ll_acl_ioctl_data *ioc)
+{
+ struct ptlrpc_request *req = NULL;
+ struct mds_body *body;
+ char *cmd, *res;
+ struct lustre_id id;
+ int rc;
+ ENTRY;
+
+ if (!ioc->cmd || !ioc->cmd_len ||
+ !ioc->res || !ioc->res_len) {
+ CERROR("error: cmd %p, len %lu, res %p, len %lu\n",
+ ioc->cmd, ioc->cmd_len, ioc->res, ioc->res_len);
+ RETURN(-EINVAL);
+ }
+
+ OBD_ALLOC(cmd, ioc->cmd_len);
+ if (!cmd)
+ RETURN(-ENOMEM);
+ if (copy_from_user(cmd, ioc->cmd, ioc->cmd_len))
+ GOTO(out, rc = -EFAULT);
+
+ /* we didn't call ll_getxattr_internal() because we'd like to
+ * copy from reply buffer to user space directly.
+ */
+ ll_inode2id(&id, inode);
+ rc = md_getattr(ll_i2sbi(inode)->ll_md_exp, &id, OBD_MD_FLXATTR,
+ XATTR_NAME_LUSTRE_ACL,
+ cmd, ioc->cmd_len, ioc->res_len, &req);
+ if (rc < 0) {
+ CERROR("rc: %d\n", rc);
+ GOTO(out, rc);
+ }
+
+ res = lustre_msg_buf(req->rq_repmsg, 1, ioc->res_len);
+ LASSERT(res);
+ if (copy_to_user(ioc->res, res, ioc->res_len))
+ rc = -EFAULT;
+
+ body = lustre_msg_buf(req->rq_repmsg, 0, sizeof(*body));
+ LASSERT(body);
+ ioc->status = (__s32) body->flags;
+
+ EXIT;
+out:
+ if (req)
+ ptlrpc_req_finished(req);
+ OBD_FREE(cmd, ioc->cmd_len);
+
+ return rc;
+}
+
+static int ll_ioctl_setfacl(struct inode *inode,
+ struct file *file,
+ struct ll_acl_ioctl_data *ioc)
+{
+ struct ptlrpc_request *req = NULL;
+ struct mdc_op_data op_data;
+ struct mds_body *body;
+ struct iattr attr;
+ char *cmd;
+ int replen, rc;
+ ENTRY;
+
+ if (!ioc->cmd || !ioc->cmd_len) {
+ CERROR("error: cmd %p, len %lu\n", ioc->cmd, ioc->cmd_len);
+ RETURN(-EINVAL);
+ }
+
+ OBD_ALLOC(cmd, ioc->cmd_len);
+ if (!cmd)
+ RETURN(-ENOMEM);
+ if (copy_from_user(cmd, ioc->cmd, ioc->cmd_len))
+ GOTO(out, rc = -EFAULT);
+
+ memset(&attr, 0x0, sizeof(attr));
+ attr.ia_valid |= ATTR_EA;
+ attr.ia_attr_flags = 0;
+
+ ll_prepare_mdc_data(&op_data, inode, NULL, NULL, 0, 0);
+
+ rc = md_setattr(ll_i2sbi(inode)->ll_md_exp, &op_data, &attr,
+ (void*) XATTR_NAME_LUSTRE_ACL,
+ sizeof(XATTR_NAME_LUSTRE_ACL),
+ (void*) cmd, ioc->cmd_len, &req);
+ if (rc) {
+ CERROR("md_setattr fails: rc = %d\n", rc);
+ GOTO(out, rc);
+ }
+
+ body = lustre_msg_buf(req->rq_repmsg, 0, sizeof(*body));
+ LASSERT(body);
+ ioc->status = (__s32) body->flags;
+
+ LASSERT(req->rq_repmsg->bufcount == 2);
+ replen = req->rq_repmsg->buflens[1];
+ LASSERT(replen <= LUSTRE_ACL_SIZE_MAX);
+ if (replen) {
+ if (replen > ioc->res_len)
+ replen = ioc->res_len;
+ if (copy_to_user(ioc->res,
+ lustre_msg_buf(req->rq_repmsg, 1, replen),
+ replen))
+ rc = -EFAULT;
+ }
+ EXIT;
+out:
+ if (req)
+ ptlrpc_req_finished(req);
+ OBD_FREE(cmd, ioc->cmd_len);
+
+ return rc;
+}
+
static int ll_dir_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
valid |= OBD_MD_FLDIREA;
ll_inode2id(&id, inode);
- rc = md_getattr(sbi->ll_md_exp, &id, valid, NULL,
+ rc = md_getattr(sbi->ll_md_exp, &id, valid, NULL, NULL, 0,
obd_size_diskmd(sbi->ll_dt_exp, NULL),
&request);
if (rc < 0) {
obd_ioctl_freedata(buf, len);
RETURN(rc);
}
+ case LL_IOC_GETFACL: {
+ struct ll_acl_ioctl_data ioc, *uioc;
+ int rc;
+
+ if (copy_from_user(&ioc, (void *) arg, sizeof(ioc)))
+ RETURN(-EFAULT);
+
+ rc = ll_ioctl_getfacl(inode, file, &ioc);
+ if (!rc) {
+ uioc = (struct ll_acl_ioctl_data *) arg;
+ if (copy_to_user(&uioc->status, &ioc.status,
+ sizeof(ioc.status)))
+ rc = -EFAULT;
+ }
+ RETURN(rc);
+ }
+ case LL_IOC_SETFACL: {
+ struct ll_acl_ioctl_data ioc, *uioc;
+ int rc;
+
+ if (copy_from_user(&ioc, (void *) arg, sizeof(ioc)))
+ RETURN(-EFAULT);
+
+ rc = ll_ioctl_setfacl(inode, file, &ioc);
+ if (!rc) {
+ uioc = (struct ll_acl_ioctl_data *) arg;
+ if (copy_to_user(&uioc->status, &ioc.status,
+ sizeof(ioc.status)))
+ rc = -EFAULT;
+ }
+ RETURN(rc);
+ }
case LL_IOC_FLUSH_CRED:
RETURN(ll_flush_cred(inode));
default:
CDEBUG(D_VFSTRACE, "VFS Op:inode=%lu\n", inode->i_ino);
lprocfs_counter_incr(ll_i2sbi(inode)->ll_stats, LPROC_LL_SETXATTR);
+ if (sbi->ll_remote && !strcmp(name, XATTR_NAME_ACL_ACCESS))
+ RETURN(-EOPNOTSUPP);
+
memset(&attr, 0x0, sizeof(attr));
attr.ia_valid |= valid;
attr.ia_attr_flags = flags;
ll_prepare_mdc_data(&op_data, inode, NULL, NULL, 0, 0);
rc = md_setattr(sbi->ll_md_exp, &op_data, &attr,
- (void*) name, strnlen(name, XATTR_NAME_MAX)+1,
+ (void*) name, strnlen(name, XATTR_NAME_MAX) + 1,
(void*) value, size, &request);
- if (rc) {
- CERROR("md_setattr fails: rc = %d\n", rc);
+ if (rc)
GOTO(out, rc);
- }
out:
ptlrpc_req_finished(request);
rc = ll_setxattr_internal(dentry->d_inode, name, value, size,
flags, ATTR_EA);
-
+
/* update inode's acl info */
if (rc == 0 && strcmp(name, XATTR_NAME_ACL_ACCESS) == 0) {
if (value) {
lprocfs_counter_incr(ll_i2sbi(inode)->ll_stats, LPROC_LL_GETXATTR);
+ if (sbi->ll_remote && !strcmp(name, XATTR_NAME_ACL_ACCESS))
+ RETURN(-EOPNOTSUPP);
+
ll_inode2id(&id, inode);
- rc = md_getattr(sbi->ll_md_exp, &id, valid, name,
+ rc = md_getattr(sbi->ll_md_exp, &id, valid, name, NULL, 0,
size, &request);
if (rc) {
if (rc != -ENODATA && rc != -EOPNOTSUPP)
- CERROR("md_getattr fails: rc = %d\n", rc);
+ CERROR("rc = %d\n", rc);
GOTO(out, rc);
}
LASSERT_REPSWABBED(request, 0);
ea_size = body->eadatasize;
- LASSERT(ea_size <= request->rq_repmsg->buflens[0]);
-
if (size == 0)
GOTO(out, rc = ea_size);
+ LASSERT(ea_size <= request->rq_repmsg->buflens[1]);
ea_data = lustre_msg_buf(request->rq_repmsg, 1, ea_size);
LASSERT(ea_data != NULL);
LASSERT_REPSWABBED(request, 1);
if (value)
memcpy(value, ea_data, ea_size);
rc = ea_size;
+
out:
ptlrpc_req_finished(request);
RETURN(rc);
int ll_md_real_close(struct obd_export *md_exp,
struct inode *inode, int flags);
extern int ll_inode_revalidate_it(struct dentry *);
-extern int ll_setxattr(struct dentry *, const char *, const void *,
- size_t, int);
-extern int ll_getxattr(struct dentry *, const char *, void *, size_t);
-extern int ll_listxattr(struct dentry *, char *, size_t);
-extern int ll_removexattr(struct dentry *, const char *);
+int ll_setxattr(struct dentry *, const char *, const void *,
+ size_t, int);
+int ll_getxattr(struct dentry *, const char *, void *, size_t);
+int ll_listxattr(struct dentry *, char *, size_t);
+int ll_removexattr(struct dentry *, const char *);
extern int ll_inode_permission(struct inode *, int, struct nameidata *);
int ll_refresh_lsm(struct inode *inode, struct lov_stripe_md *lsm);
int ll_extent_lock(struct ll_file_data *, struct inode *,
/* make root inode */
err = md_getattr(sbi->ll_md_exp, &sbi->ll_rootid,
(OBD_MD_FLNOTOBD | OBD_MD_FLBLOCKS | OBD_MD_FID),
- NULL, 0, &request);
+ NULL, NULL, 0, 0, &request);
if (err) {
CERROR("md_getattr failed for root: rc = %d\n", err);
GOTO(out_lov, err);
struct mds_body *body;
ll_inode2id(&id, inode);
- rc = md_getattr(sbi->ll_md_exp, &id, valid, NULL, 0, &req);
+ rc = md_getattr(sbi->ll_md_exp, &id, valid, NULL, NULL, 0, 0,
+ &req);
if (rc) {
CERROR("failure %d inode %lu\n", rc, inode->i_ino);
RETURN(-abs(rc));
id_ino(&id) = (__u64)ino;
id_gen(&id) = generation;
- rc = md_getattr(sbi->ll_md_exp, &id, valid, NULL,
+ rc = md_getattr(sbi->ll_md_exp, &id, valid, NULL, NULL, 0,
eadatalen, &req);
if (rc) {
CERROR("failure %d inode %lu\n", rc, ino);
}
ll_inode2id(&id, inode);
- rc = md_getattr(sbi->ll_md_exp, &id, OBD_MD_LINKNAME, NULL, symlen,
- request);
+ rc = md_getattr(sbi->ll_md_exp, &id, OBD_MD_LINKNAME, NULL, NULL, 0,
+ symlen, request);
if (rc) {
if (rc != -ENOENT)
static int lmv_getattr(struct obd_export *exp, struct lustre_id *id,
__u64 valid, const char *xattr_name,
+ const void *xattr_data, unsigned int xattr_datalen,
unsigned int ea_size, struct ptlrpc_request **request)
{
struct obd_device *obd = exp->exp_obd;
LASSERT(i < lmv->desc.ld_tgt_count);
- rc = md_getattr(lmv->tgts[i].ltd_exp, id, valid, xattr_name,
+ rc = md_getattr(lmv->tgts[i].ltd_exp, id, valid,
+ xattr_name, xattr_data, xattr_datalen,
ea_size, request);
if (rc)
RETURN(rc);
/* time to update mea of parent id */
rc = md_getattr(lmv->tgts[id_group(id)].ltd_exp,
- id, valid, NULL, mealen, &req);
+ id, valid, NULL, NULL, 0, mealen, &req);
if (rc) {
CERROR("md_getattr() failed, error %d\n", rc);
GOTO(cleanup, rc);
valid = OBD_MD_FLEASIZE | OBD_MD_FLDIREA | OBD_MD_MEA;
rc = md_getattr(lmv->tgts[id_group(id)].ltd_exp,
- id, valid, NULL, mealen, &req);
+ id, valid, NULL, NULL, 0, mealen, &req);
if (rc) {
CERROR("md_getattr() failed, error %d\n", rc);
GOTO(cleanup, obj = ERR_PTR(rc));
#include <linux/obd_class.h>
#include <linux/lustre_mds.h>
+#include <linux/lustre_acl.h>
#include "mdc_internal.h"
/* this function actually sends request to desired target. */
mdc_setattr_pack(req->rq_reqmsg, 1, data, iattr, ea, ealen,
ea2, ea2len);
+ /* prepare the reply buffer
+ */
+ bufcount = 1;
size[0] = sizeof(struct mds_body);
- req->rq_replen = lustre_msg_size(1, size);
+
+ /* This is a hack for setfacl remotely. XXX */
+ if (ealen == sizeof(XATTR_NAME_LUSTRE_ACL) &&
+ !strncmp((char *) ea, XATTR_NAME_LUSTRE_ACL, ealen)) {
+ size[bufcount++] = LUSTRE_ACL_SIZE_MAX;
+ }
+
+ req->rq_replen = lustre_msg_size(bufcount, size);
rc = mdc_reint(req, rpc_lock, LUSTRE_IMP_FULL);
*request = req;
CERROR ("Missing/short eadata\n");
RETURN (-EPROTO);
}
- }
+ }
RETURN (0);
}
int mdc_getattr(struct obd_export *exp, struct lustre_id *id,
__u64 valid, const char *xattr_name,
+ const void *xattr_data, unsigned int xattr_datalen,
unsigned int ea_size, struct ptlrpc_request **request)
{
struct ptlrpc_request *req;
struct mds_body *body;
int xattr_namelen = xattr_name ? strlen(xattr_name) + 1 : 0;
+ int size[4] = {0, sizeof(*body)};
int bufcount = 2;
- int size[3] = {0, sizeof(*body)};
int rc;
ENTRY;
size[0] = lustre_secdesc_size();
- if (valid & OBD_MD_FLXATTR)
+ if (valid & OBD_MD_FLXATTR) {
size[bufcount++] = xattr_namelen;
+ if (xattr_datalen > 0) {
+ LASSERT(xattr_data);
+ size[bufcount++] = xattr_datalen;
+ }
+ } else
+ LASSERT(!xattr_data && !xattr_datalen);
+
req = ptlrpc_prep_req(class_exp2cliimp(exp), LUSTRE_MDS_VERSION,
MDS_GETATTR, bufcount, size, NULL);
if (!req)
body->valid = valid;
body->eadatasize = ea_size;
-
- if (valid & OBD_MD_FLXATTR)
+ if (valid & OBD_MD_FLXATTR) {
memcpy(lustre_msg_buf(req->rq_reqmsg, 2, xattr_namelen),
xattr_name, xattr_namelen);
+ if (xattr_datalen)
+ memcpy(lustre_msg_buf(req->rq_reqmsg, 3, xattr_datalen),
+ xattr_data, xattr_datalen);
+ }
rc = mdc_getattr_common(exp, ea_size, req);
if (rc != 0) {
MODULES := mds
mds-objs := mds_log.o mds_unlink_open.o mds_lov.o handler.o mds_reint.o
mds-objs += mds_fs.o lproc_mds.o mds_open.o mds_lib.o mds_lmv.o mds_lsd.o
+mds-objs += mds_acl.o
@INCLUDE_RULES@
RETURN(rc);
}
-int mds_pack_ea(struct dentry *dentry, struct ptlrpc_request *req,
- struct mds_body *repbody, int req_off, int reply_off)
+int mds_pack_xattr(struct dentry *dentry, struct ptlrpc_request *req,
+ struct mds_body *repbody, int req_off, int reply_off)
{
struct inode *inode = dentry->d_inode;
char *ea_name;
value = lustre_msg_buf(req->rq_repmsg, reply_off + 1, len);
rc = -EOPNOTSUPP;
- if (inode->i_op && inode->i_op->getxattr)
+
+ if (!strcmp(ea_name, XATTR_NAME_LUSTRE_ACL)) {
+ struct rmtacl_upcall_desc desc;
+
+ if (len != LUSTRE_ACL_SIZE_MAX || !value) {
+ CERROR("no reply buffer prepared\n");
+ RETURN(-EFAULT);
+ }
+
+ memset(&desc, 0, sizeof(desc));
+ desc.get = 1;
+ desc.cmd = lustre_msg_string(req->rq_reqmsg, req_off + 2, 0);
+ desc.cmdlen = req->rq_reqmsg->buflens[req_off + 2];
+ desc.res = (char *) value;
+ desc.reslen = LUSTRE_ACL_SIZE_MAX;
+
+ mds_do_remote_acl_upcall(&desc);
+
+ if (desc.upcall_status)
+ RETURN(desc.upcall_status);
+
+ if (desc.reslen > LUSTRE_ACL_SIZE_MAX) {
+ CERROR("downcall claim reslen %u\n", desc.reslen);
+ RETURN(-EINVAL);
+ }
+ /* like remote setfacl, steal "flags" in mds_body as the
+ * exececution status
+ */
+ repbody->flags = desc.status;
+ repbody->valid |= OBD_MD_FLXATTR;
+ repbody->eadatasize = desc.reslen;
+
+ RETURN(0);
+ }
+
+ if (inode->i_op && inode->i_op->getxattr)
rc = inode->i_op->getxattr(dentry, ea_name, value, len);
if (rc < 0) {
rc = 0;
}
- RETURN(rc);
+ RETURN(rc);
}
-int mds_pack_ealist(struct dentry *dentry, struct ptlrpc_request *req,
- struct mds_body *repbody, int reply_off)
+int mds_pack_xattr_list(struct dentry *dentry, struct ptlrpc_request *req,
+ struct mds_body *repbody, int reply_off)
{
struct inode *inode = dentry->d_inode;
void *value = NULL;
(reqbody->valid & OBD_MD_LINKNAME) != 0) {
rc = mds_pack_link(dentry, req, body, reply_off);
} else if (reqbody->valid & OBD_MD_FLXATTR) {
- rc = mds_pack_ea(dentry, req, body, req_off, reply_off);
+ rc = mds_pack_xattr(dentry, req, body, req_off, reply_off);
} else if (reqbody->valid & OBD_MD_FLXATTRLIST) {
- rc = mds_pack_ealist(dentry, req, body, reply_off);
+ rc = mds_pack_xattr_list(dentry, req, body, reply_off);
}
if (reqbody->valid & OBD_MD_FLACL) {
char *ea_name = lustre_msg_string(req->rq_reqmsg,
offset + 1, 0);
rc = -EOPNOTSUPP;
- if (inode->i_op && inode->i_op->getxattr)
- rc = inode->i_op->getxattr(de, ea_name, NULL, 0);
-
- if (rc < 0) {
- if (rc != -ENODATA && rc != -EOPNOTSUPP)
- CERROR("error getting inode %lu EA: rc = %d\n",
- inode->i_ino, rc);
- size[bufcount] = 0;
+
+ if (!strcmp(ea_name, XATTR_NAME_LUSTRE_ACL)) {
+ size[bufcount] = LUSTRE_ACL_SIZE_MAX;
} else {
- size[bufcount] = min_t(int, body->eadatasize, rc);
+ if (inode->i_op && inode->i_op->getxattr)
+ rc = inode->i_op->getxattr(de, ea_name,
+ NULL, 0);
+
+ if (rc < 0) {
+ if (rc != -ENODATA && rc != -EOPNOTSUPP)
+ CERROR("error get inode %lu EA: %d\n",
+ inode->i_ino, rc);
+ size[bufcount] = 0;
+ } else {
+ size[bufcount] = min_t(int,
+ body->eadatasize, rc);
+ }
}
bufcount++;
} else if (body->valid & OBD_MD_FLXATTRLIST) {
else
bufcount = 1;
- rc = lustre_pack_reply(req, bufcount, size, NULL);
- if (rc)
- break;
+ /* for SETATTR: I have different reply setting for
+ * remote setfacl, so delay the reply buffer allocation.
+ */
+ if (opc != REINT_SETATTR) {
+ rc = lustre_pack_reply(req, bufcount, size, NULL);
+ if (rc)
+ break;
+ }
rc = mds_reint(req, MDS_REQ_REC_OFF, NULL);
fail = OBD_FAIL_MDS_REINT_NET_REP;
struct lprocfs_static_vars lvars;
mds_init_lsd_cache();
+ mds_init_rmtacl_upcall_cache();
lprocfs_init_multi_vars(0, &lvars);
class_register_type(&mds_obd_ops, NULL, lvars.module_vars,
static void /*__exit*/ mds_exit(void)
{
+ mds_cleanup_rmtacl_upcall_cache();
mds_cleanup_lsd_cache();
class_unregister_type(OBD_MDS_DEVICENAME);
return count;
}
+/*
+ * remote acl proc handling
+ */
+static int lprocfs_rd_lacl_upcall(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ struct upcall_cache *cache = __mds_get_global_rmtacl_upcall_cache();
+
+ *eof = 1;
+ return snprintf(page, count, "%s\n", cache->uc_upcall);
+}
+
+static int lprocfs_wr_lacl_upcall(struct file *file, const char *buffer,
+ unsigned long count, void *data)
+{
+ struct upcall_cache *cache = __mds_get_global_rmtacl_upcall_cache();
+
+ if (count < UC_CACHE_UPCALL_MAXPATH) {
+ sscanf(buffer, "%1024s", cache->uc_upcall);
+ cache->uc_upcall[UC_CACHE_UPCALL_MAXPATH - 1] = 0;
+ }
+ return count;
+}
+
+static int lprocfs_wr_lacl_downcall(struct file *file, const char *buffer,
+ unsigned long count, void *data)
+{
+ struct upcall_cache *cache = __mds_get_global_rmtacl_upcall_cache();
+ struct rmtacl_downcall_args param;
+
+ if (count != sizeof(param)) {
+ CERROR("invalid data size %lu\n", count);
+ goto do_err_downcall;
+ }
+ if (copy_from_user(¶m, buffer, count)) {
+ CERROR("broken downcall\n");
+ goto do_err_downcall;
+ }
+
+do_downcall:
+ upcall_cache_downcall(cache, param.key, ¶m);
+ return count;
+
+do_err_downcall:
+ memset(¶m, 0, sizeof(param));
+ param.status = -EINVAL;
+ goto do_downcall;
+}
+
struct lprocfs_vars lprocfs_mds_module_vars[] = {
{ "num_refs", lprocfs_rd_numrefs, 0, 0 },
/* LSD stuff */
lprocfs_wr_lsd_upcall, 0},
{ "lsd_flush", 0, lprocfs_wr_lsd_flush, 0},
{ "lsd_downcall", 0, lprocfs_wr_lsd_downcall, 0},
+ /* remote acl */
+ { "lacl_upcall", lprocfs_rd_lacl_upcall,
+ lprocfs_wr_lacl_upcall, 0},
+ { "lacl_downcall", 0, lprocfs_wr_lacl_downcall, 0},
{ 0 }
};
--- /dev/null
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ * Copyright (c) 2005 Cluster File Systems, Inc.
+ *
+ * This file is part of Lustre, http://www.lustre.org.
+ *
+ * Lustre is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * Lustre is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Lustre; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#define DEBUG_SUBSYSTEM S_MDS
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/kmod.h>
+#include <linux/string.h>
+#include <linux/stat.h>
+#include <linux/errno.h>
+#include <linux/version.h>
+#include <linux/unistd.h>
+
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+#include <linux/fs.h>
+#include <linux/stat.h>
+#include <asm/uaccess.h>
+#include <linux/slab.h>
+#include <asm/segment.h>
+
+#include <libcfs/list.h>
+#include <linux/obd_support.h>
+#include <linux/lustre_lib.h>
+#include <linux/lustre_mds.h>
+#include <linux/lustre_ucache.h>
+
+#include "mds_internal.h"
+
+/****************************************
+ * handle remote getfacl/setfacl upcall *
+ ****************************************/
+
+#define RMTACL_UPCALL_HASHSIZE (1)
+static struct upcall_cache _rmtacl_upcall_cache;
+static struct list_head _rmtacl_upcall_hashtable[RMTACL_UPCALL_HASHSIZE];
+
+#define RMTACL_UPCALL_PATH "/usr/bin/lacl_upcall"
+#define RMTACL_ACQUIRE_EXPIRE (15)
+#define RMTACL_ENTRY_EXPIRE (0)
+#define RMTACL_ERR_ENTRY_EXPIRE (0)
+
+struct upcall_cache *__mds_get_global_rmtacl_upcall_cache()
+{
+ return &_rmtacl_upcall_cache;
+}
+
+static unsigned int rmtacl_hash(struct upcall_cache *cache, __u64 key)
+{
+ LASSERT(cache == &_rmtacl_upcall_cache);
+ return 0;
+}
+
+static struct upcall_cache_entry *
+rmtacl_alloc_entry(struct upcall_cache *cache, __u64 key)
+{
+ struct rmtacl_upcall_entry *entry;
+
+ OBD_ALLOC(entry, sizeof(*entry));
+ if (!entry)
+ return NULL;
+
+ upcall_cache_init_entry(cache, &entry->base, key);
+ entry->desc = (struct rmtacl_upcall_desc *) ((unsigned long) key);
+
+ return &entry->base;
+}
+
+static void rmtacl_free_entry(struct upcall_cache *cache,
+ struct upcall_cache_entry *entry)
+{
+ struct rmtacl_upcall_entry *rentry;
+
+ rentry = container_of(entry, struct rmtacl_upcall_entry, base);
+ OBD_FREE(rentry, sizeof(*rentry));
+}
+
+static int rmtacl_make_upcall(struct upcall_cache *cache,
+ struct upcall_cache_entry *entry)
+{
+ struct rmtacl_upcall_entry *rentry;
+ struct rmtacl_upcall_desc *desc;
+ char *argv[7];
+ char *envp[3];
+ char keystr[20];
+ char uidstr[16];
+ int rc;
+
+ rentry = container_of(entry, struct rmtacl_upcall_entry, base);
+ desc = rentry->desc;
+
+ snprintf(keystr, 20, LPX64, entry->ue_key);
+ snprintf(uidstr, 16, "%u", desc->uid);
+
+ argv[0] = cache->uc_upcall;
+ argv[1] = keystr;
+ argv[2] = uidstr;
+ argv[3] = desc->root;
+ argv[4] = desc->get ? "get" : "set";
+ argv[5] = desc->cmd;
+ argv[6] = NULL;
+
+ envp[0] = "HOME=/";
+ envp[1] = "PATH=/bin:/usr/bin:/usr/local/bin";
+ envp[2] = NULL;
+
+ rc = USERMODEHELPER(argv[0], argv, envp);
+ if (rc < 0) {
+ CERROR("Error invoking upcall %s: %d; check "
+ "/proc/fs/lustre/mds/lacl_upcall\n",
+ argv[0], rc);
+ } else {
+ CDEBUG(D_SEC, "Invoked upcall %s %s %s %s\n",
+ argv[0], argv[1], argv[2], argv[3]);
+ }
+ return rc;
+}
+
+static int rmtacl_parse_downcall(struct upcall_cache *cache,
+ struct upcall_cache_entry *entry,
+ void *args)
+{
+ struct rmtacl_upcall_entry *rentry;
+ struct rmtacl_upcall_desc *desc;
+ struct rmtacl_downcall_args *rargs;
+
+ LASSERT(args);
+
+ rentry = container_of(entry, struct rmtacl_upcall_entry, base);
+ desc = rentry->desc;
+ rargs = (struct rmtacl_downcall_args *) args;
+
+ desc->status = rargs->status;
+
+ if (desc->reslen < rargs->reslen) {
+ CERROR("bufsize %u, while %u passed down\n",
+ desc->reslen, rargs->reslen);
+ desc->upcall_status = -ENOMEM;
+ goto out;
+ }
+
+ desc->reslen = rargs->reslen;
+ if (!rargs->reslen)
+ goto out;
+
+ if (copy_from_user(desc->res, rargs->res, rargs->reslen)) {
+ desc->upcall_status = -EFAULT;
+ goto out;
+ }
+
+out:
+ return 0;
+}
+
+static void mds_rmtacl_upcall(struct rmtacl_upcall_desc *desc)
+{
+ struct upcall_cache *cache = &_rmtacl_upcall_cache;
+ struct upcall_cache_entry *entry;
+
+ desc->upcall_status = 0;
+
+ entry = upcall_cache_get_entry(cache, (__u64) ((unsigned long) desc));
+ if (!entry) {
+ desc->upcall_status = -EINVAL;
+ return;
+ }
+
+ UC_CACHE_SET_EXPIRED(entry);
+ upcall_cache_put_entry(entry);
+}
+
+int mds_init_rmtacl_upcall_cache()
+{
+ struct upcall_cache *cache = &_rmtacl_upcall_cache;
+ int i;
+ ENTRY;
+
+ cache->uc_hashtable = _rmtacl_upcall_hashtable;
+ cache->uc_hashsize = RMTACL_UPCALL_HASHSIZE;
+ cache->uc_hashlock = RW_LOCK_UNLOCKED;
+ for (i = 0; i < cache->uc_hashsize; i++)
+ INIT_LIST_HEAD(&cache->uc_hashtable[i]);
+ cache->uc_name = "RMTACL_UPCALL";
+
+ /* set default value, proc tunable */
+ sprintf(cache->uc_upcall, RMTACL_UPCALL_PATH);
+ cache->uc_acquire_expire = RMTACL_ACQUIRE_EXPIRE;
+ cache->uc_entry_expire = RMTACL_ENTRY_EXPIRE;
+ cache->uc_err_entry_expire = RMTACL_ERR_ENTRY_EXPIRE;
+
+ cache->hash = rmtacl_hash;
+ cache->alloc_entry = rmtacl_alloc_entry;
+ cache->free_entry = rmtacl_free_entry;
+ cache->make_upcall = rmtacl_make_upcall;
+ cache->parse_downcall = rmtacl_parse_downcall;
+
+ RETURN(0);
+}
+
+void mds_cleanup_rmtacl_upcall_cache()
+{
+ struct upcall_cache *cache = &_rmtacl_upcall_cache;
+
+ LASSERT(list_empty(&cache->uc_hashtable[0]));
+}
+
+/****************************************
+ * exported helper functions *
+ ****************************************/
+
+/*
+ * traverse through the mountpoint to find lustre mountpoint
+ */
+static struct vfsmount *mds_get_lustre_mnt(void)
+{
+ struct vfsmount *mnt, *lmnt = NULL;
+
+ LASSERT(current->fs);
+ read_lock(¤t->fs->lock);
+ mnt = mntget(current->fs->rootmnt);
+ read_unlock(¤t->fs->lock);
+ LASSERT(mnt);
+
+ spin_lock(&vfsmount_lock);
+check_point:
+ if (!strcmp(mnt->mnt_sb->s_type->name, "lustre") ||
+ !strcmp(mnt->mnt_sb->s_type->name, "llite")) {
+ lmnt = mntget(mnt);
+ goto break_out;
+ }
+
+ if (!list_empty(&mnt->mnt_mounts)) {
+ mnt = list_entry(mnt->mnt_mounts.next,
+ struct vfsmount, mnt_child);
+ goto check_point;
+ }
+
+follow_siblings:
+ /* check siblings */
+ if (list_empty(&mnt->mnt_child) ||
+ mnt->mnt_child.next == &mnt->mnt_parent->mnt_mounts) {
+ /* we are the last child */
+ LASSERT(mnt->mnt_parent != NULL);
+ if (list_empty(&mnt->mnt_child) ||
+ mnt->mnt_parent == NULL)
+ goto break_out;
+ mnt = mnt->mnt_parent;
+ goto follow_siblings;
+ }
+
+ mnt = list_entry(mnt->mnt_child.next, struct vfsmount, mnt_child);
+ goto check_point;
+
+break_out:
+ spin_unlock(&vfsmount_lock);
+
+ return lmnt;
+}
+
+void mds_do_remote_acl_upcall(struct rmtacl_upcall_desc *desc)
+{
+ struct fs_struct *fs = current->fs;
+ struct vfsmount *lmnt;
+ char *buf = NULL, *mntpnt;
+
+ lmnt = mds_get_lustre_mnt();
+ if (!lmnt) {
+ desc->upcall_status = -EOPNOTSUPP;
+ return;
+ }
+
+ OBD_ALLOC(buf, PAGE_SIZE);
+ if (!buf) {
+ desc->upcall_status = -ENOMEM;
+ goto out;
+ }
+
+ mntpnt = __d_path(lmnt->mnt_root, lmnt, fs->root, fs->rootmnt,
+ buf, PAGE_SIZE);
+ if (IS_ERR(mntpnt)) {
+ desc->upcall_status = PTR_ERR(mntpnt);
+ goto out;
+ }
+
+ desc->root = mntpnt;
+ desc->uid = current->uid;
+
+ mds_rmtacl_upcall(desc);
+
+out:
+ if (buf)
+ OBD_FREE(buf, PAGE_SIZE);
+ mntput(lmnt);
+}
struct mds_body *, struct inode *, int lock, int mea);
int mds_pack_link(struct dentry *dentry, struct ptlrpc_request *req,
struct mds_body *repbody, int reply_off);
-int mds_pack_ea(struct dentry *dentry, struct ptlrpc_request *req,
- struct mds_body *repbody, int req_off, int reply_off);
-int mds_pack_ealist(struct dentry *dentry, struct ptlrpc_request *req,
- struct mds_body *repbody, int reply_off);
+int mds_pack_xattr(struct dentry *dentry, struct ptlrpc_request *req,
+ struct mds_body *repbody, int req_off, int reply_off);
+int mds_pack_xattr_list(struct dentry *dentry, struct ptlrpc_request *req,
+ struct mds_body *repbody, int reply_off);
int mds_pack_acl(struct ptlrpc_request *req, int reply_off,
struct mds_body *body, struct inode *inode);
int mds_pack_inode2id(struct obd_device *, struct lustre_id *,
void mds_put_lsd(struct lustre_sec_desc *lsd);
void mds_flush_lsd(__u32 id);
+/* mds_acl.c */
+struct upcall_cache *__mds_get_global_rmtacl_upcall_cache(void);
+int mds_init_rmtacl_upcall_cache(void);
+void mds_cleanup_rmtacl_upcall_cache(void);
+void mds_do_remote_acl_upcall(struct rmtacl_upcall_desc *desc);
+
#endif /* _MDS_INTERNAL_H */
l_dput(de);
}
+
+static int mds_reint_remote_setfacl(struct obd_device *obd,
+ struct mds_export_data *med,
+ struct mds_update_record *rec,
+ struct ptlrpc_request *req)
+{
+ struct rmtacl_upcall_desc desc;
+ struct dentry *de;
+ struct inode *inode;
+ struct mds_body *body;
+ int rc = 0;
+ int repsize[2] = { sizeof(*body), LUSTRE_ACL_SIZE_MAX };
+ ENTRY;
+
+ rc = lustre_pack_reply(req, 2, repsize, NULL);
+ if (rc)
+ RETURN(rc);
+
+ de = mds_id2dentry(obd, rec->ur_id1, NULL);
+ if (IS_ERR(de))
+ GOTO(out, rc = PTR_ERR(de));
+
+ inode = de->d_inode;
+ LASSERT(inode);
+
+ /* setxattr from remote client:
+ */
+ memset(&desc, 0, sizeof(desc));
+ desc.cmd = (char *) rec->ur_ea2data;
+ desc.cmdlen = rec->ur_ea2datalen;
+ desc.res = lustre_msg_buf(req->rq_repmsg, 1, LUSTRE_ACL_SIZE_MAX);
+ desc.reslen = LUSTRE_ACL_SIZE_MAX;
+
+ mds_do_remote_acl_upcall(&desc);
+ if (desc.upcall_status)
+ GOTO(out_put, rc = desc.upcall_status);
+
+ if (desc.status < 0)
+ desc.status = -desc.status;
+
+ body = lustre_msg_buf(req->rq_repmsg, 0, sizeof (*body));
+ LASSERT(body);
+
+ /* client (lmv) will do limited checking upon replied mds_body,
+ * we pack it as normal, but "steal" field "flags" field to store
+ * the acl execution status.
+ */
+ mds_pack_inode2body(obd, body, inode, 1);
+ body->flags = desc.status;
+ mds_body_do_reverse_map(med, body);
+
+ EXIT;
+out_put:
+ l_dput(de);
+out:
+ req->rq_status = rc;
+ return 0;
+}
+
/*This is a tmp fix for cmobd setattr reint*/
#define XATTR_LUSTRE_MDS_LOV_EA "lov"
void *handle = NULL;
struct mds_logcancel_data *mlcd = NULL;
int rc = 0, cleanup_phase = 0, err;
- int locked = 0;
+ int repsize = sizeof(*body), locked = 0;
ENTRY;
LASSERT(offset == 1);
id_ino(rec->ur_id1), id_gen(rec->ur_id1),
rec->ur_iattr.ia_valid);
+ /* remote setfacl need special handling */
+ if ((rec->ur_iattr.ia_valid & ATTR_EA) &&
+ !strcmp(rec->ur_eadata, XATTR_NAME_LUSTRE_ACL)) {
+ return mds_reint_remote_setfacl(obd, med, rec, req);
+ }
+
+ rc = lustre_pack_reply(req, 1, &repsize, NULL);
+ if (rc)
+ RETURN(rc);
+
MDS_CHECK_RESENT(req, reconstruct_reint_setattr(rec, offset, req));
MD_COUNTER_INCREMENT(obd, setattr);
if (rc == 0) {
if (rec->ur_iattr.ia_valid & ATTR_EA) {
- int flags = (int)rec->ur_iattr.ia_attr_flags;
+ int flags = (int) rec->ur_iattr.ia_attr_flags;
rc = -EOPNOTSUPP;
- if (inode->i_op && inode->i_op->setxattr)
- rc = inode->i_op->setxattr(de, rec->ur_eadata,
- rec->ur_ea2data, rec->ur_ea2datalen,
- flags);
+ if (!med->med_remote && inode->i_op &&
+ inode->i_op->setxattr)
+ rc = inode->i_op->setxattr(
+ de, rec->ur_eadata,
+ rec->ur_ea2data,
+ rec->ur_ea2datalen,
+ flags);
} else if (rec->ur_iattr.ia_valid & ATTR_EA_RM) {
rc = -EOPNOTSUPP;
- if (inode->i_op && inode->i_op->removexattr)
- rc = inode->i_op->removexattr(de, rec->ur_eadata);
+ if (!med->med_remote && inode->i_op &&
+ inode->i_op->removexattr)
+ rc = inode->i_op->removexattr(
+ de, rec->ur_eadata);
} else if (rec->ur_iattr.ia_valid & ATTR_EA_CMOBD) {
char *name;
int type;
}
/* Now we know it's good */
- LASSERT(UC_CACHE_IS_VALID(entry));
write_unlock(&cache->uc_hashlock);
RETURN(entry);
if UTILS
rootsbin_SCRIPTS = mount.lustre
-sbin_PROGRAMS = lctl obdio obdbarrier lload wirecheck wiretest llmount lsd_upcall
+sbin_PROGRAMS = lctl obdio obdbarrier lload wirecheck wiretest llmount \
+ lsd_upcall lacl_upcall
bin_PROGRAMS = lfs lkinit
lib_LIBRARIES = liblustreapi.a
sbin_SCRIPTS = $(sbin_scripts)
lsd_upcall_LDADD = $(LIBREADLINE) $(LIBPTLCTL)
lsd_upcall_DEPENDENCIES := $(LIBPTLCTL)
+lacl_upcall_SOURCES = lacl_upcall.c
+lacl_upcall_LDADD = $(LIBREADLINE) $(LIBPTLCTL)
+lacl_upcall_DEPENDENCIES := $(LIBPTLCTL)
+
EXTRA_DIST = $(bin_scripts) $(sbin_scripts)
# NOTE: this should only be run on i386.
--- /dev/null
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ * Copyright (C) 2005 Cluster File Systems, Inc.
+ *
+ * This file is part of Lustre, http://www.lustre.org.
+ *
+ * Lustre is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * Lustre is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Lustre; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <fcntl.h>
+#include <pwd.h>
+#include <grp.h>
+
+#include <liblustre.h>
+#include <linux/lustre_idl.h>
+#include <linux/obd.h>
+#include <linux/lustre_mds.h>
+#include <linux/obd_support.h>
+
+#include <portals/ptlctl.h>
+#include <portals/types.h>
+
+int switch_user_identity(uid_t uid)
+{
+ gid_t gid;
+ struct passwd *pw;
+ int maxgroups, ngroups = 0;
+ gid_t *groups;
+ struct group *gr;
+ int i;
+
+ /* originally must be root */
+ if (getuid() != 0 || geteuid() != 0)
+ return -EPERM;
+
+ /* nothing more is needed for root */
+ if (uid == 0)
+ return 0;
+
+ /* - groups
+ * - gid
+ * - uid
+ */
+ maxgroups = sysconf(_SC_NGROUPS_MAX);
+ groups = malloc(maxgroups * sizeof(gid_t));
+ if (!groups)
+ return -ENOMEM;
+
+ pw = getpwuid(uid);
+ if (!pw)
+ return -EPERM;
+
+ gid = pw->pw_gid;
+
+ while ((gr = getgrent())) {
+ if (!gr->gr_mem)
+ continue;
+ for (i = 0; gr->gr_mem[i]; i++) {
+ if (strcmp(gr->gr_mem[i], pw->pw_name))
+ continue;
+ groups[ngroups++] = gr->gr_gid;
+ break;
+ }
+ if (ngroups == maxgroups)
+ break;
+ }
+ endgrent();
+
+ if (setgroups(ngroups, groups) == -1) {
+ free(groups);
+ return -EPERM;
+ }
+ free(groups);
+
+ if (setgid(gid) == -1) {
+ return -EPERM;
+ }
+
+ if (setuid(uid) == -1) {
+ return -EPERM;
+ }
+
+ return 0;
+}
+
+/*
+ * caller guarantee args not empty
+ */
+int compose_command_line(char *cmdline, char *op, char *args)
+{
+ char *p, *params, *file;
+
+ /* skip the white space at the tail */
+ p = args + strlen(args) - 1;
+
+ while (p >= args) {
+ if (*p != ' ' && *p != '\t')
+ break;
+ p--;
+ }
+
+ /* not allow empty args */
+ if (p < args)
+ return -1;
+
+ *(p + 1) = '\0';
+
+ /* find next space */
+ while (p >= args) {
+ if (*p == ' ' || *p == '\t')
+ break;
+ p--;
+ }
+
+ if (p >= args) {
+ *p = '\0';
+ file = p + 1; /* file name */
+ params = args;
+ } else {
+ file = args;
+ params = "";
+ }
+
+ /* backward path not allowed */
+ if (strstr(file, ".."))
+ return -EPERM;
+
+ /* absolute path not allowed */
+ if (file[0] == '/')
+ return -EPERM;
+
+ snprintf(cmdline, PATH_MAX, "%sfacl %s %s",
+ op, params, file);
+ return 0;
+}
+
+void do_acl_command(uid_t uid, char *lroot, char *cmdline)
+{
+ if (switch_user_identity(uid)) {
+ printf("MDS: invalid user %u\n", uid);
+ return;
+ }
+
+ if (chdir(lroot) < 0) {
+ printf("MDS: can't change dir\n");
+ return;
+ }
+
+ execl("/bin/sh", "sh", "-c", cmdline, NULL);
+ printf("MDS: can't execute\n");
+}
+
+#define ERRSTR_NO_CMDLINE "No command line supplied\n"
+#define ERRSTR_INVALID_ARGS "Invalid arguments\n"
+#define ERRSTR_MDS_PROCESS "MDS procession error\n"
+
+/*
+ * The args passed in are:
+ * 1. key (in hex)
+ * 2. uid (in uint)
+ * 3. lustre root
+ * 4. get/set
+ * 5. command line
+ */
+#define OUTPUT_BUFSIZE 8192
+int main (int argc, char **argv)
+{
+ struct rmtacl_downcall_args dc_args;
+ char *dc_name = "/proc/fs/lustre/mds/lacl_downcall";
+ int dc_fd;
+ int uid;
+ char output[OUTPUT_BUFSIZE];
+ char cmdline[PATH_MAX];
+ int pipeout[2], pipeerr[2], pid;
+ int output_size, rd, childret;
+
+ if (argc != 6)
+ return -1;
+
+ if (strcmp(argv[4], "get") && strcmp(argv[4], "set"))
+ return -1;
+
+ dc_args.key = strtoull(argv[1], NULL, 16);
+ dc_args.res = output;
+ dc_args.reslen = 0;
+ dc_args.status = -1; /* default return error */
+
+ uid = atoi(argv[2]);
+
+ if (strlen(argv[5]) == 0) {
+ dc_args.reslen = sizeof(ERRSTR_NO_CMDLINE);
+ memcpy(output, ERRSTR_NO_CMDLINE, dc_args.reslen);
+ goto downcall;
+ }
+
+ if (compose_command_line(cmdline, argv[4], argv[5])) {
+ dc_args.reslen = sizeof(ERRSTR_INVALID_ARGS);
+ memcpy(output, ERRSTR_INVALID_ARGS, dc_args.reslen);
+ goto downcall;
+ }
+
+ /* create pipe */
+ if (pipe(pipeout) < 0 || pipe(pipeerr) < 0) {
+ dc_args.reslen = sizeof(ERRSTR_MDS_PROCESS);
+ memcpy(output, ERRSTR_MDS_PROCESS, dc_args.reslen);
+ goto downcall;
+ }
+
+ if ((pid = fork()) < 0) {
+ dc_args.reslen = sizeof(ERRSTR_MDS_PROCESS);
+ memcpy(output, ERRSTR_MDS_PROCESS, dc_args.reslen);
+ goto downcall;
+ } else if (pid == 0) {
+ close(pipeout[0]);
+ if (pipeout[1] != STDOUT_FILENO) {
+ dup2(pipeout[1], STDOUT_FILENO);
+ close(pipeout[1]);
+ }
+
+ close(pipeerr[0]);
+ if (pipeerr[1] != STDERR_FILENO) {
+ dup2(pipeerr[1], STDERR_FILENO);
+ close(pipeerr[1]);
+ }
+
+ close(STDIN_FILENO);
+
+ do_acl_command(uid, argv[3], cmdline);
+ exit(-1);
+ }
+
+ /* parent process handling */
+ close(pipeout[1]);
+ close(pipeerr[1]);
+
+ output[0] = 0;
+ output_size = 0;
+ while (1) {
+ rd = read(pipeout[0], output + output_size,
+ OUTPUT_BUFSIZE - output_size);
+ if (rd < 0) {
+ output_size = sizeof(ERRSTR_MDS_PROCESS);
+ memcpy(output, ERRSTR_MDS_PROCESS, dc_args.reslen);
+ break;
+ }
+ if (rd == 0)
+ break;
+ output_size += rd;
+ if (output_size >= OUTPUT_BUFSIZE)
+ break;
+ }
+
+ /* if we got standard output, just leave; otherwise collect
+ * error output.
+ */
+ if (output_size != 0)
+ goto wait_child;
+
+ while (1) {
+ rd = read(pipeerr[0], output + output_size,
+ OUTPUT_BUFSIZE - output_size);
+ if (rd < 0) {
+ output_size = sizeof(ERRSTR_MDS_PROCESS);
+ memcpy(output, ERRSTR_MDS_PROCESS, dc_args.reslen);
+ break;
+ }
+ if (rd == 0)
+ break;
+ output_size += rd;
+ if (output_size >= OUTPUT_BUFSIZE)
+ break;
+ }
+
+wait_child:
+ wait(&childret);
+
+ dc_args.status = childret;
+ dc_args.reslen = output_size;
+
+downcall:
+ dc_fd = open(dc_name, O_WRONLY);
+ if (dc_fd != -1) {
+ write(dc_fd, &dc_args, sizeof(dc_args));
+ close(dc_fd);
+ }
+
+ return 0;
+}
lctl.newdev("mdt", 'MDT', 'MDT_UUID', setup ="")
if development_mode():
+ # set lsd upcall path
procentry = "/proc/fs/lustre/mds/lsd_upcall"
upcall = os.path.abspath(os.path.dirname(sys.argv[0]) + "/lsd_upcall")
if not (os.access(procentry, os.R_OK) and os.access(upcall, os.R_OK)):
print "MDS Warning: failed to set lsd cache upcall"
else:
run("echo ", upcall, " > ", procentry)
+ # set lacl upcall path
+ procentry = "/proc/fs/lustre/mds/lacl_upcall"
+ upcall = os.path.abspath(os.path.dirname(sys.argv[0]) + "/lacl_upcall")
+ if not (os.access(procentry, os.R_OK) and os.access(upcall, os.R_OK)):
+ print "MDS Warning: failed to set remote acl upcall"
+ else:
+ run("echo ", upcall, " > ", procentry)
if config.root_squash == None:
config.root_squash = self.root_squash
#include <getopt.h>
#include <string.h>
#include <mntent.h>
+#include <dirent.h>
+#include <libgen.h>
#include <portals/ptlctl.h>
#include <liblustre.h>
static int lfs_osts(int argc, char **argv);
static int lfs_check(int argc, char **argv);
static int lfs_catinfo(int argc, char **argv);
+static int lfs_getfacl(int argc, char **argv);
+static int lfs_setfacl(int argc, char **argv);
/* all avaialable commands */
command_t cmdlist[] = {
"usage: catinfo {keyword} [node name]\n"
"\tkeywords are one of followings: config, deletions.\n"
"\tnode name must be provided when use keyword config."},
+ {"getfacl", lfs_getfacl, 0,
+ "Get file access control lists.\n"
+ "usage: getfacl [-dRLPvh] file"},
+ {"setfacl", lfs_setfacl, 0,
+ "Set file access control lists.\n"
+ "usage: setfacl [-bkndRLPvh] [{-m|-x} acl_spec] [{-M|-X} acl_file] file ..."},
{"osts", lfs_osts, 0, "osts"},
{"help", Parser_help, 0, "help"},
{"exit", Parser_quit, 0, "quit"},
return rc;
}
+/*
+ * We assume one and only one filename is supplied as the
+ * last parameter.
+ */
+static int acl_cmd_parse(int argc, char **argv,
+ char *dirbuf, char *cmdbuf)
+{
+ char path[PATH_MAX];
+ char path2[PATH_MAX];
+ FILE *fp;
+ struct mntent *mnt = NULL;
+ char *dir, *tgt;
+ int found = 0, i;
+
+ if (argc < 2)
+ return -1;
+
+ /* get path prefix */
+ strncpy(path, argv[argc - 1], PATH_MAX);
+ dir = dirname(path);
+
+ /* try to resolve the pathname into relative to the
+ * root of the mounted lustre filesystem.
+ * FIXME we simply suppose there's no sub-mounted filesystems
+ * under this mounted lustre tree.
+ */
+ if (getcwd(path2, PATH_MAX) == NULL) {
+ fprintf(stderr, "getcwd old: %s\n", strerror(errno));
+ return -1;
+ }
+
+ if (chdir(dir) == -1) {
+ fprintf(stderr, "chdir to %s: %s\n",
+ dir, strerror(errno));
+ return -1;
+ }
+
+ if (getcwd(path, PATH_MAX) == NULL) {
+ fprintf(stderr, "getcwd new: %s\n", strerror(errno));
+ return -1;
+ }
+
+ if (chdir(path2) == -1) {
+ fprintf(stderr, "chdir back: %s\n", strerror(errno));
+ return -1;
+ }
+
+ fp = setmntent(MOUNTED, "r");
+ if (fp == NULL) {
+ fprintf(stderr, "setmntent(%s): %s\n", MOUNTED,
+ strerror(errno));
+ return -1;
+ }
+
+ while (1) {
+ mnt = getmntent(fp);
+ if (!mnt)
+ break;
+
+ if (!llapi_is_lustre_mnttype(mnt->mnt_type))
+ continue;
+
+ if (!strncmp(mnt->mnt_dir, path, strlen(mnt->mnt_dir))) {
+ char *p;
+
+ /* save the mountpoint dir part */
+ strncpy(dirbuf, mnt->mnt_dir, PATH_MAX);
+
+ /* get rest of path under the mountpoint,
+ * don't start with slash.
+ */
+ p = path + strlen(mnt->mnt_dir);
+ while (*p == '/')
+ p++;
+ snprintf(path2, PATH_MAX, "%s", p);
+
+ /* remove trailing slash */
+ if (path2[strlen(path2)] == '/')
+ path2[strlen(path2)] = '\0';
+ found = 1;
+ /* continue try to match more proper fs */
+ }
+ }
+ endmntent(fp);
+
+ if (!found) {
+ fprintf(stderr, "no mounted lustre fs\n");
+ return -1;
+ }
+
+ /* get base name of target */
+ strncpy(path, argv[argc - 1], PATH_MAX);
+ tgt = basename(path);
+
+ cmdbuf[0] = '\0';
+ for (i = 1; i < argc - 1; i++) {
+ strncat(cmdbuf, argv[i], PATH_MAX);
+ strncat(cmdbuf, " ", PATH_MAX);
+ }
+ strncat(cmdbuf, path2, PATH_MAX);
+ if (path2[0] != '\0')
+ strncat(cmdbuf, "/", PATH_MAX);
+ strncat(cmdbuf, tgt, PATH_MAX);
+
+ return 0;
+}
+
+static int lfs_getfacl(int argc, char **argv)
+{
+ char dir[PATH_MAX];
+ char cmd[PATH_MAX];
+
+ if (acl_cmd_parse(argc, argv, dir, cmd))
+ return CMD_HELP;
+
+ return llapi_getfacl(dir, cmd);
+}
+
+static int lfs_setfacl(int argc, char **argv)
+{
+ char dir[PATH_MAX];
+ char cmd[PATH_MAX];
+
+ if (acl_cmd_parse(argc, argv, dir, cmd))
+ return CMD_HELP;
+
+ return llapi_setfacl(dir, cmd);
+}
+
int main(int argc, char **argv)
{
int rc;
#include <liblustre.h>
#include <linux/obd.h>
#include <linux/lustre_lib.h>
+#include <linux/lustre_acl.h>
#include <lustre/lustre_user.h>
#include <linux/obd_lov.h>
return rc;
}
+int llapi_getfacl(char *dir, char *cmd)
+{
+ struct ll_acl_ioctl_data data;
+ char out[LUSTRE_ACL_SIZE_MAX];
+ int fd, rc;
+
+ data.cmd = cmd;
+ data.cmd_len = strlen(cmd) + 1;
+ data.res = out;
+ data.res_len = sizeof(out);
+ data.status = 0;
+
+ fd = open(dir, O_RDONLY | O_DIRECTORY);
+ if (fd == -1) {
+ err_msg("can't open dir %s", dir);
+ return -1;
+ }
+
+ rc = ioctl(fd, LL_IOC_GETFACL, &data);
+ if (rc)
+ err_msg("getfacl failed");
+ else {
+ out[sizeof(out) - 1] = '\0';
+ printf("%s", out);
+ rc = data.status;
+ }
+
+ close(fd);
+
+ return rc;
+}
+
+int llapi_setfacl(char *dir, char *cmd)
+{
+ struct ll_acl_ioctl_data data;
+ char out[LUSTRE_ACL_SIZE_MAX];
+ int fd, rc;
+
+ data.cmd = cmd;
+ data.cmd_len = strlen(cmd) + 1;
+ data.res = out;
+ data.res_len = sizeof(out);
+ data.status = 0;
+
+ fd = open(dir, O_RDONLY | O_DIRECTORY);
+ if (fd == -1) {
+ err_msg("can't open dir %s", dir);
+ return -1;
+ }
+
+ rc = ioctl(fd, LL_IOC_SETFACL, &data);
+ if (rc)
+ err_msg("setfacl failed");
+ else {
+ out[sizeof(out) - 1] = '\0';
+ printf("%s", out);
+ rc = data.status;
+ }
+
+ close(fd);
+
+ return rc;
+}
+
int llapi_is_lustre_mnttype(char *type)
{
return (strcmp(type,"lustre") == 0 || strcmp(type,"lustre_lite") == 0);