MDS QOS usage of statfs, it should not stuck in waiting.
Severity : enhancement
+Bugzilla : 11842
+Description: remote_acl support
+Details : Support ACL-based permission check for remote user.
+ Support setfacl/getfacl for remote user with the utils
+ "lfs {l,r}{s,g}etfacl" which follow the same parameter format as
+ the system "{s,g}etfacl" utils.
+
+Severity : enhancement
Bugzilla : 14288
Description: Update to RHEL4 U6 kernel-2.6.9-67.EL.
AC_DEFINE_UNQUOTED(KRB5_VERSION, $K5VERS, [Define this as the Kerberos version number])
if test -f $dir/include/gssapi/gssapi_krb5.h -a \
\( -f $dir/lib/libgssapi_krb5.a -o \
+ -f $dir/lib64/libgssapi_krb5.a -o \
+ -f $dir/lib64/libgssapi_krb5.so -o \
-f $dir/lib/libgssapi_krb5.so \) ; then
AC_DEFINE(HAVE_KRB5, 1, [Define this if you have MIT Kerberos libraries])
KRBDIR="$dir"
AC_CHECK_LIB($gssapi_lib, gss_krb5_ccache_name,
AC_DEFINE(HAVE_GSS_KRB5_CCACHE_NAME, 1, [Define this if the Kerberos GSS library supports gss_krb5_ccache_name]), ,$KRBLIBS)
+ dnl Check for newer error message facility
+ AC_CHECK_LIB($gssapi_lib, krb5_get_error_message,
+ AC_DEFINE(HAVE_KRB5_GET_ERROR_MESSAGE, 1, [Define this if the function krb5_get_error_message is available]), ,$KRBLIBS)
+
+ dnl Check for function to specify addressless tickets
+ AC_CHECK_LIB($gssapi_lib, krb5_get_init_creds_opt_set_addressless,
+ AC_DEFINE(HAVE_KRB5_GET_INIT_CREDS_OPT_SET_ADDRESSLESS, 1, [Define this if the function krb5_get_init_creds_opt_set_addressless is available]), ,$KRBLIBS)
+
dnl If they specified a directory and it didn't work, give them a warning
if test "x$krb5_with" != "x" -a "$krb5_with" != "$KRBDIR"; then
AC_MSG_WARN(Using $KRBDIR instead of requested value of $krb5_with for Kerberos!)
obd_cache.h obd_class.h obd_echo.h obd.h obd_lov.h \
obd_ost.h obd_support.h lustre_ver.h lu_object.h lu_time.h \
md_object.h dt_object.h lustre_param.h lustre_mdt.h \
- lustre_fid.h lustre_fld.h lustre_req_layout.h lustre_capa.h
-
+ lustre_fid.h lustre_fld.h lustre_req_layout.h lustre_capa.h \
+ lustre_idmap.h lustre_eacl.h
# ifdef CONFIG_FS_POSIX_ACL
# ifdef HAVE_XATTR_ACL
# include <linux/xattr_acl.h>
-# endif
+# endif /* HAVE_XATTR_ACL */
# ifdef HAVE_LINUX_POSIX_ACL_XATTR_H
# include <linux/posix_acl_xattr.h>
-# endif
-# endif
+# endif /* HAVE_LINUX_POSIX_ACL_XATTR_H */
+# endif /* CONFIG_FS_POSIX_ACL */
# ifndef HAVE_VFS_INTENT_PATCHES
# include <linux/lustre_intent.h>
# endif
-#endif
+#endif /* __KERNEL__ */
/* ACL */
#ifdef CONFIG_FS_POSIX_ACL
# define LUSTRE_POSIX_ACL_MAX_SIZE XATTR_ACL_SIZE
-#else /* CONFIG_FS_POSIX_ACL */
+# else /* CONFIG_FS_POSIX_ACL */
# define LUSTRE_POSIX_ACL_MAX_SIZE 0
-#endif /* CONFIG_FS_POSIX_ACL */
+# endif /* CONFIG_FS_POSIX_ACL */
#endif /* _LUSTRE_ACL_H */
# ifdef CONFIG_FS_POSIX_ACL
# ifdef HAVE_XATTR_ACL
# include <linux/xattr_acl.h>
-# endif
+# endif /* HAVE_XATTR_ACL */
# ifdef HAVE_LINUX_POSIX_ACL_XATTR_H
# include <linux/posix_acl_xattr.h>
-# endif
-# endif
+# endif /* HAVE_LINUX_POSIX_ACL_XATTR_H */
+# endif /* CONFIG_FS_POSIX_ACL */
# ifndef HAVE_VFS_INTENT_PATCHES
# include <linux/lustre_intent.h>
# endif
-#endif
+#endif /* __KERNEL__ */
struct mds_obd;
struct ptlrpc_request;
__u32 luc_cap;
__u32 luc_umask;
struct group_info *luc_ginfo;
- struct mdt_identity *luc_identity;
+ struct md_identity *luc_identity;
};
struct lvfs_callback_ops {
extern int llapi_poll_quotacheck(char *mnt, struct if_quotacheck *qchk);
extern int llapi_quotactl(char *mnt, struct if_quotactl *qctl);
extern int llapi_target_iterate(int type_num, char **obd_type, void *args, llapi_cb_t cb);
-extern int llapi_getfacl(char *fname, char *cmd);
-extern int llapi_setfacl(char *fname, char *cmd);
+extern int llapi_lsetfacl(int argc, char *argv[]);
+extern int llapi_lgetfacl(int argc, char *argv[]);
+extern int llapi_rsetfacl(int argc, char *argv[]);
+extern int llapi_rgetfacl(int argc, char *argv[]);
+extern int llapi_cp(int argc, char *argv[]);
+extern int llapi_ls(int argc, char *argv[]);
#endif
#define XATTR_NAME_ACL_DEFAULT "system.posix_acl_default"
#define XATTR_NAME_LOV "trusted.lov"
-/* remote ACL */
-#define XATTR_NAME_LUSTRE_ACL "system.lustre_acl"
-
#define OBD_MD_FLID (0x00000001ULL) /* object ID */
#define OBD_MD_FLATIME (0x00000002ULL) /* access time */
#define OBD_MD_FLMTIME (0x00000004ULL) /* data modification time */
#define OBD_MD_FLCKSPLIT (0x0000080000000000ULL) /* Check split on server */
#define OBD_MD_FLCROSSREF (0x0000100000000000ULL) /* Cross-ref case */
+#define OBD_MD_FLRMTLSETFACL (0x0001000000000000ULL) /* lfs lsetfacl case */
+#define OBD_MD_FLRMTLGETFACL (0x0002000000000000ULL) /* lfs lgetfacl case */
+#define OBD_MD_FLRMTRSETFACL (0x0004000000000000ULL) /* lfs rsetfacl case */
+#define OBD_MD_FLRMTRGETFACL (0x0008000000000000ULL) /* lfs rgetfacl case */
+
#define OBD_MD_FLGETATTR (OBD_MD_FLID | OBD_MD_FLATIME | OBD_MD_FLMTIME | \
OBD_MD_FLCTIME | OBD_MD_FLSIZE | OBD_MD_FLBLKSZ | \
OBD_MD_FLMODE | OBD_MD_FLTYPE | OBD_MD_FLUID | \
__u32 rp_access_perm; /* MAY_READ/WRITE/EXEC */
};
-/* setxid permissions for mds_setxid_perm.mp_perm */
-#define LUSTRE_SETUID_PERM 0x01
-#define LUSTRE_SETGID_PERM 0x02
-#define LUSTRE_SETGRP_PERM 0x04
+/* permissions for md_perm.mp_perm */
+enum {
+ CFS_SETUID_PERM = 0x01,
+ CFS_SETGID_PERM = 0x02,
+ CFS_SETGRP_PERM = 0x04,
+ CFS_RMTACL_PERM = 0x08
+};
extern void lustre_swab_mds_remote_perm(struct mds_remote_perm *p);
#define MAY_VTX_PART (1 << 12)
/* full VTX permission check */
#define MAY_VTX_FULL (1 << 13)
+/* lfs rgetfacl permission check */
+#define MAY_RGETFACL (1 << 14)
enum {
MDS_CHECK_SPLIT = 1 << 0,
#define IOC_OBD_STATFS _IOWR('f', 164, struct obd_statfs *)
#define IOC_LOV_GETINFO _IOWR('f', 165, struct lov_user_mds_data *)
#define LL_IOC_FLUSHCTX _IOW ('f', 166, long)
-#define LL_IOC_GETFACL _IOWR('f', 167, struct rmtacl_ioctl_data *)
-#define LL_IOC_SETFACL _IOWR('f', 168, struct rmtacl_ioctl_data *)
+#define LL_IOC_RMTACL _IOW ('f', 167, long)
#define LL_IOC_LLOOP_ATTACH _IOWR('f', 169, long)
#define LL_IOC_LLOOP_DETACH _IOWR('f', 170, long)
#define LL_FILE_IGNORE_LOCK 0x00000001
#define LL_FILE_GROUP_LOCKED 0x00000002
#define LL_FILE_READAHEAD 0x00000004
+#define LL_FILE_RMTACL 0x00000008
#define LOV_USER_MAGIC_V1 0x0BD10BD0
#define LOV_USER_MAGIC LOV_USER_MAGIC_V1
#define IDENTITY_DOWNCALL_MAGIC 0x6d6dd620
-/* setxid permission */
-#define N_SETXID_PERMS_MAX 64
+/* permission */
+#define N_PERMS_MAX 64
-struct setxid_perm_downcall_data {
+struct perm_downcall_data {
__u64 pdd_nid;
__u32 pdd_perm;
};
__u32 idd_uid;
__u32 idd_gid;
__u32 idd_nperms;
- struct setxid_perm_downcall_data idd_perms[N_SETXID_PERMS_MAX];
+ struct perm_downcall_data idd_perms[N_PERMS_MAX];
__u32 idd_ngroups;
__u32 idd_groups[0];
};
-#define RMTACL_DOWNCALL_MAGIC 0x6d6dd620
-#define RMTACL_SIZE_MAX (4096)
+/* for non-mapped uid/gid */
+#define NOBODY_UID 99
+#define NOBODY_GID 99
-struct rmtacl_downcall_data {
- __u32 add_magic;
- __u32 add_handle;
- __u64 add_key;
- __u32 add_buflen;
- __u32 add_padding;
- __u8 add_buf[0];
+#define INVALID_ID (-1)
+
+enum {
+ RMT_LSETFACL = 1,
+ RMT_LGETFACL = 2,
+ RMT_RSETFACL = 3,
+ RMT_RGETFACL = 4
};
#ifdef NEED_QUOTA_DEFS
# define offsetof(typ,memb) ((unsigned long)((char *)&(((typ *)0)->memb)))
#endif
-/* remote acl ioctl */
-struct rmtacl_ioctl_data {
- char *cmd; /* IN */
- unsigned long cmd_len;
- char *res; /* OUT */
- unsigned long res_len;
-};
-
#endif /* _LUSTRE_USER_H */
LCFG_LOV_ADD_INA = 0x00ce013,
LCFG_ADD_MDC = 0x00cf014,
LCFG_DEL_MDC = 0x00cf015,
- LCFG_SEC_FLAVOR = 0x00ce016,
+ LCFG_SPTLRPC_CONF = 0x00cf016,
};
struct lustre_cfg_bufs {
RETURN(0);
}
-/* default value for nllu/nllg for llite */
-#define NOBODY_UID 99
-#define NOBODY_GID 99
+#include <lustre/lustre_user.h>
+
#define INVALID_UID (-1)
#endif // _LUSTRE_CFG_H
int lmd_exclude_count;
char *lmd_dev; /* device name */
char *lmd_profile; /* client only */
- char *lmd_sec_mdt; /* sec from mdt (to ost/mdt) */
- char *lmd_sec_cli; /* sec from client (to ost/mdt) */
- uid_t lmd_nllu; /* non-lustre-local-user id */
- gid_t lmd_nllg; /* non-lustre-local-group id */
char *lmd_opts; /* lustre mount options (as opposed to
_device_ mount options) */
__u32 *lmd_exclude; /* array of OSTs to ignore */
--- /dev/null
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ * This file is part of Lustre, http://www.lustre.org
+ *
+ * MDS data structures.
+ * See also lustre_idl.h for wire formats of requests.
+ */
+
+#ifndef _LUSTRE_EACL_H
+#define _LUSTRE_EACL_H
+
+#ifdef CONFIG_FS_POSIX_ACL
+
+# ifdef HAVE_XATTR_ACL
+# include <linux/xattr_acl.h>
+# endif /* HAVE_XATTR_ACL */
+# ifdef HAVE_LINUX_POSIX_ACL_XATTR_H
+# include <linux/posix_acl_xattr.h>
+# endif /* HAVE_LINUX_POSIX_ACL_XATTR_H */
+
+#include <lustre_idmap.h>
+#include <md_object.h>
+#include <lu_object.h>
+
+typedef struct {
+ __u16 e_tag;
+ __u16 e_perm;
+ __u32 e_id;
+ __u32 e_stat;
+} ext_acl_xattr_entry;
+
+typedef struct {
+ __u32 a_count;
+ ext_acl_xattr_entry a_entries[0];
+} ext_acl_xattr_header;
+
+#define CFS_ACL_XATTR_SIZE(count, prefix) \
+ (sizeof(prefix ## _header) + (count) * sizeof(prefix ## _entry))
+
+#define CFS_ACL_XATTR_COUNT(size, prefix) \
+ (((size) - sizeof(prefix ## _header)) / sizeof(prefix ## _entry))
+
+extern int lustre_posix_acl_permission(struct md_ucred *mu, struct lu_attr *la,
+ int want, posix_acl_xattr_entry *entry,
+ int count);
+extern int lustre_posix_acl_chmod_masq(posix_acl_xattr_entry *entry,
+ __u32 mode, int count);
+extern int lustre_posix_acl_create_masq(posix_acl_xattr_entry *entry,
+ __u32 *pmode, int count);
+
+extern ext_acl_xattr_header *
+lustre_posix_acl_xattr_2ext(posix_acl_xattr_header *header, int size);
+extern int
+lustre_posix_acl_xattr_filter(posix_acl_xattr_header *header, int size,
+ posix_acl_xattr_header **out);
+extern int
+lustre_posix_acl_xattr_id2client(struct md_ucred *mu,
+ struct lustre_idmap_table *t,
+ posix_acl_xattr_header *header,
+ int size, int flags);
+extern void
+lustre_posix_acl_xattr_free(posix_acl_xattr_header *header, int size);
+extern int
+lustre_ext_acl_xattr_id2server(struct md_ucred *mu,
+ struct lustre_idmap_table *t,
+ ext_acl_xattr_header *header);
+extern void
+lustre_ext_acl_xattr_free(ext_acl_xattr_header *header);
+extern int
+lustre_acl_xattr_merge2posix(posix_acl_xattr_header *posix_header, int size,
+ ext_acl_xattr_header *ext_header,
+ posix_acl_xattr_header **out);
+extern ext_acl_xattr_header *
+lustre_acl_xattr_merge2ext(posix_acl_xattr_header *posix_header, int size,
+ ext_acl_xattr_header *ext_header);
+
+#endif /* CONFIG_FS_POSIX_ACL */
+
+#endif
loff_t med_lr_off;
int med_lr_idx;
unsigned int med_rmtclient:1; /* remote client? */
- __u32 med_nllu;
- __u32 med_nllg;
- struct mds_idmap_table *med_idmap;
+ struct semaphore med_idmap_sem;
+ struct lustre_idmap_table *med_idmap;
};
struct mdt_export_data {
loff_t med_lr_off;
int med_lr_idx;
unsigned int med_rmtclient:1; /* remote client? */
- __u32 med_nllu;
- __u32 med_nllg;
- struct mdt_idmap_table *med_idmap;
+ struct semaphore med_idmap_sem;
+ struct lustre_idmap_table *med_idmap;
};
struct osc_creator {
exp_req_replay_needed:1,
exp_lock_replay_needed:1,
exp_need_sync:1,
+ exp_flvr_changed:1,
+ exp_flvr_adapt:1,
exp_libclient:1; /* liblustre client? */
+ /* also protected by exp_lock */
+ enum lustre_sec_part exp_sp_peer;
+ struct sptlrpc_flavor exp_flvr; /* current */
+ struct sptlrpc_flavor exp_flvr_old[2]; /* about-to-expire */
+ cfs_time_t exp_flvr_expire[2]; /* seconds */
+
union {
struct mds_export_data eu_mds_data;
struct mdt_export_data eu_mdt_data;
--- /dev/null
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ * This file is part of Lustre, http://www.lustre.org
+ *
+ * MDS data structures.
+ * See also lustre_idl.h for wire formats of requests.
+ */
+
+#ifndef _LUSTRE_IDMAP_H
+#define _LUSTRE_IDMAP_H
+
+#include <md_object.h>
+
+#define CFS_NGROUPS_PER_BLOCK ((int)(CFS_PAGE_SIZE / sizeof(gid_t)))
+
+#define CFS_GROUP_AT(gi, i) \
+ ((gi)->blocks[(i) / CFS_NGROUPS_PER_BLOCK][(i) % CFS_NGROUPS_PER_BLOCK])
+
+enum {
+ CFS_IC_NOTHING = 0, /* convert nothing */
+ CFS_IC_ALL = 1, /* convert all items */
+ CFS_IC_MAPPED = 2, /* convert mapped uid/gid */
+ CFS_IC_UNMAPPED = 3 /* convert unmapped uid/gid */
+};
+
+#define CFS_IDMAP_NOTFOUND (-1)
+
+#define CFS_IDMAP_HASHSIZE 32
+
+enum lustre_idmap_idx {
+ RMT_UIDMAP_IDX,
+ LCL_UIDMAP_IDX,
+ RMT_GIDMAP_IDX,
+ LCL_GIDMAP_IDX,
+ CFS_IDMAP_N_HASHES
+};
+
+struct lustre_idmap_table {
+ spinlock_t lit_lock;
+ struct list_head lit_idmaps[CFS_IDMAP_N_HASHES][CFS_IDMAP_HASHSIZE];
+};
+
+extern void lustre_groups_from_list(struct group_info *ginfo, gid_t *glist);
+extern void lustre_groups_sort(struct group_info *group_info);
+extern int lustre_in_group_p(struct md_ucred *mu, gid_t grp);
+
+extern int lustre_idmap_add(struct lustre_idmap_table *t,
+ uid_t ruid, uid_t luid,
+ gid_t rgid, gid_t lgid);
+extern int lustre_idmap_del(struct lustre_idmap_table *t,
+ uid_t ruid, uid_t luid,
+ gid_t rgid, gid_t lgid);
+extern int lustre_idmap_lookup_uid(struct md_ucred *mu,
+ struct lustre_idmap_table *t,
+ int reverse, uid_t uid);
+extern int lustre_idmap_lookup_gid(struct md_ucred *mu,
+ struct lustre_idmap_table *t,
+ int reverse, gid_t gid);
+extern struct lustre_idmap_table *lustre_idmap_init(void);
+extern void lustre_idmap_fini(struct lustre_idmap_table *t);
+
+#endif
struct obd_device *imp_obd;
struct ptlrpc_sec *imp_sec;
+ struct semaphore imp_sec_mutex;
+ cfs_time_t imp_sec_expire;
cfs_waitq_t imp_recovery_waitq;
atomic_t imp_inflight;
# ifdef CONFIG_FS_POSIX_ACL
# ifdef HAVE_XATTR_ACL
# include <linux/xattr_acl.h>
-# endif
+# endif /*HAVE_XATTR_ACL */
# ifdef HAVE_LINUX_POSIX_ACL_XATTR_H
# include <linux/posix_acl_xattr.h>
-# endif
-# endif
+# endif /* HAVE_LINUX_POSIX_ACL_XATTR_H */
+# endif /* CONFIG_FS_POSIX_ACL */
# ifndef HAVE_VFS_INTENT_PATCHES
# include <linux/lustre_intent.h>
-# endif
-#endif
+# endif /* HAVE_VFS_INTENT_PATCHES */
+#endif /* __KERNEL__ */
#include <lustre_handles.h>
#include <libcfs/kp30.h>
#include <lustre/lustre_idl.h>
struct req_capsule cti_pill;
};
-/* id map */
-#define MDT_IDMAP_HASHSIZE (32)
-#define MDT_IDMAP_HASHFUNC(id) ((id) & (MDT_IDMAP_HASHSIZE - 1))
-
-enum mdt_idmap_idx {
- RMT_UIDMAP_IDX,
- LCL_UIDMAP_IDX,
- RMT_GIDMAP_IDX,
- LCL_GIDMAP_IDX,
- MDT_IDMAP_N_HASHES
-};
-
-struct mdt_idmap_table {
- spinlock_t mit_lock;
- struct list_head mit_idmaps[MDT_IDMAP_N_HASHES]
- [MDT_IDMAP_HASHSIZE];
-};
-
enum {
ESERIOUS = 0x0001000
};
struct ptlrpc_cli_ctx *rq_cli_ctx; /* client's half ctx */
struct ptlrpc_svc_ctx *rq_svc_ctx; /* server's half ctx */
struct list_head rq_ctx_chain; /* link to waited ctx */
- ptlrpc_sec_flavor_t rq_sec_flavor; /* client & server */
- /* client security flags */
- unsigned long rq_ctx_init:1, /* context initiation */
+
+ struct sptlrpc_flavor rq_flvr; /* client & server */
+ enum lustre_sec_part rq_sp_from;
+
+ unsigned long /* client/server security flags */
+ rq_ctx_init:1, /* context initiation */
rq_ctx_fini:1, /* context destroy */
rq_bulk_read:1, /* request bulk read */
rq_bulk_write:1, /* request bulk write */
rq_auth_remote:1, /* authed as remote user */
rq_auth_usr_root:1, /* authed as root */
rq_auth_usr_mdt:1, /* authed as mdt */
+ /* security tfm flags */
+ rq_pack_udesc:1,
+ rq_pack_bulk:1,
/* doesn't expect reply FIXME */
rq_no_reply:1;
#define PARAM_MDC "mdc."
#define PARAM_LLITE "llite."
#define PARAM_LOV "lov."
+#define PARAM_SRPC "srpc."
+#define PARAM_SRPC_FLVR "srpc.flavor."
+#define PARAM_SRPC_UDESC "srpc.udesc.cli2mdt"
#define PARAM_SEC "security."
-#define PARAM_SEC_RPC PARAM_SEC"rpc."
-#define PARAM_SEC_RPC_MDT PARAM_SEC_RPC"mdt="
-#define PARAM_SEC_RPC_CLI PARAM_SEC_RPC"cli="
#endif /* _LUSTRE_PARAM_H */
/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
* vim:expandtab:shiftwidth=8:tabstop=8:
*
- * Copyright (C) 2004-2006 Cluster File Systems, Inc.
+ * Copyright (C) 2004-2007 Cluster File Systems, Inc.
*
* This file is part of Lustre, http://www.lustre.org.
*
struct ptlrpc_reply_state;
struct ptlrpc_bulk_desc;
struct brw_page;
+struct seq_file;
/*
* forward declaration
SPTLRPC_POLICY_NULL = 0,
SPTLRPC_POLICY_PLAIN = 1,
SPTLRPC_POLICY_GSS = 2,
- SPTLRPC_POLICY_GSS_PIPEFS = 3,
SPTLRPC_POLICY_MAX,
};
};
/*
- * flavor compose/extract
+ * rpc flavor compose/extract, represented as 16 bits
+ *
+ * 4b (reserved) | 4b (svc) | 4b (mech) | 4b (policy)
*/
+#define RPC_FLVR_POLICY_OFFSET (0)
+#define RPC_FLVR_MECH_OFFSET (4)
+#define RPC_FLVR_SVC_OFFSET (8)
-typedef __u32 ptlrpc_sec_flavor_t;
+#define MAKE_RPC_FLVR(policy, mech, svc) \
+ (((__u16)(policy) << RPC_FLVR_POLICY_OFFSET) | \
+ ((__u16)(mech) << RPC_FLVR_MECH_OFFSET) | \
+ ((__u16)(svc) << RPC_FLVR_SVC_OFFSET))
-/*
- * 8b (reserved) | 8b (flags)
- * 4b (reserved) | 4b (svc) | 4b (mech) | 4b (policy)
- */
-#define SEC_FLAVOR_POLICY_OFFSET (0)
-#define SEC_FLAVOR_MECH_OFFSET (4)
-#define SEC_FLAVOR_SVC_OFFSET (8)
-#define SEC_FLAVOR_RESERVE1_OFFSET (12)
-#define SEC_FLAVOR_FLAGS_OFFSET (16)
-
-#define SEC_MAKE_RPC_FLAVOR(policy, mech, svc) \
- (((__u32)(policy) << SEC_FLAVOR_POLICY_OFFSET) | \
- ((__u32)(mech) << SEC_FLAVOR_MECH_OFFSET) | \
- ((__u32)(svc) << SEC_FLAVOR_SVC_OFFSET))
-
-#define SEC_MAKE_RPC_SUBFLAVOR(mech, svc) \
- ((__u32)(mech) | \
- ((__u32)(svc) << \
- (SEC_FLAVOR_SVC_OFFSET - SEC_FLAVOR_MECH_OFFSET)))
-
-#define SEC_FLAVOR_SUB(flavor) \
- ((((__u32)(flavor)) >> SEC_FLAVOR_MECH_OFFSET) & 0xFF)
-
-#define SEC_FLAVOR_POLICY(flavor) \
- ((((__u32)(flavor)) >> SEC_FLAVOR_POLICY_OFFSET) & 0xF)
-#define SEC_FLAVOR_MECH(flavor) \
- ((((__u32)(flavor)) >> SEC_FLAVOR_MECH_OFFSET) & 0xF)
-#define SEC_FLAVOR_SVC(flavor) \
- ((((__u32)(flavor)) >> SEC_FLAVOR_SVC_OFFSET) & 0xF)
-
-#define SEC_FLAVOR_RPC(f) \
- (((__u32) (f)) & ((1 << SEC_FLAVOR_RESERVE1_OFFSET) - 1))
+#define MAKE_RPC_SUBFLVR(mech, svc) \
+ ((__u16)(mech) | \
+ ((__u16)(svc) << (RPC_FLVR_SVC_OFFSET - RPC_FLVR_MECH_OFFSET)))
+
+#define RPC_FLVR_SUB(flavor) \
+ ((((__u16)(flavor)) >> RPC_FLVR_MECH_OFFSET) & 0xFF)
+
+#define RPC_FLVR_POLICY(flavor) \
+ ((((__u16)(flavor)) >> RPC_FLVR_POLICY_OFFSET) & 0xF)
+#define RPC_FLVR_MECH(flavor) \
+ ((((__u16)(flavor)) >> RPC_FLVR_MECH_OFFSET) & 0xF)
+#define RPC_FLVR_SVC(flavor) \
+ ((((__u16)(flavor)) >> RPC_FLVR_SVC_OFFSET) & 0xF)
/*
* gss subflavors
*/
-#define SPTLRPC_SUBFLVR_KRB5N \
- SEC_MAKE_RPC_SUBFLAVOR(SPTLRPC_MECH_GSS_KRB5, \
- SPTLRPC_SVC_NULL)
-#define SPTLRPC_SUBFLVR_KRB5A \
- SEC_MAKE_RPC_SUBFLAVOR(SPTLRPC_MECH_GSS_KRB5, \
- SPTLRPC_SVC_AUTH)
-#define SPTLRPC_SUBFLVR_KRB5I \
- SEC_MAKE_RPC_SUBFLAVOR(SPTLRPC_MECH_GSS_KRB5, \
- SPTLRPC_SVC_INTG)
-#define SPTLRPC_SUBFLVR_KRB5P \
- SEC_MAKE_RPC_SUBFLAVOR(SPTLRPC_MECH_GSS_KRB5, \
- SPTLRPC_SVC_PRIV)
+#define SPTLRPC_SUBFLVR_KRB5N \
+ MAKE_RPC_SUBFLVR(SPTLRPC_MECH_GSS_KRB5, SPTLRPC_SVC_NULL)
+#define SPTLRPC_SUBFLVR_KRB5A \
+ MAKE_RPC_SUBFLVR(SPTLRPC_MECH_GSS_KRB5, SPTLRPC_SVC_AUTH)
+#define SPTLRPC_SUBFLVR_KRB5I \
+ MAKE_RPC_SUBFLVR(SPTLRPC_MECH_GSS_KRB5, SPTLRPC_SVC_INTG)
+#define SPTLRPC_SUBFLVR_KRB5P \
+ MAKE_RPC_SUBFLVR(SPTLRPC_MECH_GSS_KRB5, SPTLRPC_SVC_PRIV)
/*
* "end user" flavors
*/
-#define SPTLRPC_FLVR_NULL \
- SEC_MAKE_RPC_FLAVOR(SPTLRPC_POLICY_NULL, \
- SPTLRPC_MECH_NULL, \
- SPTLRPC_SVC_NULL)
-#define SPTLRPC_FLVR_PLAIN \
- SEC_MAKE_RPC_FLAVOR(SPTLRPC_POLICY_PLAIN, \
- SPTLRPC_MECH_PLAIN, \
- SPTLRPC_SVC_NULL)
-#define SPTLRPC_FLVR_KRB5N \
- SEC_MAKE_RPC_FLAVOR(SPTLRPC_POLICY_GSS, \
- SPTLRPC_MECH_GSS_KRB5, \
- SPTLRPC_SVC_NULL)
-#define SPTLRPC_FLVR_KRB5A \
- SEC_MAKE_RPC_FLAVOR(SPTLRPC_POLICY_GSS, \
- SPTLRPC_MECH_GSS_KRB5, \
- SPTLRPC_SVC_AUTH)
-#define SPTLRPC_FLVR_KRB5I \
- SEC_MAKE_RPC_FLAVOR(SPTLRPC_POLICY_GSS, \
- SPTLRPC_MECH_GSS_KRB5, \
- SPTLRPC_SVC_INTG)
-#define SPTLRPC_FLVR_KRB5P \
- SEC_MAKE_RPC_FLAVOR(SPTLRPC_POLICY_GSS, \
- SPTLRPC_MECH_GSS_KRB5, \
- SPTLRPC_SVC_PRIV)
-
-#define SPTLRPC_FLVR_INVALID (-1)
+#define SPTLRPC_FLVR_NULL \
+ MAKE_RPC_FLVR(SPTLRPC_POLICY_NULL, \
+ SPTLRPC_MECH_NULL, \
+ SPTLRPC_SVC_NULL)
+#define SPTLRPC_FLVR_PLAIN \
+ MAKE_RPC_FLVR(SPTLRPC_POLICY_PLAIN, \
+ SPTLRPC_MECH_PLAIN, \
+ SPTLRPC_SVC_NULL)
+#define SPTLRPC_FLVR_KRB5N \
+ MAKE_RPC_FLVR(SPTLRPC_POLICY_GSS, \
+ SPTLRPC_MECH_GSS_KRB5, \
+ SPTLRPC_SVC_NULL)
+#define SPTLRPC_FLVR_KRB5A \
+ MAKE_RPC_FLVR(SPTLRPC_POLICY_GSS, \
+ SPTLRPC_MECH_GSS_KRB5, \
+ SPTLRPC_SVC_AUTH)
+#define SPTLRPC_FLVR_KRB5I \
+ MAKE_RPC_FLVR(SPTLRPC_POLICY_GSS, \
+ SPTLRPC_MECH_GSS_KRB5, \
+ SPTLRPC_SVC_INTG)
+#define SPTLRPC_FLVR_KRB5P \
+ MAKE_RPC_FLVR(SPTLRPC_POLICY_GSS, \
+ SPTLRPC_MECH_GSS_KRB5, \
+ SPTLRPC_SVC_PRIV)
+
+#define SPTLRPC_FLVR_INVALID ((__u16) -1)
#define SPTLRPC_FLVR_DEFAULT SPTLRPC_FLVR_NULL
/*
- * flavor flags (maximum 8 flags)
+ * 32 bits wire flavor (msg->lm_secflvr), lower 12 bits is the rpc flavor,
+ * higher 20 bits is not defined right now.
*/
-#define SEC_FLAVOR_FL_BULK (1 << (0 + SEC_FLAVOR_FLAGS_OFFSET))
-#define SEC_FLAVOR_FL_USER (1 << (1 + SEC_FLAVOR_FLAGS_OFFSET))
+#define WIRE_FLVR_RPC(wflvr) (((__u16) (wflvr)) & 0x0FFF)
+
+static inline void rpc_flvr_set_svc(__u16 *flvr, __u16 svc)
+{
+ LASSERT(svc < SPTLRPC_SVC_MAX);
+ *flvr = MAKE_RPC_FLVR(RPC_FLVR_POLICY(*flvr),
+ RPC_FLVR_MECH(*flvr),
+ svc);
+}
+
-#define SEC_FLAVOR_HAS_BULK(flavor) \
- (((flavor) & SEC_FLAVOR_FL_BULK) != 0)
-#define SEC_FLAVOR_HAS_USER(flavor) \
- (((flavor) & SEC_FLAVOR_FL_USER) != 0)
+struct sptlrpc_flavor {
+ __u16 sf_rpc; /* rpc flavor */
+ __u8 sf_bulk_priv; /* bulk encrypt alg */
+ __u8 sf_bulk_csum; /* bulk checksum alg */
+ __u32 sf_flags; /* general flags */
+};
+enum lustre_sec_part {
+ LUSTRE_SP_CLI = 0,
+ LUSTRE_SP_MDT,
+ LUSTRE_SP_OST,
+ LUSTRE_SP_MGS,
+ LUSTRE_SP_ANY = 0xFF
+};
-struct sec_flavor_config {
- __u32 sfc_rpc_flavor; /* main rpc flavor */
- __u32 sfc_bulk_priv; /* bulk encryption algorithm */
- __u32 sfc_bulk_csum; /* bulk checksum algorithm */
- __u32 sfc_flags; /* extra flags */
+struct sptlrpc_rule {
+ __u32 sr_netid; /* LNET network ID */
+ __u8 sr_from; /* sec_part */
+ __u8 sr_to; /* sec_part */
+ __u16 sr_padding;
+ struct sptlrpc_flavor sr_flvr;
};
-enum lustre_part {
- LUSTRE_CLI = 0,
- LUSTRE_MDT,
- LUSTRE_OST,
- LUSTRE_MGC,
- LUSTRE_MGS,
+struct sptlrpc_rule_set {
+ int srs_nslot;
+ int srs_nrule;
+ struct sptlrpc_rule *srs_rules;
+};
+
+#define SPTLRPC_CONF_LOG_MAX (64)
+
+struct sptlrpc_conf_log {
+ __u32 scl_max; /* maximum rules # */
+ __u32 scl_nrule; /* rules # */
+ __u8 scl_part; /* which part am i */
+ __u8 scl_pad0;
+ __u16 scl_pad1;
+ __u32 scl_pad2;
+ struct sptlrpc_rule scl_rules[SPTLRPC_CONF_LOG_MAX];
};
+static inline void sptlrpc_rule_set_init(struct sptlrpc_rule_set *set)
+{
+ memset(set, 0, sizeof(*set));
+}
+
+void sptlrpc_rule_set_free(struct sptlrpc_rule_set *set);
+int sptlrpc_rule_set_expand(struct sptlrpc_rule_set *set, int expand);
+int sptlrpc_rule_set_merge(struct sptlrpc_rule_set *set,
+ struct sptlrpc_rule *rule,
+ int expand);
+int sptlrpc_rule_set_from_log(struct sptlrpc_rule_set *rset,
+ struct sptlrpc_conf_log *log);
+void sptlrpc_rule_set_choose(struct sptlrpc_rule_set *rset,
+ enum lustre_sec_part from,
+ lnet_nid_t nid,
+ struct sptlrpc_flavor *flavor);
+void sptlrpc_rule_set_dump(struct sptlrpc_rule_set *set);
+
+struct sptlrpc_conf_log *sptlrpc_conf_log_alloc(void);
+void sptlrpc_conf_log_free(struct sptlrpc_conf_log *log);
+int sptlrpc_conf_log_populate(struct sptlrpc_rule_set *gen,
+ struct sptlrpc_rule_set *tgt,
+ enum lustre_sec_part from,
+ enum lustre_sec_part to,
+ unsigned int fl_udesc,
+ struct sptlrpc_conf_log *log);
+struct sptlrpc_conf_log *sptlrpc_conf_log_extract(struct lustre_cfg *lcfg);
+void sptlrpc_conf_log_cleanup(struct sptlrpc_conf_log *log);
+void sptlrpc_conf_log_dump(struct sptlrpc_conf_log *log);
+
+const char *sptlrpc_part2name(enum lustre_sec_part part);
+enum lustre_sec_part sptlrpc_target_sec_part(struct obd_device *obd);
+
+int sptlrpc_cliobd_process_config(struct obd_device *obd,
+ struct lustre_cfg *lcfg);
+
/* The maximum length of security payload. 1024 is enough for Kerberos 5,
* and should be enough for other future mechanisms but not sure.
* Only used by pre-allocated request/reply pool.
*/
struct ptlrpc_sec * (*create_sec) (struct obd_import *imp,
struct ptlrpc_svc_ctx *ctx,
- __u32 flavor,
- unsigned long flags);
+ struct sptlrpc_flavor *flavor);
void (*destroy_sec) (struct ptlrpc_sec *sec);
/*
+ * notify to-be-dead
+ */
+ void (*kill_sec) (struct ptlrpc_sec *sec);
+
+ /*
* context
*/
struct ptlrpc_cli_ctx * (*lookup_ctx) (struct ptlrpc_sec *sec,
* misc
*/
int (*display) (struct ptlrpc_sec *sec,
- char *buf, int buflen);
+ struct seq_file *seq);
};
struct ptlrpc_sec_sops {
struct ptlrpc_sec_policy {
struct module *sp_owner;
char *sp_name;
- __u32 sp_policy; /* policy number */
+ __u16 sp_policy; /* policy number */
struct ptlrpc_sec_cops *sp_cops; /* client ops */
struct ptlrpc_sec_sops *sp_sops; /* server ops */
};
#define PTLRPC_SEC_FL_REVERSE 0x0001 /* reverse sec */
#define PTLRPC_SEC_FL_ROOTONLY 0x0002 /* treat everyone as root */
-#define PTLRPC_SEC_FL_PAG 0x0004 /* PAG mode */
+#define PTLRPC_SEC_FL_UDESC 0x0004 /* ship udesc */
#define PTLRPC_SEC_FL_BULK 0x0008 /* intensive bulk i/o expected */
+#define PTLRPC_SEC_FL_PAG 0x0010 /* PAG mode */
struct ptlrpc_sec {
struct ptlrpc_sec_policy *ps_policy;
atomic_t ps_refcount;
- __u32 ps_flavor; /* rpc flavor */
- unsigned long ps_flags; /* PTLRPC_SEC_FL_XX */
+ atomic_t ps_nctx; /* statistic only */
+ int ps_id; /* unique identifier */
+ struct sptlrpc_flavor ps_flvr; /* flavor */
+ enum lustre_sec_part ps_part;
+ unsigned int ps_dying:1;
struct obd_import *ps_import; /* owning import */
spinlock_t ps_lock; /* protect ccache */
- atomic_t ps_busy; /* busy count */
/*
* garbage collection
*/
static inline int sec_is_reverse(struct ptlrpc_sec *sec)
{
- return (sec->ps_flags & PTLRPC_SEC_FL_REVERSE);
+ return (sec->ps_flvr.sf_flags & PTLRPC_SEC_FL_REVERSE);
}
static inline int sec_is_rootonly(struct ptlrpc_sec *sec)
{
- return (sec->ps_flags & PTLRPC_SEC_FL_ROOTONLY);
+ return (sec->ps_flvr.sf_flags & PTLRPC_SEC_FL_ROOTONLY);
}
struct ptlrpc_bulk_sec_desc {
__u32 bsd_version;
- __u32 bsd_pad;
- __u32 bsd_csum_alg; /* checksum algorithm */
- __u32 bsd_priv_alg; /* encrypt algorithm */
+ __u8 bsd_csum_alg; /* checksum algorithm */
+ __u8 bsd_priv_alg; /* encrypt algorithm */
+ __u16 bsd_pad;
__u8 bsd_iv[16]; /* encrypt iv */
__u8 bsd_csum[0];
};
-const char * sptlrpc_bulk_csum_alg2name(__u32 csum_alg);
-const char * sptlrpc_bulk_priv_alg2name(__u32 priv_alg);
-__u32 sptlrpc_bulk_priv_alg2flags(__u32 priv_alg);
+const char * sptlrpc_bulk_csum_alg2name(__u8 csum_alg);
+const char * sptlrpc_bulk_priv_alg2name(__u8 priv_alg);
+__u32 sptlrpc_bulk_priv_alg2flags(__u8 priv_alg);
/*
* lprocfs
int sptlrpc_register_policy(struct ptlrpc_sec_policy *policy);
int sptlrpc_unregister_policy(struct ptlrpc_sec_policy *policy);
-__u32 sptlrpc_name2flavor(const char *name);
-char *sptlrpc_flavor2name(__u32 flavor);
+__u16 sptlrpc_name2rpcflavor(const char *name);
+const char *sptlrpc_rpcflavor2name(__u16 flavor);
+int sptlrpc_flavor2name(struct sptlrpc_flavor *sf, char *buf, int bufsize);
static inline
struct ptlrpc_sec_policy *sptlrpc_policy_get(struct ptlrpc_sec_policy *policy)
}
/*
+ * sec get/put
+ */
+struct ptlrpc_sec *sptlrpc_sec_get(struct ptlrpc_sec *sec);
+void sptlrpc_sec_put(struct ptlrpc_sec *sec);
+
+/*
* internal apis which only used by policy impelentation
*/
+int sptlrpc_get_next_secid(void);
void sptlrpc_sec_destroy(struct ptlrpc_sec *sec);
/*
/*
* exported higher interface of import & request
*/
-int sptlrpc_import_get_sec(struct obd_import *imp, struct ptlrpc_svc_ctx *svc_ctx,
- __u32 flavor, unsigned long flags);
-void sptlrpc_import_put_sec(struct obd_import *imp);
+int sptlrpc_import_sec_adapt(struct obd_import *imp,
+ struct ptlrpc_svc_ctx *ctx,
+ __u16 rpc_flavor);
+struct ptlrpc_sec *sptlrpc_import_sec_ref(struct obd_import *imp);
+void sptlrpc_import_sec_put(struct obd_import *imp);
+
int sptlrpc_import_check_ctx(struct obd_import *imp);
+void sptlrpc_import_inval_all_ctx(struct obd_import *imp);
void sptlrpc_import_flush_root_ctx(struct obd_import *imp);
void sptlrpc_import_flush_my_ctx(struct obd_import *imp);
void sptlrpc_import_flush_all_ctx(struct obd_import *imp);
int sptlrpc_req_replace_dead_ctx(struct ptlrpc_request *req);
void sptlrpc_req_set_flavor(struct ptlrpc_request *req, int opcode);
-int sptlrpc_parse_flavor(enum lustre_part from, enum lustre_part to,
- char *str, struct sec_flavor_config *conf);
+int sptlrpc_parse_rule(char *param, struct sptlrpc_rule *rule);
/* gc */
void sptlrpc_gc_add_sec(struct ptlrpc_sec *sec);
/* misc */
const char * sec2target_str(struct ptlrpc_sec *sec);
-int sptlrpc_lprocfs_rd(char *page, char **start, off_t off, int count,
- int *eof, void *data);
+int sptlrpc_lprocfs_cliobd_attach(struct obd_device *dev);
/*
* server side
SECSVC_DROP,
};
-int sptlrpc_target_export_check(struct obd_export *exp,
- struct ptlrpc_request *req);
int sptlrpc_svc_unwrap_request(struct ptlrpc_request *req);
int sptlrpc_svc_alloc_rs(struct ptlrpc_request *req, int msglen);
int sptlrpc_svc_wrap_reply(struct ptlrpc_request *req);
void sptlrpc_svc_ctx_decref(struct ptlrpc_request *req);
void sptlrpc_svc_ctx_invalidate(struct ptlrpc_request *req);
+int sptlrpc_target_export_check(struct obd_export *exp,
+ struct ptlrpc_request *req);
+void sptlrpc_target_update_exp_flavor(struct obd_device *obd,
+ struct sptlrpc_rule_set *rset);
+
/*
* reverse context
*/
int sptlrpc_unpack_user_desc(struct lustre_msg *msg, int offset);
/* bulk helpers (internal use only by policies) */
-int bulk_sec_desc_size(__u32 csum_alg, int request, int read);
+int bulk_sec_desc_size(__u8 csum_alg, int request, int read);
int bulk_sec_desc_unpack(struct lustre_msg *msg, int offset);
int bulk_csum_cli_request(struct ptlrpc_bulk_desc *desc, int read,
struct upcall_cache_entry;
-struct mdt_setxid_perm {
+struct md_perm {
lnet_nid_t mp_nid;
__u32 mp_perm;
};
-struct mdt_identity {
+struct md_identity {
struct upcall_cache_entry *mi_uc_entry;
uid_t mi_uid;
gid_t mi_gid;
struct group_info *mi_ginfo;
int mi_nperms;
- struct mdt_setxid_perm *mi_perms;
-};
-
-struct rmtacl_upcall_data {
- uid_t aud_uid;
- gid_t aud_gid;
- char *aud_cmd;
-};
-
-struct mdt_rmtacl {
- uid_t ra_uid;
- gid_t ra_gid;
- __u32 ra_handle;
- char *ra_cmd;
- char *ra_buf;
+ struct md_perm *mi_perms;
};
struct upcall_cache_entry {
struct list_head ue_hash;
__u64 ue_key;
-// __u64 ue_primary;
-// struct group_info *ue_group_info;
atomic_t ue_refcount;
int ue_flags;
cfs_waitq_t ue_waitq;
cfs_time_t ue_acquire_expire;
cfs_time_t ue_expire;
union {
- struct mdt_identity identity;
- struct mdt_rmtacl acl;
+ struct md_identity identity;
} u;
};
struct md_object;
-typedef enum {
+enum {
UCRED_INVALID = -1,
UCRED_INIT = 0,
UCRED_OLD = 1,
- UCRED_NEW = 2,
-} ucred_t;
-
-#define SQUASH_NONE 0x00
-#define SQUASH_UID 0x01
-#define SQUASH_GID 0x02
+ UCRED_NEW = 2
+};
struct md_ucred {
- ucred_t mu_valid;
- __u32 mu_squash;
+ __u32 mu_valid;
__u32 mu_o_uid;
__u32 mu_o_gid;
__u32 mu_o_fsuid;
__u32 mu_cap;
__u32 mu_umask;
struct group_info *mu_ginfo;
- struct mdt_identity *mu_identity;
+ struct md_identity *mu_identity;
};
#define MD_CAPAINFO_MAX 5
int fo_fmd_max_num; /* per exp filter_mod_data */
int fo_fmd_max_age; /* jiffies to fmd expiry */
+ /* sptlrpc stuff */
+ rwlock_t fo_sptlrpc_lock;
+ struct sptlrpc_rule_set fo_sptlrpc_rset;
+
/* capability related */
unsigned int fo_fl_oss_capa;
struct list_head fo_capa_keys;
int cl_max_mds_cookiesize;
/* security configuration */
- struct sec_flavor_config cl_sec_conf;
+ struct sptlrpc_rule_set cl_sptlrpc_rset;
+ enum lustre_sec_part cl_sec_part;
//struct llog_canceld_ctxt *cl_llcd; /* it's included by obd_llog_ctxt */
void *cl_llcd_offset;
cfs_proc_dir_entry_t *mgs_proc_live;
};
-/* hah, upper limit 64 should be enough */
-#define N_NOSQUASH_NIDS 64
-struct rootsquash_info {
- uid_t rsi_uid;
- gid_t rsi_gid;
- int rsi_n_nosquash_nids;
- lnet_nid_t rsi_nosquash_nids[N_NOSQUASH_NIDS];
-};
-
struct mds_obd {
/* NB this field MUST be first */
struct obd_device_target mds_obt;
mds_fl_synced:1;
struct upcall_cache *mds_identity_cache;
- struct upcall_cache *mds_rmtacl_cache;
-
- /* root squash */
- struct rootsquash_info *mds_rootsquash_info;
/* for capability keys update */
struct lustre_capa_key *mds_capa_keys;
int (*o_connect)(const struct lu_env *env,
struct lustre_handle *conn, struct obd_device *src,
struct obd_uuid *cluuid, struct obd_connect_data *ocd);
- int (*o_reconnect)(struct obd_export *exp, struct obd_device *src,
+ int (*o_reconnect)(const struct lu_env *env,
+ struct obd_export *exp, struct obd_device *src,
struct obd_uuid *cluuid,
struct obd_connect_data *ocd);
int (*o_disconnect)(struct obd_export *exp);
struct ptlrpc_request **);
int (*m_getattr_name)(struct obd_export *, const struct lu_fid *,
struct obd_capa *, const char *, int, obd_valid,
- int, struct ptlrpc_request **);
+ int, __u32, struct ptlrpc_request **);
int (*m_intent_lock)(struct obd_export *, struct md_op_data *,
void *, int, struct lookup_intent *, int,
struct ptlrpc_request **,
int (*m_setxattr)(struct obd_export *, const struct lu_fid *,
struct obd_capa *, obd_valid, const char *,
- const char *, int, int, int,
+ const char *, int, int, int, __u32,
struct ptlrpc_request **);
int (*m_getxattr)(struct obd_export *, const struct lu_fid *,
renew_capa_cb_t cb);
int (*m_get_remote_perm)(struct obd_export *, const struct lu_fid *,
- struct obd_capa *, struct ptlrpc_request **);
+ struct obd_capa *, __u32,
+ struct ptlrpc_request **);
/*
* NOTE: If adding ops, add another LPROCFS_MD_OP_INIT() line to
RETURN(rc);
}
-static inline int obd_reconnect(struct obd_export *exp,
+static inline int obd_reconnect(const struct lu_env *env,
+ struct obd_export *exp,
struct obd_device *obd,
struct obd_uuid *cluuid,
struct obd_connect_data *d)
OBD_CHECK_DT_OP(obd, reconnect, 0);
OBD_COUNTER_INCREMENT(obd, reconnect);
- rc = OBP(obd, reconnect)(exp, obd, cluuid, d);
+ rc = OBP(obd, reconnect)(env, exp, obd, cluuid, d);
/* check that only subset is granted */
LASSERT(ergo(d != NULL,
(d->ocd_connect_flags & ocf) == d->ocd_connect_flags));
static inline int md_getattr_name(struct obd_export *exp,
const struct lu_fid *fid, struct obd_capa *oc,
const char *name, int namelen,
- obd_valid valid, int ea_size,
+ obd_valid valid, int ea_size, __u32 suppgid,
struct ptlrpc_request **request)
{
int rc;
EXP_CHECK_MD_OP(exp, getattr_name);
EXP_MD_COUNTER_INCREMENT(exp, getattr_name);
rc = MDP(exp->exp_obd, getattr_name)(exp, fid, oc, name, namelen,
- valid, ea_size, request);
+ valid, ea_size, suppgid, request);
RETURN(rc);
}
const struct lu_fid *fid, struct obd_capa *oc,
obd_valid valid, const char *name,
const char *input, int input_size,
- int output_size, int flags,
+ int output_size, int flags, __u32 suppgid,
struct ptlrpc_request **request)
{
ENTRY;
EXP_MD_COUNTER_INCREMENT(exp, setxattr);
RETURN(MDP(exp->exp_obd, setxattr)(exp, fid, oc, valid, name, input,
input_size, output_size, flags,
- request));
+ suppgid, request));
}
static inline int md_getxattr(struct obd_export *exp,
static inline int md_get_remote_perm(struct obd_export *exp,
const struct lu_fid *fid,
- struct obd_capa *oc,
+ struct obd_capa *oc, __u32 suppgid,
struct ptlrpc_request **request)
{
ENTRY;
EXP_CHECK_MD_OP(exp, get_remote_perm);
EXP_MD_COUNTER_INCREMENT(exp, get_remote_perm);
- RETURN(MDP(exp->exp_obd, get_remote_perm)(exp, fid, oc, request));
+ RETURN(MDP(exp->exp_obd, get_remote_perm)(exp, fid, oc, suppgid,
+ request));
}
static inline int md_renew_capa(struct obd_export *exp, struct obd_capa *ocapa,
#
# Security options
#
-# CONFIG_KEYS is not set
+CONFIG_KEYS=y
+CONFIG_KEYS_DEBUG_PROC_KEYS=y
CONFIG_SECURITY=y
CONFIG_SECURITY_NETWORK=y
# CONFIG_SECURITY_NETWORK_XFRM is not set
#
# Security options
#
-# CONFIG_KEYS is not set
+CONFIG_KEYS=y
+CONFIG_KEYS_DEBUG_PROC_KEYS=y
CONFIG_SECURITY=y
CONFIG_SECURITY_NETWORK=y
# CONFIG_SECURITY_NETWORK_XFRM is not set
#
# Security options
#
-# CONFIG_KEYS is not set
+CONFIG_KEYS=y
+CONFIG_KEYS_DEBUG_PROC_KEYS=y
CONFIG_SECURITY=y
CONFIG_SECURITY_NETWORK=y
# CONFIG_SECURITY_NETWORK_XFRM is not set
#
# Security options
#
-# CONFIG_KEYS is not set
+CONFIG_KEYS=y
+CONFIG_KEYS_DEBUG_PROC_KEYS=y
CONFIG_SECURITY=y
CONFIG_SECURITY_NETWORK=y
# CONFIG_SECURITY_NETWORK_XFRM is not set
static void destroy_import(struct obd_import *imp)
{
/* drop security policy instance after all rpc finished/aborted
- * to let all busy credentials be released.
- */
+ * to let all busy contexts be released. */
class_import_get(imp);
class_destroy_import(imp);
- sptlrpc_import_put_sec(imp);
+ sptlrpc_import_sec_put(imp);
class_import_put(imp);
}
sema_init(&cli->cl_sem, 1);
sema_init(&cli->cl_mgc_sem, 1);
- cli->cl_sec_conf.sfc_rpc_flavor = SPTLRPC_FLVR_NULL;
- cli->cl_sec_conf.sfc_bulk_csum = BULK_CSUM_ALG_NULL;
- cli->cl_sec_conf.sfc_bulk_priv = BULK_PRIV_ALG_NULL;
- cli->cl_sec_conf.sfc_flags = 0;
+ sptlrpc_rule_set_init(&cli->cl_sptlrpc_rset);
+ cli->cl_sec_part = LUSTRE_SP_ANY;
cli->cl_conn_count = 0;
memcpy(server_uuid.uuid, lustre_cfg_buf(lcfg, 2),
min_t(unsigned int, LUSTRE_CFG_BUFLEN(lcfg, 2),
int client_obd_cleanup(struct obd_device *obddev)
{
ENTRY;
+ sptlrpc_rule_set_free(&obddev->u.cli.cl_sptlrpc_rset);
ldlm_put_ref(obddev->obd_force);
RETURN(0);
}
if (rc != 0)
GOTO(out_ldlm, rc);
- rc = sptlrpc_import_get_sec(imp, NULL, cli->cl_sec_conf.sfc_rpc_flavor,
- cli->cl_sec_conf.sfc_flags);
- if (rc)
- GOTO(out_ldlm, rc);
-
ocd = &imp->imp_connect_data;
if (data) {
*ocd = *data;
&conn, target, &cluuid, data);
}
} else {
- rc = obd_reconnect(export, target, &cluuid, data);
+ rc = obd_reconnect(req->rq_svc_thread->t_env,
+ export, target, &cluuid, data);
}
if (rc)
GOTO(out, rc);
/* destroyed import can be still referenced in ctxt */
obd_set_info_async(export, strlen(KEY_REVIMP_UPD),
KEY_REVIMP_UPD, 0, NULL, NULL);
+
+ /* in some recovery senarios, previous ctx init rpc handled
+ * in sptlrpc_target_export_check() might be used to install
+ * a reverse ctx in this reverse import, and later OBD_CONNECT
+ * using the same gss ctx could reach here and following new
+ * reverse import. note all reverse ctx in new/old import are
+ * actually based on the same gss ctx. so we invalidate ctx
+ * here before destroy import, otherwise flush old import will
+ * lead to remote reverse ctx be destroied, thus the reverse
+ * ctx of new import will lost its peer.
+ * there might be a better way to deal with this???
+ */
+ sptlrpc_import_inval_all_ctx(export->exp_imp_reverse);
+
destroy_import(export->exp_imp_reverse);
}
lustre_msg_add_op_flags(req->rq_repmsg, MSG_CONNECT_NEXT_VER);
}
- rc = sptlrpc_import_get_sec(revimp, req->rq_svc_ctx,
- req->rq_sec_flavor, 0);
+ rc = sptlrpc_import_sec_adapt(revimp, req->rq_svc_ctx,
+ req->rq_flvr.sf_rpc);
if (rc) {
CERROR("Failed to get sec for reverse import: %d\n", rc);
export->exp_imp_reverse = NULL;
static int ldlm_callback_reply(struct ptlrpc_request *req, int rc)
{
+ if (req->rq_no_reply)
+ return 0;
+
req->rq_status = rc;
if (req->rq_reply_state == NULL) {
rc = lustre_pack_reply(req, 1, NULL, NULL);
MODULES := lustre llite_lloop
lustre-objs := dcache.o dir.o file.o llite_close.o llite_lib.o llite_nfs.o
lustre-objs += llite_fid.o rw.o lproc_llite.o namei.o symlink.o llite_mmap.o
-lustre-objs += xattr.o remote_perm.o llite_capa.o
+lustre-objs += xattr.o remote_perm.o llite_rmtacl.o llite_capa.o
lustre-objs += rw26.o super25.o
llite_lloop-objs := lloop.o
oc = ll_mdscapa_get(inode);
rc = md_getattr_name(sbi->ll_md_exp, ll_inode2fid(inode), oc,
filename, namelen, OBD_MD_FLID, 0,
- &request);
+ ll_i2suppgid(inode), &request);
capa_put(oc);
if (rc < 0) {
CDEBUG(D_INFO, "md_getattr_name: %d\n", rc);
}
case LL_IOC_FLUSHCTX:
RETURN(ll_flush_ctx(inode));
- case LL_IOC_GETFACL: {
- struct rmtacl_ioctl_data ioc;
-
- if (copy_from_user(&ioc, (void *)arg, sizeof(ioc)))
- RETURN(-EFAULT);
-
- RETURN(ll_ioctl_getfacl(inode, &ioc));
- }
- case LL_IOC_SETFACL: {
- struct rmtacl_ioctl_data ioc;
-
- if (copy_from_user(&ioc, (void *)arg, sizeof(ioc)))
- RETURN(-EFAULT);
+#ifdef CONFIG_FS_POSIX_ACL
+ case LL_IOC_RMTACL: {
+ if (sbi->ll_flags & LL_SBI_RMT_CLIENT &&
+ inode == inode->i_sb->s_root->d_inode) {
+ struct ll_file_data *fd = LUSTRE_FPRIVATE(file);
+ int rc;
- RETURN(ll_ioctl_setfacl(inode, &ioc));
+ LASSERT(fd != NULL);
+ rc = rct_add(&sbi->ll_rct, cfs_curproc_pid(), arg);
+ if (!rc)
+ fd->fd_flags |= LL_FILE_RMTACL;
+ RETURN(rc);
+ } else
+ RETURN(0);
}
+#endif
default:
RETURN(obd_iocontrol(cmd, sbi->ll_dt_exp,0,NULL,(void *)arg));
}
CDEBUG(D_VFSTRACE, "VFS Op:inode=%lu/%u(%p)\n", inode->i_ino,
inode->i_generation, inode);
- /* don't do anything for / */
- if (inode->i_sb->s_root == file->f_dentry)
- RETURN(0);
+#ifdef CONFIG_FS_POSIX_ACL
+ if (sbi->ll_flags & LL_SBI_RMT_CLIENT &&
+ inode == inode->i_sb->s_root->d_inode) {
+ struct ll_file_data *fd = LUSTRE_FPRIVATE(file);
+
+ LASSERT(fd != NULL);
+ if (unlikely(fd->fd_flags & LL_FILE_RMTACL)) {
+ fd->fd_flags &= ~LL_FILE_RMTACL;
+ rct_del(&sbi->ll_rct, cfs_curproc_pid());
+ et_search_free(&sbi->ll_et, cfs_curproc_pid());
+ }
+ }
+#endif
ll_stats_ops_tally(sbi, LPROC_LL_RELEASE, 1);
fd = LUSTRE_FPRIVATE(file);
CDEBUG(D_VFSTRACE, "VFS Op:inode=%lu/%u(%p), flags %o\n", inode->i_ino,
inode->i_generation, inode, file->f_flags);
- /* don't do anything for / */
- if (inode->i_sb->s_root == file->f_dentry)
- RETURN(0);
-
#ifdef HAVE_VFS_INTENT_PATCHES
it = file->f_it;
#else
oc = ll_mdscapa_get(inode);
rc = md_getattr_name(sbi->ll_md_exp, ll_inode2fid(inode),
oc, filename, strlen(filename) + 1,
- OBD_MD_FLEASIZE | OBD_MD_FLDIREA, lmmsize, &req);
+ OBD_MD_FLEASIZE | OBD_MD_FLDIREA, lmmsize,
+ ll_i2suppgid(inode), &req);
capa_put(oc);
if (rc < 0) {
CDEBUG(D_INFO, "md_getattr_name failed "
*/
case LL_IOC_FLUSHCTX:
RETURN(ll_flush_ctx(inode));
- case LL_IOC_GETFACL: {
- struct rmtacl_ioctl_data ioc;
-
- if (copy_from_user(&ioc, (void *)arg, sizeof(ioc)))
- RETURN(-EFAULT);
-
- RETURN(ll_ioctl_getfacl(inode, &ioc));
- }
- case LL_IOC_SETFACL: {
- struct rmtacl_ioctl_data ioc;
-
- if (copy_from_user(&ioc, (void *)arg, sizeof(ioc)))
- RETURN(-EFAULT);
-
- RETURN(ll_ioctl_setfacl(inode, &ioc));
- }
default: {
int err;
# include <linux/fs.h>
#ifdef HAVE_XATTR_ACL
# include <linux/xattr_acl.h>
-#endif
+#endif /* HAVE_XATTR_ACL */
#ifdef HAVE_LINUX_POSIX_ACL_XATTR_H
# include <linux/posix_acl_xattr.h>
-#endif
-#endif
+#endif /* HAVE_LINUX_POSIX_ACL_XATTR_H */
+#endif /* CONFIG_FS_POSIX_ACL */
#include <lustre_debug.h>
#include <lustre_ver.h>
#include <lustre_disk.h> /* for s2sbi */
+#include <lustre_eacl.h>
#ifndef FMODE_EXEC
#define FMODE_EXEC 0
#define LL_SBI_LOCALFLOCK 0x200 /* Local flocks support by kernel */
#define LL_SBI_LRU_RESIZE 0x400 /* lru resize support */
+#define RCE_HASHES 32
+
+struct rmtacl_ctl_entry {
+ struct list_head rce_list;
+ pid_t rce_key; /* hash key */
+ int rce_ops; /* acl operation type */
+};
+
+struct rmtacl_ctl_table {
+ spinlock_t rct_lock;
+ struct list_head rct_entries[RCE_HASHES];
+};
+
+#define EE_HASHES 32
+
+struct eacl_entry {
+ struct list_head ee_list;
+ pid_t ee_key; /* hash key */
+ struct lu_fid ee_fid;
+ int ee_type; /* ACL type for ACCESS or DEFAULT */
+ ext_acl_xattr_header *ee_acl;
+};
+
+struct eacl_table {
+ spinlock_t et_lock;
+ struct list_head et_entries[EE_HASHES];
+};
+
struct ll_sb_info {
struct list_head ll_list;
/* this protects pglist and ra_info. It isn't safe to
dev_t ll_sdev_orig; /* save s_dev before assign for
* clustred nfs */
+ struct rmtacl_ctl_table ll_rct;
+ struct eacl_table ll_et;
};
#define LL_DEFAULT_MAX_RW_CHUNK (32 * 1024 * 1024)
obd_id hash;
};
+__u32 ll_i2suppgid(struct inode *i);
void ll_i2gids(__u32 *suppgids, struct inode *i1,struct inode *i2);
#define LLAP_MAGIC 98764321
int ll_obd_statfs(struct inode *inode, void *arg);
int ll_get_max_mdsize(struct ll_sb_info *sbi, int *max_mdsize);
int ll_process_config(struct lustre_cfg *lcfg);
-int ll_ioctl_getfacl(struct inode *inode, struct rmtacl_ioctl_data *ioc);
-int ll_ioctl_setfacl(struct inode *inode, struct rmtacl_ioctl_data *ioc);
struct md_op_data *ll_prep_md_op_data(struct md_op_data *op_data,
struct inode *i1, struct inode *i2,
const char *name, int namelen,
void ll_clear_inode_capas(struct inode *inode);
void ll_print_capa_stat(struct ll_sb_info *sbi);
+/* llite/llite_rmtacl.c */
+#ifdef CONFIG_FS_POSIX_ACL
+obd_valid rce_ops2valid(int ops);
+struct rmtacl_ctl_entry *rct_search(struct rmtacl_ctl_table *rct, pid_t key);
+int rct_add(struct rmtacl_ctl_table *rct, pid_t key, int ops);
+int rct_del(struct rmtacl_ctl_table *rct, pid_t key);
+void rct_init(struct rmtacl_ctl_table *rct);
+void rct_fini(struct rmtacl_ctl_table *rct);
+
+void ee_free(struct eacl_entry *ee);
+int ee_add(struct eacl_table *et, pid_t key, struct lu_fid *fid, int type,
+ ext_acl_xattr_header *header);
+struct eacl_entry *et_search_del(struct eacl_table *et, pid_t key,
+ struct lu_fid *fid, int type);
+void et_search_free(struct eacl_table *et, pid_t key);
+void et_init(struct eacl_table *et);
+void et_fini(struct eacl_table *et);
+#endif
+
/* llite ioctl register support rountine */
#ifdef __KERNEL__
enum llioc_iter {
RETURN(rc);
}
-static int client_common_fill_super(struct super_block *sb, char *md, char *dt,
- uid_t nllu, gid_t nllg)
+static int client_common_fill_super(struct super_block *sb, char *md, char *dt)
{
struct inode *root = 0;
struct ll_sb_info *sbi = ll_s2sbi(sb);
data->ocd_connect_flags &= ~OBD_CONNECT_RMT_CLIENT;
data->ocd_connect_flags |= OBD_CONNECT_LCL_CLIENT;
}
- data->ocd_nllu = nllu;
- data->ocd_nllg = nllg;
err = obd_connect(NULL, &md_conn, obd, &sbi->ll_sb_uuid, data);
if (err == -EBUSY) {
GOTO(out_root, err);
}
+#ifdef CONFIG_FS_POSIX_ACL
+ if (sbi->ll_flags & LL_SBI_RMT_CLIENT) {
+ rct_init(&sbi->ll_rct);
+ et_init(&sbi->ll_et);
+ }
+#endif
+
checksum = sbi->ll_flags & LL_SBI_CHECKSUM;
err = obd_set_info_async(sbi->ll_dt_exp, strlen("checksum"),"checksum",
sizeof(checksum), &checksum, NULL);
struct ll_sb_info *sbi = ll_s2sbi(sb);
ENTRY;
+#ifdef CONFIG_FS_POSIX_ACL
+ if (sbi->ll_flags & LL_SBI_RMT_CLIENT) {
+ et_fini(&sbi->ll_et);
+ rct_fini(&sbi->ll_rct);
+ }
+#endif
+
obd_cancel_unused(sbi->ll_dt_exp, NULL, 0, NULL);
ll_close_thread_shutdown(sbi->ll_lcq);
sprintf(md, "%s-%s", lprof->lp_md, ll_instance);
/* connections, registrations, sb setup */
- err = client_common_fill_super(sb, md, dt,
- lsi->lsi_lmd->lmd_nllu,
- lsi->lsi_lmd->lmd_nllg);
+ err = client_common_fill_super(sb, md, dt);
out_free:
if (md)
capa_put(op_data->op_capa2);
OBD_FREE_PTR(op_data);
}
-
-int ll_ioctl_getfacl(struct inode *inode, struct rmtacl_ioctl_data *ioc)
-{
- struct ll_sb_info *sbi = ll_i2sbi(inode);
- struct ptlrpc_request *req = NULL;
- struct mdt_body *body;
- char *cmd, *buf;
- struct obd_capa *oc;
- int rc, buflen;
- ENTRY;
-
- if (!(sbi->ll_flags & LL_SBI_RMT_CLIENT))
- RETURN(-EBADE);
-
- LASSERT(ioc->cmd && ioc->cmd_len && ioc->res && ioc->res_len);
-
- OBD_ALLOC(cmd, ioc->cmd_len);
- if (!cmd)
- RETURN(-ENOMEM);
- if (copy_from_user(cmd, ioc->cmd, ioc->cmd_len))
- GOTO(out, rc = -EFAULT);
-
- oc = ll_mdscapa_get(inode);
- rc = md_getxattr(ll_i2sbi(inode)->ll_md_exp, ll_inode2fid(inode), oc,
- OBD_MD_FLXATTR, XATTR_NAME_LUSTRE_ACL, cmd,
- ioc->cmd_len, ioc->res_len, 0, &req);
- capa_put(oc);
- if (rc < 0) {
- CERROR("mdc_getxattr %s [%s] failed: %d\n",
- XATTR_NAME_LUSTRE_ACL, cmd, rc);
- GOTO(out, rc);
- }
-
- body = lustre_msg_buf(req->rq_repmsg, REPLY_REC_OFF, sizeof(*body));
- LASSERT(body);
-
- buflen = lustre_msg_buflen(req->rq_repmsg, REPLY_REC_OFF);
- LASSERT(buflen <= ioc->res_len);
- buf = lustre_msg_string(req->rq_repmsg, REPLY_REC_OFF + 1, ioc->res_len);
- LASSERT(buf);
- if (copy_to_user(ioc->res, buf, buflen))
- GOTO(out, rc = -EFAULT);
- EXIT;
-out:
- if (req)
- ptlrpc_req_finished(req);
- OBD_FREE(cmd, ioc->cmd_len);
- return rc;
-}
-
-int ll_ioctl_setfacl(struct inode *inode, struct rmtacl_ioctl_data *ioc)
-{
- struct ll_sb_info *sbi = ll_i2sbi(inode);
- struct ptlrpc_request *req = NULL;
- char *cmd, *buf;
- struct obd_capa *oc;
- int buflen, rc;
- ENTRY;
-
- if (!(sbi->ll_flags & LL_SBI_RMT_CLIENT))
- RETURN(-EBADE);
-
- if (!(sbi->ll_flags & LL_SBI_ACL))
- RETURN(-EOPNOTSUPP);
-
- LASSERT(ioc->cmd && ioc->cmd_len && ioc->res && ioc->res_len);
-
- OBD_ALLOC(cmd, ioc->cmd_len);
- if (!cmd)
- RETURN(-ENOMEM);
- if (copy_from_user(cmd, ioc->cmd, ioc->cmd_len))
- GOTO(out, rc = -EFAULT);
-
- oc = ll_mdscapa_get(inode);
- rc = md_setxattr(ll_i2sbi(inode)->ll_md_exp, ll_inode2fid(inode), oc,
- OBD_MD_FLXATTR, XATTR_NAME_LUSTRE_ACL, cmd,
- ioc->cmd_len, ioc->res_len, 0, &req);
- capa_put(oc);
- if (rc) {
- CERROR("mdc_setxattr %s [%s] failed: %d\n",
- XATTR_NAME_LUSTRE_ACL, cmd, rc);
- GOTO(out, rc);
- }
-
- buflen = lustre_msg_buflen(req->rq_repmsg, REPLY_REC_OFF);
- LASSERT(buflen <= ioc->res_len);
- buf = lustre_msg_string(req->rq_repmsg, REPLY_REC_OFF, ioc->res_len);
- LASSERT(buf);
- if (copy_to_user(ioc->res, buf, buflen))
- GOTO(out, rc = -EFAULT);
- EXIT;
-out:
- if (req)
- ptlrpc_req_finished(req);
- OBD_FREE(cmd, ioc->cmd_len);
- return rc;
-}
dir->i_ino, PFID(ll_inode2fid(dir)));
rc = md_getattr_name(sbi->ll_md_exp, ll_inode2fid(dir), NULL,
- dotdot, strlen(dotdot) + 1, 0, 0, &req);
+ dotdot, strlen(dotdot) + 1, 0, 0,
+ ll_i2suppgid(dir), &req);
if (rc) {
CERROR("failure %d inode %lu get parent\n", rc, dir->i_ino);
RETURN(ERR_PTR(rc));
--- /dev/null
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ * lustre/llite/llite_rmtacl.c
+ * Lustre Remote User Access Control List.
+ * Author: Fan Yong <fanyong@clusterfs.com>
+ *
+ * Copyright (c) 2004-2007 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_LLITE
+
+#ifdef CONFIG_FS_POSIX_ACL
+
+#include <lustre_lite.h>
+#include "llite_internal.h"
+
+static inline __u32 rce_hashfunc(uid_t id)
+{
+ return id & (RCE_HASHES - 1);
+}
+
+static inline __u32 ee_hashfunc(uid_t id)
+{
+ return id & (EE_HASHES - 1);
+}
+
+obd_valid rce_ops2valid(int ops)
+{
+ switch (ops) {
+ case RMT_LSETFACL:
+ return OBD_MD_FLRMTLSETFACL;
+ case RMT_LGETFACL:
+ return OBD_MD_FLRMTLGETFACL;
+ case RMT_RSETFACL:
+ return OBD_MD_FLRMTRSETFACL;
+ case RMT_RGETFACL:
+ return OBD_MD_FLRMTRGETFACL;
+ default:
+ return 0;
+ }
+}
+
+static struct rmtacl_ctl_entry *rce_alloc(pid_t key, int ops)
+{
+ struct rmtacl_ctl_entry *rce;
+
+ OBD_ALLOC_PTR(rce);
+ if (!rce)
+ return NULL;
+
+ CFS_INIT_LIST_HEAD(&rce->rce_list);
+ rce->rce_key = key;
+ rce->rce_ops = ops;
+
+ return rce;
+}
+
+static void rce_free(struct rmtacl_ctl_entry *rce)
+{
+ if (!list_empty(&rce->rce_list))
+ list_del(&rce->rce_list);
+
+ OBD_FREE_PTR(rce);
+}
+
+static struct rmtacl_ctl_entry *__rct_search(struct rmtacl_ctl_table *rct,
+ pid_t key)
+{
+ struct rmtacl_ctl_entry *rce;
+ struct list_head *head = &rct->rct_entries[rce_hashfunc(key)];
+
+ list_for_each_entry(rce, head, rce_list)
+ if (rce->rce_key == key)
+ return rce;
+
+ return NULL;
+}
+
+struct rmtacl_ctl_entry *rct_search(struct rmtacl_ctl_table *rct, pid_t key)
+{
+ struct rmtacl_ctl_entry *rce;
+
+ spin_lock(&rct->rct_lock);
+ rce = __rct_search(rct, key);
+ spin_unlock(&rct->rct_lock);
+ return rce;
+}
+
+int rct_add(struct rmtacl_ctl_table *rct, pid_t key, int ops)
+{
+ struct rmtacl_ctl_entry *rce, *e;
+
+ rce = rce_alloc(key, ops);
+ if (rce == NULL)
+ return -ENOMEM;
+
+ spin_lock(&rct->rct_lock);
+ e = __rct_search(rct, key);
+ if (unlikely(e != NULL)) {
+ CWARN("Unexpected stale rmtacl_entry found: "
+ "[key: %d] [ops: %d]\n", (int)key, ops);
+ rce_free(e);
+ }
+ list_add_tail(&rce->rce_list, &rct->rct_entries[rce_hashfunc(key)]);
+ spin_unlock(&rct->rct_lock);
+
+ return 0;
+}
+
+int rct_del(struct rmtacl_ctl_table *rct, pid_t key)
+{
+ struct rmtacl_ctl_entry *rce;
+
+ spin_lock(&rct->rct_lock);
+ rce = __rct_search(rct, key);
+ if (rce)
+ rce_free(rce);
+ spin_unlock(&rct->rct_lock);
+
+ return rce ? 0 : -ENOENT;
+}
+
+void rct_init(struct rmtacl_ctl_table *rct)
+{
+ int i;
+
+ spin_lock_init(&rct->rct_lock);
+ for (i = 0; i < RCE_HASHES; i++)
+ CFS_INIT_LIST_HEAD(&rct->rct_entries[i]);
+}
+
+void rct_fini(struct rmtacl_ctl_table *rct)
+{
+ struct rmtacl_ctl_entry *rce;
+ int i;
+
+ spin_lock(&rct->rct_lock);
+ for (i = 0; i < RCE_HASHES; i++)
+ while (!list_empty(&rct->rct_entries[i])) {
+ rce = list_entry(rct->rct_entries[i].next,
+ struct rmtacl_ctl_entry, rce_list);
+ rce_free(rce);
+ }
+ spin_unlock(&rct->rct_lock);
+}
+
+
+static struct eacl_entry *ee_alloc(pid_t key, struct lu_fid *fid, int type,
+ ext_acl_xattr_header *header)
+{
+ struct eacl_entry *ee;
+
+ OBD_ALLOC_PTR(ee);
+ if (!ee)
+ return NULL;
+
+ CFS_INIT_LIST_HEAD(&ee->ee_list);
+ ee->ee_key = key;
+ ee->ee_fid = *fid;
+ ee->ee_type = type;
+ ee->ee_acl = header;
+
+ return ee;
+}
+
+void ee_free(struct eacl_entry *ee)
+{
+ if (!list_empty(&ee->ee_list))
+ list_del(&ee->ee_list);
+
+ if (ee->ee_acl)
+ lustre_ext_acl_xattr_free(ee->ee_acl);
+
+ OBD_FREE_PTR(ee);
+}
+
+static struct eacl_entry *__et_search_del(struct eacl_table *et, pid_t key,
+ struct lu_fid *fid, int type)
+{
+ struct eacl_entry *ee;
+ struct list_head *head = &et->et_entries[ee_hashfunc(key)];
+
+ LASSERT(fid != NULL);
+ list_for_each_entry(ee, head, ee_list)
+ if (ee->ee_key == key) {
+ if (lu_fid_eq(&ee->ee_fid, fid) &&
+ ee->ee_type == type) {
+ list_del_init(&ee->ee_list);
+ return ee;
+ }
+ }
+
+ return NULL;
+}
+
+struct eacl_entry *et_search_del(struct eacl_table *et, pid_t key,
+ struct lu_fid *fid, int type)
+{
+ struct eacl_entry *ee;
+
+ spin_lock(&et->et_lock);
+ ee = __et_search_del(et, key, fid, type);
+ spin_unlock(&et->et_lock);
+ return ee;
+}
+
+void et_search_free(struct eacl_table *et, pid_t key)
+{
+ struct eacl_entry *ee, *next;
+ struct list_head *head = &et->et_entries[ee_hashfunc(key)];
+
+ spin_lock(&et->et_lock);
+ list_for_each_entry_safe(ee, next, head, ee_list)
+ if (ee->ee_key == key)
+ ee_free(ee);
+
+ spin_unlock(&et->et_lock);
+}
+
+int ee_add(struct eacl_table *et, pid_t key, struct lu_fid *fid, int type,
+ ext_acl_xattr_header *header)
+{
+ struct eacl_entry *ee, *e;
+
+ ee = ee_alloc(key, fid, type, header);
+ if (ee == NULL)
+ return -ENOMEM;
+
+ spin_lock(&et->et_lock);
+ e = __et_search_del(et, key, fid, type);
+ if (unlikely(e != NULL)) {
+ CWARN("Unexpected stale eacl_entry found: "
+ "[key: %d] [fid: "DFID"] [type: %d]\n",
+ (int)key, PFID(fid), type);
+ ee_free(e);
+ }
+ list_add_tail(&ee->ee_list, &et->et_entries[ee_hashfunc(key)]);
+ spin_unlock(&et->et_lock);
+
+ return 0;
+}
+
+void et_init(struct eacl_table *et)
+{
+ int i;
+
+ spin_lock_init(&et->et_lock);
+ for (i = 0; i < EE_HASHES; i++)
+ CFS_INIT_LIST_HEAD(&et->et_entries[i]);
+}
+
+void et_fini(struct eacl_table *et)
+{
+ struct eacl_entry *ee;
+ int i;
+
+ spin_lock(&et->et_lock);
+ for (i = 0; i < EE_HASHES; i++)
+ while (!list_empty(&et->et_entries[i])) {
+ ee = list_entry(et->et_entries[i].next,
+ struct eacl_entry, ee_list);
+ ee_free(ee);
+ }
+ spin_unlock(&et->et_lock);
+}
+
+#endif
RETURN(0);
}
+__u32 ll_i2suppgid(struct inode *i)
+{
+ if (in_group_p(i->i_gid))
+ return (__u32)i->i_gid;
+ else
+ return (__u32)(-1);
+}
+
/* Pack the required supplementary groups into the supplied groups array.
* If we don't need to use the groups from the target inode(s) then we
* instead pack one or more groups from the user's supplementary group
* array in case it might be useful. Not needed if doing an MDS-side upcall. */
void ll_i2gids(__u32 *suppgids, struct inode *i1, struct inode *i2)
{
+#if 0
int i;
+#endif
LASSERT(i1 != NULL);
LASSERT(suppgids != NULL);
- if (in_group_p(i1->i_gid))
- suppgids[0] = i1->i_gid;
- else
- suppgids[0] = -1;
+ suppgids[0] = ll_i2suppgid(i1);
- if (i2) {
- if (in_group_p(i2->i_gid))
- suppgids[1] = i2->i_gid;
+ if (i2)
+ suppgids[1] = ll_i2suppgid(i2);
else
suppgids[1] = -1;
- } else {
- suppgids[1] = -1;
- }
+#if 0
for (i = 0; i < current_ngroups; i++) {
if (suppgids[0] == -1) {
if (current_groups[i] != suppgids[1])
}
break;
}
+#endif
}
static void ll_d_add(struct dentry *de, struct inode *inode)
}
oc = ll_mdscapa_get(inode);
- rc = md_get_remote_perm(sbi->ll_md_exp, ll_inode2fid(inode), oc, &req);
+ rc = md_get_remote_perm(sbi->ll_md_exp, ll_inode2fid(inode), oc,
+ ll_i2suppgid(inode), &req);
capa_put(oc);
if (rc) {
up(&lli->lli_rmtperm_sem);
static
int xattr_type_filter(struct ll_sb_info *sbi, int xattr_type)
{
- if (((xattr_type == XATTR_ACL_ACCESS_T) ||
- (xattr_type == XATTR_ACL_DEFAULT_T)) &&
- (!(sbi->ll_flags & LL_SBI_ACL) ||
- (sbi->ll_flags & LL_SBI_RMT_CLIENT)))
+ if ((xattr_type == XATTR_ACL_ACCESS_T ||
+ xattr_type == XATTR_ACL_DEFAULT_T) &&
+ !(sbi->ll_flags & LL_SBI_ACL))
return -EOPNOTSUPP;
if (xattr_type == XATTR_USER_T && !(sbi->ll_flags & LL_SBI_USER_XATTR))
struct ptlrpc_request *req;
int xattr_type, rc;
struct obd_capa *oc;
+ posix_acl_xattr_header *new_value = NULL;
+ struct rmtacl_ctl_entry *rce = NULL;
+ ext_acl_xattr_header *acl = NULL;
+ const char *pv = value;
ENTRY;
xattr_type = get_xattr_type(name);
(xattr_type == XATTR_LUSTRE_T && strcmp(name, "lustre.lov") == 0))
RETURN(0);
+#ifdef CONFIG_FS_POSIX_ACL
+ if (sbi->ll_flags & LL_SBI_RMT_CLIENT &&
+ (xattr_type == XATTR_ACL_ACCESS_T ||
+ xattr_type == XATTR_ACL_DEFAULT_T)) {
+ rce = rct_search(&sbi->ll_rct, cfs_curproc_pid());
+ if (rce == NULL ||
+ (rce->rce_ops != RMT_LSETFACL &&
+ rce->rce_ops != RMT_RSETFACL))
+ RETURN(-EOPNOTSUPP);
+
+ if (rce->rce_ops == RMT_LSETFACL) {
+ struct eacl_entry *ee;
+
+ ee = et_search_del(&sbi->ll_et, cfs_curproc_pid(),
+ ll_inode2fid(inode), xattr_type);
+ LASSERT(ee != NULL);
+ if (valid & OBD_MD_FLXATTR) {
+ acl = lustre_acl_xattr_merge2ext(
+ (posix_acl_xattr_header *)value,
+ size, ee->ee_acl);
+ if (IS_ERR(acl)) {
+ ee_free(ee);
+ RETURN(PTR_ERR(acl));
+ }
+ size = CFS_ACL_XATTR_SIZE(\
+ le32_to_cpu(acl->a_count), \
+ ext_acl_xattr);
+ pv = (const char *)acl;
+ }
+ ee_free(ee);
+ } else if (rce->rce_ops == RMT_RSETFACL) {
+ size = lustre_posix_acl_xattr_filter(
+ (posix_acl_xattr_header *)value,
+ size, &new_value);
+ if (unlikely(size < 0))
+ RETURN(size);
+
+ pv = (const char *)new_value;
+ } else
+ RETURN(-EOPNOTSUPP);
+
+ valid |= rce_ops2valid(rce->rce_ops);
+ }
+#endif
oc = ll_mdscapa_get(inode);
- rc = md_setxattr(sbi->ll_md_exp, ll_inode2fid(inode), oc, valid, name,
- value, size, 0, flags, &req);
+ rc = md_setxattr(sbi->ll_md_exp, ll_inode2fid(inode), oc,
+ valid, name, pv, size, 0, flags, ll_i2suppgid(inode),
+ &req);
capa_put(oc);
+#ifdef CONFIG_FS_POSIX_ACL
+ if (new_value != NULL)
+ lustre_posix_acl_xattr_free(new_value, size);
+ if (acl != NULL)
+ lustre_ext_acl_xattr_free(acl);
+#endif
if (rc) {
if (rc == -EOPNOTSUPP && xattr_type == XATTR_USER_T) {
LCONSOLE_INFO("Disabling user_xattr feature because "
int xattr_type, rc;
void *xdata;
struct obd_capa *oc;
+ struct rmtacl_ctl_entry *rce = NULL;
ENTRY;
CDEBUG(D_VFSTRACE, "VFS Op:inode=%lu/%u(%p)\n",
if (rc)
RETURN(rc);
+#ifdef CONFIG_FS_POSIX_ACL
+ if (sbi->ll_flags & LL_SBI_RMT_CLIENT &&
+ (xattr_type == XATTR_ACL_ACCESS_T ||
+ xattr_type == XATTR_ACL_DEFAULT_T)) {
+ rce = rct_search(&sbi->ll_rct, cfs_curproc_pid());
+ if (rce == NULL ||
+ (rce->rce_ops != RMT_LSETFACL &&
+ rce->rce_ops != RMT_LGETFACL &&
+ rce->rce_ops != RMT_RSETFACL &&
+ rce->rce_ops != RMT_RGETFACL))
+ RETURN(-EOPNOTSUPP);
+ }
+#endif
+
/* posix acl is under protection of LOOKUP lock. when calling to this,
* we just have path resolution to the target inode, so we have great
* chance that cached ACL is uptodate.
*/
#ifdef CONFIG_FS_POSIX_ACL
- if (xattr_type == XATTR_ACL_ACCESS_T) {
+ if (xattr_type == XATTR_ACL_ACCESS_T &&
+ !(sbi->ll_flags & LL_SBI_RMT_CLIENT)) {
struct ll_inode_info *lli = ll_i2info(inode);
struct posix_acl *acl;
do_getxattr:
oc = ll_mdscapa_get(inode);
- rc = md_getxattr(sbi->ll_md_exp, ll_inode2fid(inode), oc, valid, name,
- NULL, 0, size, 0, &req);
+ rc = md_getxattr(sbi->ll_md_exp, ll_inode2fid(inode), oc,
+ valid | (rce ? rce_ops2valid(rce->rce_ops) : 0),
+ name, NULL, 0, size, 0, &req);
capa_put(oc);
if (rc) {
if (rc == -EOPNOTSUPP && xattr_type == XATTR_USER_T) {
GOTO(out, rc = -EFAULT);
}
+#ifdef CONFIG_FS_POSIX_ACL
+ if (body->eadatasize >= 0 && rce && rce->rce_ops == RMT_LSETFACL) {
+ ext_acl_xattr_header *acl;
+
+ acl = lustre_posix_acl_xattr_2ext((posix_acl_xattr_header *)xdata,
+ body->eadatasize);
+ if (IS_ERR(acl))
+ GOTO(out, rc = PTR_ERR(acl));
+
+ rc = ee_add(&sbi->ll_et, cfs_curproc_pid(), ll_inode2fid(inode),
+ xattr_type, acl);
+ if (unlikely(rc < 0)) {
+ lustre_ext_acl_xattr_free(acl);
+ GOTO(out, rc);
+ }
+ }
+
+ if (xattr_type == XATTR_ACL_ACCESS_T && !body->eadatasize)
+ GOTO(out, rc = -ENODATA);
+#endif
LASSERT(buffer);
memcpy(buffer, xdata, body->eadatasize);
rc = body->eadatasize;
+ EXIT;
out:
ptlrpc_req_finished(req);
- RETURN(rc);
+ return rc;
}
ssize_t ll_getxattr(struct dentry *dentry, const char *name,
static int lmv_setxattr(struct obd_export *exp, const struct lu_fid *fid,
struct obd_capa *oc, obd_valid valid, const char *name,
const char *input, int input_size, int output_size,
- int flags, struct ptlrpc_request **request)
+ int flags, __u32 suppgid,
+ struct ptlrpc_request **request)
{
struct obd_device *obd = exp->exp_obd;
struct lmv_obd *lmv = &obd->u.lmv;
RETURN(PTR_ERR(tgt_exp));
rc = md_setxattr(tgt_exp, fid, oc, valid, name,
- input, input_size, output_size, flags, request);
+ input, input_size, output_size, flags, suppgid,
+ request);
RETURN(rc);
}
static int
lmv_getattr_name(struct obd_export *exp, const struct lu_fid *fid,
struct obd_capa *oc, const char *filename, int namelen,
- obd_valid valid, int ea_size, struct ptlrpc_request **request)
+ obd_valid valid, int ea_size, __u32 suppgid,
+ struct ptlrpc_request **request)
{
struct obd_device *obd = exp->exp_obd;
struct lmv_obd *lmv = &obd->u.lmv;
namelen, filename, PFID(fid), PFID(&rid));
rc = md_getattr_name(tgt_exp, &rid, oc, filename, namelen, valid,
- ea_size, request);
+ ea_size, suppgid, request);
if (rc == 0) {
body = lustre_msg_buf((*request)->rq_repmsg,
REQ_REC_OFF, sizeof(*body));
rc = md_getattr_name(tgt_exp, &rid, NULL, NULL, 1,
valid | OBD_MD_FLCROSSREF,
- ea_size, &req);
+ ea_size, suppgid, &req);
ptlrpc_req_finished(*request);
*request = req;
}
static int lmv_get_remote_perm(struct obd_export *exp,
const struct lu_fid *fid,
- struct obd_capa *oc,
+ struct obd_capa *oc, __u32 suppgid,
struct ptlrpc_request **request)
{
struct obd_device *obd = exp->exp_obd;
if (IS_ERR(tgt_exp))
RETURN(PTR_ERR(tgt_exp));
- rc = md_get_remote_perm(tgt_exp, fid, oc, request);
+ rc = md_get_remote_perm(tgt_exp, fid, oc, suppgid, request);
RETURN(rc);
}
{ "mds_conn_uuid", lprocfs_rd_conn_uuid, 0, 0 },
{ "max_rpcs_in_flight", mdc_rd_max_rpcs_in_flight,
mdc_wr_max_rpcs_in_flight, 0 },
- { "sptlrpc", sptlrpc_lprocfs_rd, 0, 0 },
{ 0 }
};
#endif
void mdc_pack_req_body(struct ptlrpc_request *req, int offset,
__u64 valid, const struct lu_fid *fid,
- struct obd_capa *oc, int ea_size, int flags);
+ struct obd_capa *oc, int ea_size,
+ __u32 suppgid, int flags);
void mdc_pack_capa(struct ptlrpc_request *req, int offset, struct obd_capa *oc);
void mdc_pack_rep_body(struct ptlrpc_request *);
void mdc_is_subdir_pack(struct ptlrpc_request *req, int offset,
#endif
#endif
-static void mdc_pack_body(struct mdt_body *b)
+static void mdc_pack_body(struct mdt_body *b, __u32 suppgid)
{
LASSERT (b != NULL);
+ b->suppgid = suppgid;
+ b->uid = current->uid;
+ b->gid = current->gid;
b->fsuid = current->fsuid;
b->fsgid = current->fsgid;
b->capability = current->cap_effective;
void mdc_pack_req_body(struct ptlrpc_request *req, int offset,
__u64 valid, const struct lu_fid *fid,
- struct obd_capa *oc, int ea_size, int flags)
+ struct obd_capa *oc, int ea_size, __u32 suppgid,
+ int flags)
{
struct mdt_body *b = lustre_msg_buf(req->rq_reqmsg, offset, sizeof(*b));
b->valid = valid;
b->eadatasize = ea_size;
b->flags = flags;
- mdc_pack_body(b);
+ mdc_pack_body(b, suppgid);
if (fid) {
b->fid1 = *fid;
mdc_pack_capa(req, offset + 1, oc);
b = lustre_msg_buf(req->rq_reqmsg, offset, sizeof(*b));
b->fid1 = *fid;
b->size = pgoff; /* !! */
- b->suppgid = -1;
b->nlink = size; /* !! */
- mdc_pack_body(b);
+ mdc_pack_body(b, -1);
mdc_pack_capa(req, offset + 1, oc);
}
req->rq_send_state = level;
ptlrpc_req_set_repsize(req, 3, size);
- mdc_pack_req_body(req, REQ_REC_OFF, 0, NULL, NULL, 0, 0);
+ mdc_pack_req_body(req, REQ_REC_OFF, 0, NULL, NULL, 0, -1, 0);
lustre_msg_add_flags(req->rq_reqmsg, msg_flags);
rc = ptlrpc_queue_wait(req);
if (!req)
GOTO(out, rc = -ENOMEM);
- mdc_pack_req_body(req, REQ_REC_OFF, valid, fid, oc, ea_size,
+ mdc_pack_req_body(req, REQ_REC_OFF, valid, fid, oc, ea_size, -1,
MDS_BFLAG_EXT_FLAGS/*request "new" flags(bug 9486)*/);
if (valid & OBD_MD_FLRMTPERM)
int mdc_getattr_name(struct obd_export *exp, const struct lu_fid *fid,
struct obd_capa *oc, const char *filename, int namelen,
- obd_valid valid, int ea_size,
+ obd_valid valid, int ea_size, __u32 suppgid,
struct ptlrpc_request **request)
{
struct ptlrpc_request *req;
if (!req)
GOTO(out, rc = -ENOMEM);
- mdc_pack_req_body(req, REQ_REC_OFF, valid, fid, oc, ea_size,
+ mdc_pack_req_body(req, REQ_REC_OFF, valid, fid, oc, ea_size, suppgid,
MDS_BFLAG_EXT_FLAGS/*request "new" flags(bug 9486)*/);
if (filename) {
struct obd_capa *oc,
int opcode, obd_valid valid, const char *xattr_name,
const char *input, int input_size, int output_size,
- int flags, struct ptlrpc_request **request)
+ int flags, __u32 suppgid, struct ptlrpc_request **request)
{
struct ptlrpc_request *req;
int size[5] = { sizeof(struct ptlrpc_body), sizeof(struct mdt_body) };
int bufcnt = 3, offset = REQ_REC_OFF + 2;
- int rc, xattr_namelen = 0, remote_acl = 0;
+ int rc, xattr_namelen = 0;
void *tmp;
ENTRY;
GOTO(out, rc = -ENOMEM);
/* request data */
- mdc_pack_req_body(req, REQ_REC_OFF, valid, fid, oc, output_size, flags);
+ mdc_pack_req_body(req, REQ_REC_OFF, valid, fid, oc, output_size,
+ suppgid, flags);
if (xattr_name) {
tmp = lustre_msg_buf(req->rq_reqmsg, offset++, xattr_namelen);
memcpy(tmp, xattr_name, xattr_namelen);
- if (!strcmp(xattr_name, XATTR_NAME_LUSTRE_ACL))
- remote_acl = 1;
}
if (input_size) {
tmp = lustre_msg_buf(req->rq_reqmsg, offset++, input_size);
ptlrpc_req_set_repsize(req, bufcnt, size);
/* make rpc */
- /* NB: set remote acl doesn't need hold rpc lock, because it just
- * send command to MDS, and when it's executed on mountpoint on MDS,
- * another mdc_xattr_common() will be invoked there. */
- if (opcode == MDS_SETXATTR && !remote_acl)
+ if (opcode == MDS_SETXATTR)
mdc_get_rpc_lock(exp->exp_obd->u.cli.cl_rpc_lock, NULL);
rc = ptlrpc_queue_wait(req);
- if (opcode == MDS_SETXATTR && !remote_acl)
+ if (opcode == MDS_SETXATTR)
mdc_put_rpc_lock(exp->exp_obd->u.cli.cl_rpc_lock, NULL);
if (rc != 0)
int mdc_setxattr(struct obd_export *exp, const struct lu_fid *fid,
struct obd_capa *oc, obd_valid valid, const char *xattr_name,
const char *input, int input_size, int output_size, int flags,
- struct ptlrpc_request **request)
+ __u32 suppgid, struct ptlrpc_request **request)
{
return mdc_xattr_common(exp, fid, oc, MDS_SETXATTR, valid, xattr_name,
- input, input_size, output_size, flags, request);
+ input, input_size, output_size, flags, suppgid,
+ request);
}
int mdc_getxattr(struct obd_export *exp, const struct lu_fid *fid,
struct ptlrpc_request **request)
{
return mdc_xattr_common(exp, fid, oc, MDS_GETXATTR, valid, xattr_name,
- input, input_size, output_size, flags, request);
+ input, input_size, output_size, flags, -1,
+ request);
}
#ifdef CONFIG_FS_POSIX_ACL
if (!req)
RETURN(rc = -ENOMEM);
- mdc_pack_req_body(req, REQ_REC_OFF, 0, fid, oc, 0, 0);
+ mdc_pack_req_body(req, REQ_REC_OFF, 0, fid, oc, 0, -1, 0);
ptlrpc_req_set_repsize(req, 2, size);
GOTO(err_close_lock, rc);
lprocfs_mdc_init_vars(&lvars);
lprocfs_obd_setup(obd, lvars.obd_vars);
+ sptlrpc_lprocfs_cliobd_attach(obd);
ptlrpc_lprocfs_register_obd(obd);
rc = obd_llog_init(obd, NULL, obd, 0, NULL, NULL);
int rc = 0;
lprocfs_mdc_init_vars(&lvars);
-
- rc = class_process_proc_param(PARAM_MDC, lvars.obd_vars, lcfg, obd);
+
+ switch (lcfg->lcfg_command) {
+ case LCFG_SPTLRPC_CONF:
+ rc = sptlrpc_cliobd_process_config(obd, lcfg);
+ break;
+ default:
+ rc = class_process_proc_param(PARAM_MDC, lvars.obd_vars,
+ lcfg, obd);
+ break;
+ }
return(rc);
}
/* get remote permission for current user on fid */
int mdc_get_remote_perm(struct obd_export *exp, const struct lu_fid *fid,
- struct obd_capa *oc, struct ptlrpc_request **request)
+ struct obd_capa *oc, __u32 suppgid,
+ struct ptlrpc_request **request)
{
struct ptlrpc_request *req;
struct mdt_body *body;
if (!req)
RETURN(-ENOMEM);
- mdc_pack_req_body(req, REQ_REC_OFF, OBD_MD_FLRMTPERM, fid, oc, 0, 0);
+ mdc_pack_req_body(req, REQ_REC_OFF, OBD_MD_FLRMTPERM, fid, oc, 0,
+ suppgid, 0);
size[REPLY_REC_OFF + 1] = sizeof(*perm);
ptlrpc_req_set_repsize(req, 5, size);
RETURN(-ENOMEM);
mdc_pack_req_body(req, REQ_REC_OFF, OBD_MD_FLOSSCAPA,
- &oc->c_capa.lc_fid, oc, 0, 0);
+ &oc->c_capa.lc_fid, oc, 0, -1, 0);
ptlrpc_req_set_repsize(req, 5, size);
req->rq_async_args.pointer_arg[0] = oc;
#include <asm/semaphore.h>
#include <linux/lustre_acl.h>
+#include <lustre_eacl.h>
#include <obd.h>
#include <md_object.h>
#include <dt_object.h>
return 0;
}
-int mdd_in_group_p(struct md_ucred *uc, gid_t grp);
int mdd_acl_def_get(const struct lu_env *env, struct mdd_object *mdd_obj,
struct md_attr *ma);
int mdd_acl_chmod(const struct lu_env *env, struct mdd_object *o, __u32 mode,
(tmp_la->la_mode & ~S_IALLUGO);
/* Also check the setgid bit! */
- if (!mdd_in_group_p(uc, (la->la_valid & LA_GID) ? la->la_gid :
+ if (!lustre_in_group_p(uc, (la->la_valid & LA_GID) ? la->la_gid :
tmp_la->la_gid) && !mdd_capable(uc, CAP_FSETID))
la->la_mode &= ~S_ISGID;
} else {
la->la_gid = tmp_la->la_gid;
if (((uc->mu_fsuid != tmp_la->la_uid) ||
((la->la_gid != tmp_la->la_gid) &&
- !mdd_in_group_p(uc, la->la_gid))) &&
+ !lustre_in_group_p(uc, la->la_gid))) &&
!mdd_capable(uc, CAP_CHOWN))
RETURN(-EPERM);
#include <lustre_mds.h>
#include <lustre/lustre_idl.h>
-#ifdef CONFIG_FS_POSIX_ACL
-# include <linux/posix_acl_xattr.h>
-# include <linux/posix_acl.h>
-#endif
-
#include "mdd_internal.h"
-#define mdd_get_group_info(group_info) do { \
- atomic_inc(&(group_info)->usage); \
-} while (0)
-
-#define mdd_put_group_info(group_info) do { \
- if (atomic_dec_and_test(&(group_info)->usage)) \
- groups_free(group_info); \
-} while (0)
-
-#define MDD_NGROUPS_PER_BLOCK ((int)(CFS_PAGE_SIZE / sizeof(gid_t)))
-
-#define MDD_GROUP_AT(gi, i) \
- ((gi)->blocks[(i) / MDD_NGROUPS_PER_BLOCK][(i) % MDD_NGROUPS_PER_BLOCK])
-
-/*
- * groups_search() is copied from linux kernel!
- * A simple bsearch.
- */
-static int mdd_groups_search(struct group_info *group_info, gid_t grp)
-{
- int left, right;
-
- if (!group_info)
- return 0;
-
- left = 0;
- right = group_info->ngroups;
- while (left < right) {
- int mid = (left + right) / 2;
- int cmp = grp - MDD_GROUP_AT(group_info, mid);
-
- if (cmp > 0)
- left = mid + 1;
- else if (cmp < 0)
- right = mid;
- else
- return 1;
- }
- return 0;
-}
-
-int mdd_in_group_p(struct md_ucred *uc, gid_t grp)
-{
- int rc = 1;
-
- if (grp != uc->mu_fsgid) {
- struct group_info *group_info = NULL;
-
- if (uc->mu_ginfo || !uc->mu_identity ||
- uc->mu_valid == UCRED_OLD)
- if (grp == uc->mu_suppgids[0] ||
- grp == uc->mu_suppgids[1])
- return 1;
-
- if (uc->mu_ginfo)
- group_info = uc->mu_ginfo;
- else if (uc->mu_identity)
- group_info = uc->mu_identity->mi_ginfo;
-
- if (!group_info)
- return 0;
-
- mdd_get_group_info(group_info);
- rc = mdd_groups_search(group_info, grp);
- mdd_put_group_info(group_info);
- }
- return rc;
-}
-
#ifdef CONFIG_FS_POSIX_ACL
-static inline void mdd_acl_le_to_cpu(posix_acl_xattr_entry *p)
-{
- p->e_tag = le16_to_cpu(p->e_tag);
- p->e_perm = le16_to_cpu(p->e_perm);
- p->e_id = le32_to_cpu(p->e_id);
-}
-
-static inline void mdd_acl_cpu_to_le(posix_acl_xattr_entry *p)
-{
- p->e_tag = cpu_to_le16(p->e_tag);
- p->e_perm = cpu_to_le16(p->e_perm);
- p->e_id = cpu_to_le32(p->e_id);
-}
-
-/*
- * Check permission based on POSIX ACL.
- */
-static int mdd_posix_acl_permission(struct md_ucred *uc, struct lu_attr *la,
- int want, posix_acl_xattr_entry *entry,
- int count)
-{
- posix_acl_xattr_entry *pa, *pe, *mask_obj;
- int found = 0;
- ENTRY;
-
- if (count <= 0)
- RETURN(-EACCES);
-
- for (pa = &entry[0], pe = &entry[count - 1]; pa <= pe; pa++) {
- mdd_acl_le_to_cpu(pa);
- switch(pa->e_tag) {
- case ACL_USER_OBJ:
- /* (May have been checked already) */
- if (la->la_uid == uc->mu_fsuid)
- goto check_perm;
- break;
- case ACL_USER:
- if (pa->e_id == uc->mu_fsuid)
- goto mask;
- break;
- case ACL_GROUP_OBJ:
- if (mdd_in_group_p(uc, la->la_gid)) {
- found = 1;
- if ((pa->e_perm & want) == want)
- goto mask;
- }
- break;
- case ACL_GROUP:
- if (mdd_in_group_p(uc, pa->e_id)) {
- found = 1;
- if ((pa->e_perm & want) == want)
- goto mask;
- }
- break;
- case ACL_MASK:
- break;
- case ACL_OTHER:
- if (found)
- RETURN(-EACCES);
- else
- goto check_perm;
- default:
- RETURN(-EIO);
- }
- }
- RETURN(-EIO);
-
-mask:
- for (mask_obj = pa + 1; mask_obj <= pe; mask_obj++) {
- mdd_acl_le_to_cpu(mask_obj);
- if (mask_obj->e_tag == ACL_MASK) {
- if ((pa->e_perm & mask_obj->e_perm & want) == want)
- RETURN(0);
-
- RETURN(-EACCES);
- }
- }
-
-check_perm:
- if ((pa->e_perm & want) == want)
- RETURN(0);
-
- RETURN(-EACCES);
-}
/*
* Get default acl EA only.
}
/*
- * Modify the ACL for the chmod.
- */
-static int mdd_posix_acl_chmod_masq(posix_acl_xattr_entry *entry,
- __u32 mode, int count)
-{
- posix_acl_xattr_entry *group_obj = NULL, *mask_obj = NULL, *pa, *pe;
-
- for (pa = &entry[0], pe = &entry[count - 1]; pa <= pe; pa++) {
- mdd_acl_le_to_cpu(pa);
- switch(pa->e_tag) {
- case ACL_USER_OBJ:
- pa->e_perm = (mode & S_IRWXU) >> 6;
- break;
-
- case ACL_USER:
- case ACL_GROUP:
- break;
-
- case ACL_GROUP_OBJ:
- group_obj = pa;
- break;
-
- case ACL_MASK:
- mask_obj = pa;
- break;
-
- case ACL_OTHER:
- pa->e_perm = (mode & S_IRWXO);
- break;
-
- default:
- return -EIO;
- }
- mdd_acl_cpu_to_le(pa);
- }
-
- if (mask_obj) {
- mask_obj->e_perm = cpu_to_le16((mode & S_IRWXG) >> 3);
- } else {
- if (!group_obj)
- return -EIO;
- group_obj->e_perm = cpu_to_le16((mode & S_IRWXG) >> 3);
- }
-
- return 0;
-}
-
-/*
* Hold write_lock for o.
*/
int mdd_acl_chmod(const struct lu_env *env, struct mdd_object *o, __u32 mode,
if (entry_count <= 0)
RETURN(0);
- rc = mdd_posix_acl_chmod_masq(entry, mode, entry_count);
+ rc = lustre_posix_acl_chmod_masq(entry, mode, entry_count);
if (rc)
RETURN(rc);
}
/*
- * Modify acl when creating a new obj.
- */
-static int mdd_posix_acl_create_masq(posix_acl_xattr_entry *entry,
- __u32 *mode_p, int count)
-{
- posix_acl_xattr_entry *group_obj = NULL, *mask_obj = NULL, *pa, *pe;
- __u32 mode = *mode_p;
- int not_equiv = 0;
-
- for (pa = &entry[0], pe = &entry[count - 1]; pa <= pe; pa++) {
- mdd_acl_le_to_cpu(pa);
- switch(pa->e_tag) {
- case ACL_USER_OBJ:
- pa->e_perm &= (mode >> 6) | ~S_IRWXO;
- mode &= (pa->e_perm << 6) | ~S_IRWXU;
- break;
-
- case ACL_USER:
- case ACL_GROUP:
- not_equiv = 1;
- break;
-
- case ACL_GROUP_OBJ:
- group_obj = pa;
- break;
-
- case ACL_OTHER:
- pa->e_perm &= mode | ~S_IRWXO;
- mode &= pa->e_perm | ~S_IRWXO;
- break;
-
- case ACL_MASK:
- mask_obj = pa;
- not_equiv = 1;
- break;
-
- default:
- return -EIO;
- }
- mdd_acl_cpu_to_le(pa);
- }
-
- if (mask_obj) {
- mask_obj->e_perm = le16_to_cpu(mask_obj->e_perm) &
- ((mode >> 3) | ~S_IRWXO);
- mode &= (mask_obj->e_perm << 3) | ~S_IRWXG;
- mask_obj->e_perm = cpu_to_le16(mask_obj->e_perm);
- } else {
- if (!group_obj)
- return -EIO;
- group_obj->e_perm = le16_to_cpu(group_obj->e_perm) &
- ((mode >> 3) | ~S_IRWXO);
- mode &= (group_obj->e_perm << 3) | ~S_IRWXG;
- group_obj->e_perm = cpu_to_le16(group_obj->e_perm);
- }
-
- *mode_p = (*mode_p & ~S_IRWXUGO) | mode;
- return not_equiv;
-}
-
-/*
* Hold write_lock for obj.
*/
int __mdd_acl_init(const struct lu_env *env, struct mdd_object *obj,
RETURN(rc);
}
- rc = mdd_posix_acl_create_masq(entry, mode, entry_count);
+ rc = lustre_posix_acl_create_masq(entry, mode, entry_count);
if (rc <= 0)
RETURN(rc);
entry_count = (buf->lb_len - sizeof(head->a_version)) /
sizeof(posix_acl_xattr_entry);
- rc = mdd_posix_acl_permission(uc, la, mask, entry, entry_count);
+ rc = lustre_posix_acl_permission(uc, la, mask, entry, entry_count);
RETURN(rc);
#else
ENTRY;
(rc != -ENODATA))
RETURN(rc);
}
- if (mdd_in_group_p(uc, la->la_gid))
+ if (lustre_in_group_p(uc, la->la_gid))
mode >>= 3;
}
struct md_attr *ma, int mask)
{
struct mdd_object *mdd_pobj, *mdd_cobj;
+ struct md_ucred *uc = NULL;
struct lu_attr *la = NULL;
int check_create, check_link;
int check_unlink;
int check_rename_src, check_rename_tar;
int check_vtx_part, check_vtx_full;
+ int check_rgetfacl;
int rc = 0;
ENTRY;
check_rename_tar = mask & MAY_RENAME_TAR;
check_vtx_part = mask & MAY_VTX_PART;
check_vtx_full = mask & MAY_VTX_FULL;
+ check_rgetfacl = mask & MAY_RGETFACL;
mask &= ~(MAY_CREATE | MAY_LINK |
MAY_UNLINK |
MAY_RENAME_SRC | MAY_RENAME_TAR |
- MAY_VTX_PART | MAY_VTX_FULL);
+ MAY_VTX_PART | MAY_VTX_FULL |
+ MAY_RGETFACL);
rc = mdd_permission_internal_locked(env, mdd_cobj, NULL, mask);
}
if (!rc && (check_vtx_part || check_vtx_full)) {
- struct md_ucred *uc = md_ucred(env);
-
+ uc = md_ucred(env);
LASSERT(ma);
if (likely(!la)) {
la = &mdd_env_info(env)->mti_la;
}
}
+ if (unlikely(!rc && check_rgetfacl)) {
+ if (likely(!uc))
+ uc = md_ucred(env);
+
+ if (likely(!la)) {
+ la = &mdd_env_info(env)->mti_la;
+ rc = mdd_la_get(env, mdd_cobj, la, BYPASS_CAPA);
+ if (rc)
+ RETURN(rc);
+ }
+
+ if (la->la_uid != uc->mu_fsuid && !mdd_capable(uc, CAP_FOWNER))
+ rc = -EPERM;
+ }
+
RETURN(rc);
}
return 0;
}
-static int mds_reconnect(struct obd_export *exp, struct obd_device *obd,
+static int mds_reconnect(const struct lu_env *env,
+ struct obd_export *exp, struct obd_device *obd,
struct obd_uuid *cluuid,
struct obd_connect_data *data)
{
LASSERT(exp);
med = &exp->exp_mds_data;
+ exp->exp_flvr.sf_rpc = SPTLRPC_FLVR_NULL;
+
rc = mds_connect_internal(exp, data);
if (rc)
GOTO(out, rc);
MODULES := mdt
mdt-objs := mdt_handler.o mdt_lib.o mdt_reint.o mdt_xattr.o mdt_recovery.o
-mdt-objs += mdt_open.o mdt_idmap.o mdt_identity.o mdt_rmtacl.o mdt_capa.o mdt_lproc.o
+mdt-objs += mdt_open.o mdt_idmap.o mdt_identity.o mdt_capa.o mdt_lproc.o
@INCLUDE_RULES@
if (reqbody == NULL || repbody == NULL)
RETURN(err_serious(-EFAULT));
- rc = mdt_check_ucred(info);
- if (rc)
- RETURN(err_serious(rc));
-
/*
* prepare @rdpg before calling lower layers and transfer itself. Here
* reqbody->size contains offset of where to start to read and
mdt_fs_cleanup(env, m);
- upcall_cache_cleanup(m->mdt_rmtacl_cache);
- m->mdt_rmtacl_cache = NULL;
-
upcall_cache_cleanup(m->mdt_identity_cache);
m->mdt_identity_cache = NULL;
ptlrpc_lprocfs_unregister_obd(d->ld_obd);
lprocfs_obd_cleanup(d->ld_obd);
- if (m->mdt_rootsquash_info) {
- OBD_FREE_PTR(m->mdt_rootsquash_info);
- m->mdt_rootsquash_info = NULL;
- }
+ sptlrpc_rule_set_free(&m->mdt_sptlrpc_rset);
next->md_ops->mdo_init_capa_ctxt(env, next, 0, 0, 0, NULL);
del_timer(&m->mdt_ck_timer);
struct lustre_mount_info *lmi;
struct lustre_sb_info *lsi;
struct lu_site *s;
+ const char *identity_upcall = "NONE";
int rc;
ENTRY;
server_put_mount_2(dev, lmi->lmi_mnt);
}
+ m->mdt_sptlrpc_lock = RW_LOCK_UNLOCKED;
+ sptlrpc_rule_set_init(&m->mdt_sptlrpc_rset);
+
spin_lock_init(&m->mdt_ioepoch_lock);
m->mdt_opts.mo_compat_resname = 0;
m->mdt_capa_timeout = CAPA_TIMEOUT;
/* set obd_namespace for compatibility with old code */
obd->obd_namespace = m->mdt_namespace;
- m->mdt_identity_cache = upcall_cache_init(obd->obd_name,
- "NONE",
+ /* XXX: to support suppgid for ACL, we enable identity_upcall
+ * by default, otherwise, maybe got unexpected -EACCESS. */
+ if (m->mdt_opts.mo_acl)
+ identity_upcall = MDT_IDENTITY_UPCALL_PATH;
+
+ m->mdt_identity_cache = upcall_cache_init(obd->obd_name, identity_upcall,
&mdt_identity_upcall_cache_ops);
if (IS_ERR(m->mdt_identity_cache)) {
rc = PTR_ERR(m->mdt_identity_cache);
GOTO(err_free_ns, rc);
}
- m->mdt_rmtacl_cache = upcall_cache_init(obd->obd_name,
- MDT_RMTACL_UPCALL_PATH,
- &mdt_rmtacl_upcall_cache_ops);
- if (IS_ERR(m->mdt_rmtacl_cache)) {
- rc = PTR_ERR(m->mdt_rmtacl_cache);
- m->mdt_rmtacl_cache = NULL;
- GOTO(err_free_ns, rc);
- }
-
m->mdt_ck_timer.function = mdt_ck_timer_callback;
m->mdt_ck_timer.data = (unsigned long)m;
init_timer(&m->mdt_ck_timer);
del_timer(&m->mdt_ck_timer);
mdt_ck_thread_stop(m);
err_free_ns:
- upcall_cache_cleanup(m->mdt_rmtacl_cache);
- m->mdt_rmtacl_cache = NULL;
upcall_cache_cleanup(m->mdt_identity_cache);
m->mdt_identity_cache = NULL;
ldlm_namespace_free(m->mdt_namespace, 0);
ENTRY;
switch (cfg->lcfg_command) {
+ case LCFG_SPTLRPC_CONF: {
+ struct sptlrpc_conf_log *log;
+ struct sptlrpc_rule_set tmp_rset;
+
+ log = sptlrpc_conf_log_extract(cfg);
+ if (IS_ERR(log)) {
+ rc = PTR_ERR(log);
+ break;
+ }
+
+ sptlrpc_rule_set_init(&tmp_rset);
+
+ rc = sptlrpc_rule_set_from_log(&tmp_rset, log);
+ if (rc) {
+ CERROR("mdt %p: failed get sptlrpc rules: %d\n", m, rc);
+ break;
+ }
+
+ write_lock(&m->mdt_sptlrpc_lock);
+ sptlrpc_rule_set_free(&m->mdt_sptlrpc_rset);
+ m->mdt_sptlrpc_rset = tmp_rset;
+ write_unlock(&m->mdt_sptlrpc_lock);
+
+ sptlrpc_target_update_exp_flavor(
+ md2lu_dev(&m->mdt_md_dev)->ld_obd, &tmp_rset);
+
+ break;
+ }
case LCFG_PARAM: {
struct lprocfs_static_vars lvars;
struct obd_device *obd = d->ld_obd;
struct obd_uuid *cluuid,
struct obd_connect_data *data)
{
+ struct mdt_thread_info *info;
struct mdt_client_data *mcd;
struct obd_export *exp;
struct mdt_device *mdt;
+ struct ptlrpc_request *req;
int rc;
ENTRY;
if (!conn || !obd || !cluuid)
RETURN(-EINVAL);
+ info = lu_context_key_get(&env->le_ctx, &mdt_thread_key);
+ req = info->mti_pill.rc_req;
mdt = mdt_dev(obd->obd_lu_dev);
rc = class_connect(conn, obd, cluuid);
exp = class_conn2export(conn);
LASSERT(exp != NULL);
+ CDEBUG(D_SEC, "from %s\n", sptlrpc_part2name(req->rq_sp_from));
+
+ spin_lock(&exp->exp_lock);
+ exp->exp_sp_peer = req->rq_sp_from;
+
+ read_lock(&mdt->mdt_sptlrpc_lock);
+ sptlrpc_rule_set_choose(&mdt->mdt_sptlrpc_rset, exp->exp_sp_peer,
+ req->rq_peer.nid, &exp->exp_flvr);
+ read_unlock(&mdt->mdt_sptlrpc_lock);
+
+ if (exp->exp_flvr.sf_rpc != req->rq_flvr.sf_rpc) {
+ CERROR("invalid rpc flavor %x, expect %x, from %s\n",
+ req->rq_flvr.sf_rpc, exp->exp_flvr.sf_rpc,
+ libcfs_nid2str(req->rq_peer.nid));
+ exp->exp_flvr.sf_rpc = SPTLRPC_FLVR_INVALID;
+ spin_unlock(&exp->exp_lock);
+ RETURN(-EACCES);
+ }
+ spin_unlock(&exp->exp_lock);
+
rc = mdt_connect_internal(exp, mdt, data);
if (rc == 0) {
OBD_ALLOC_PTR(mcd);
RETURN(rc);
}
-static int mdt_obd_reconnect(struct obd_export *exp, struct obd_device *obd,
+static int mdt_obd_reconnect(const struct lu_env *env,
+ struct obd_export *exp, struct obd_device *obd,
struct obd_uuid *cluuid,
struct obd_connect_data *data)
{
- int rc;
+ struct mdt_thread_info *info;
+ struct mdt_device *mdt;
+ struct ptlrpc_request *req;
+ int rc;
ENTRY;
if (exp == NULL || obd == NULL || cluuid == NULL)
RETURN(-EINVAL);
+ info = lu_context_key_get(&env->le_ctx, &mdt_thread_key);
+ req = info->mti_pill.rc_req;
+ mdt = mdt_dev(obd->obd_lu_dev);
+
+ CDEBUG(D_SEC, "from %s\n", sptlrpc_part2name(req->rq_sp_from));
+
+ spin_lock(&exp->exp_lock);
+ if (exp->exp_flvr.sf_rpc == SPTLRPC_FLVR_INVALID) {
+ exp->exp_sp_peer = req->rq_sp_from;
+
+ read_lock(&mdt->mdt_sptlrpc_lock);
+ sptlrpc_rule_set_choose(&mdt->mdt_sptlrpc_rset,
+ exp->exp_sp_peer,
+ req->rq_peer.nid, &exp->exp_flvr);
+ read_unlock(&mdt->mdt_sptlrpc_lock);
+
+ if (exp->exp_flvr.sf_rpc != req->rq_flvr.sf_rpc) {
+ CERROR("invalid rpc flavor %x, expect %x, from %s\n",
+ req->rq_flvr.sf_rpc, exp->exp_flvr.sf_rpc,
+ libcfs_nid2str(req->rq_peer.nid));
+ exp->exp_flvr.sf_rpc = SPTLRPC_FLVR_INVALID;
+ spin_unlock(&exp->exp_lock);
+ RETURN(-EACCES);
+ }
+ }
+ spin_unlock(&exp->exp_lock);
+
rc = mdt_connect_internal(exp, mdt_dev(obd->obd_lu_dev), data);
RETURN(rc);
INIT_LIST_HEAD(&med->med_open_head);
spin_lock_init(&med->med_open_lock);
+ sema_init(&med->med_idmap_sem, 1);
+ med->med_idmap = NULL;
spin_lock(&exp->exp_lock);
exp->exp_connecting = 1;
spin_unlock(&exp->exp_lock);
.mos_hs = mdt_obd_ops
},
{
+ .mos_opc_start = SEC_CTX_INIT,
+ .mos_opc_end = SEC_LAST_OPC,
+ .mos_hs = mdt_sec_ctx_ops
+ },
+ {
.mos_hs = NULL
}
};
static void mdt_identity_entry_free(struct upcall_cache *cache,
struct upcall_cache_entry *entry)
{
- struct mdt_identity *identity = &entry->u.identity;
+ struct md_identity *identity = &entry->u.identity;
- if (identity->mi_ginfo)
+ if (identity->mi_ginfo) {
groups_free(identity->mi_ginfo);
+ identity->mi_ginfo = NULL;
+ }
if (identity->mi_nperms) {
LASSERT(identity->mi_perms);
OBD_FREE(identity->mi_perms,
- identity->mi_nperms * sizeof(struct mdt_setxid_perm));
+ identity->mi_nperms * sizeof(struct md_perm));
+ identity->mi_nperms = 0;
}
}
struct upcall_cache_entry *entry,
void *args)
{
- struct mdt_identity *identity = &entry->u.identity;
+ struct md_identity *identity = &entry->u.identity;
struct identity_downcall_data *data = args;
struct group_info *ginfo;
- struct mdt_setxid_perm *perms = NULL;
+ struct md_perm *perms = NULL;
int size, i;
ENTRY;
RETURN(-ENOMEM);
}
- groups_from_list(ginfo, data->idd_groups);
- groups_sort(ginfo);
- identity->mi_ginfo = ginfo;
+ lustre_groups_from_list(ginfo, data->idd_groups);
+ lustre_groups_sort(ginfo);
if (data->idd_nperms) {
size = data->idd_nperms * sizeof(*perms);
if (!perms) {
CERROR("failed to alloc %d permissions\n",
data->idd_nperms);
- put_group_info(ginfo);
+ groups_free(ginfo);
RETURN(-ENOMEM);
}
+
for (i = 0; i < data->idd_nperms; i++) {
perms[i].mp_nid = data->idd_perms[i].pdd_nid;
perms[i].mp_perm = data->idd_perms[i].pdd_perm;
RETURN(0);
}
-struct mdt_identity *mdt_identity_get(struct upcall_cache *cache, __u32 uid)
+struct md_identity *mdt_identity_get(struct upcall_cache *cache, __u32 uid)
{
struct upcall_cache_entry *entry;
return &entry->u.identity;
}
-void mdt_identity_put(struct upcall_cache *cache, struct mdt_identity *identity)
+void mdt_identity_put(struct upcall_cache *cache, struct md_identity *identity)
{
if (!cache)
return;
* If there is LNET_NID_ANY in perm[i].mp_nid,
* it must be perm[0].mp_nid, and act as default perm.
*/
-__u32 mdt_identity_get_setxid_perm(struct mdt_identity *identity,
+__u32 mdt_identity_get_perm(struct md_identity *identity,
__u32 is_rmtclient, lnet_nid_t nid)
{
- struct mdt_setxid_perm *perm = identity->mi_perms;
+ struct md_perm *perm;
int i;
+ if (!identity) {
+ LASSERT(is_rmtclient == 0);
+ return CFS_SETGRP_PERM;
+ }
+
+ perm = identity->mi_perms;
/* check exactly matched nid first */
for (i = identity->mi_nperms - 1; i > 0; i--) {
if (perm[i].mp_nid != nid)
return perm[0].mp_perm;
/* return default last */
- return is_rmtclient ? 0 : LUSTRE_SETGRP_PERM;
+ return is_rmtclient ? 0 : CFS_SETGRP_PERM;
}
int mdt_pack_remote_perm(struct mdt_thread_info *info, struct mdt_object *o,
#endif
#define DEBUG_SUBSYSTEM S_MDS
-#ifndef AUTOCONF_INCLUDED
#include <linux/config.h>
-#endif
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include "mdt_internal.h"
-enum {
- MDT_IDMAP_NOTFOUND = -1,
-};
-
-struct mdt_idmap_entry {
- struct list_head mie_rmt_hash; /* hashed as mie_rmt_id; */
- struct list_head mie_lcl_hash; /* hashed as mie_lcl_id; */
- int mie_refcount;
- uid_t mie_rmt_id; /* remote uid/gid */
- uid_t mie_lcl_id; /* local uid/gid */
-};
-
-/* uid/gid mapping */
-static struct mdt_idmap_table *mdt_idmap_alloc(void)
-{
- struct mdt_idmap_table *tbl;
- int i, j;
-
- OBD_ALLOC_PTR(tbl);
- if (!tbl)
- return NULL;
-
- spin_lock_init(&tbl->mit_lock);
- for (i = 0; i < ARRAY_SIZE(tbl->mit_idmaps); i++)
- for (j = 0; j < ARRAY_SIZE(tbl->mit_idmaps[i]); j++)
- INIT_LIST_HEAD(&tbl->mit_idmaps[i][j]);
-
- return tbl;
-}
-
-static struct mdt_idmap_entry *idmap_entry_alloc(__u32 mie_rmt_id,
- __u32 mie_lcl_id)
-{
- struct mdt_idmap_entry *e;
-
- OBD_ALLOC_PTR(e);
- if (!e)
- return NULL;
-
- INIT_LIST_HEAD(&e->mie_rmt_hash);
- INIT_LIST_HEAD(&e->mie_lcl_hash);
- e->mie_refcount = 1;
- e->mie_rmt_id = mie_rmt_id;
- e->mie_lcl_id = mie_lcl_id;
-
- return e;
-}
-
-static void idmap_entry_free(struct mdt_idmap_entry *e)
-{
- if (!list_empty(&e->mie_rmt_hash))
- list_del(&e->mie_rmt_hash);
- if (!list_empty(&e->mie_lcl_hash))
- list_del(&e->mie_lcl_hash);
- OBD_FREE_PTR(e);
-}
-
int mdt_init_idmap(struct mdt_thread_info *info)
{
struct ptlrpc_request *req = mdt_info_req(info);
if (!req->rq_auth_gss || req->rq_auth_usr_mdt) {
med->med_rmtclient = 0;
reply->ocd_connect_flags &= ~OBD_CONNECT_RMT_CLIENT;
- //reply->ocd_connect_flags |= OBD_CONNECT_LCL_CLIENT;
RETURN(0);
}
}
if (med->med_rmtclient) {
- med->med_nllu = data->ocd_nllu;
- med->med_nllg = data->ocd_nllg;
+ down(&med->med_idmap_sem);
if (!med->med_idmap)
- med->med_idmap = mdt_idmap_alloc();
- if (!med->med_idmap) {
- CERROR("client %s -> target %s failed to alloc idmap!\n"
- , client, obd->obd_name);
+ med->med_idmap = lustre_idmap_init();
+ up(&med->med_idmap_sem);
+
+ if (IS_ERR(med->med_idmap)) {
+ long err = PTR_ERR(med->med_idmap);
+
+ med->med_idmap = NULL;
+ CERROR("client %s -> target %s "
+ "failed to init idmap [%ld]!\n",
+ client, obd->obd_name, err);
+ RETURN(err);
+ } else if (!med->med_idmap) {
+ CERROR("client %s -> target %s "
+ "failed to init(2) idmap!\n",
+ client, obd->obd_name);
RETURN(-ENOMEM);
}
reply->ocd_connect_flags &= ~OBD_CONNECT_LCL_CLIENT;
- //reply->ocd_connect_flags |= OBD_CONNECT_RMT_CLIENT;
CDEBUG(D_SEC, "client %s -> target %s is remote.\n",
client, obd->obd_name);
- /* NB, MDT_CONNECT establish root idmap too! */
+ /* NB, MDS_CONNECT establish root idmap too! */
rc = mdt_handle_idmap(info);
} else {
if (req->rq_auth_uid == INVALID_UID) {
RETURN(-EACCES);
}
reply->ocd_connect_flags &= ~OBD_CONNECT_RMT_CLIENT;
- //reply->ocd_connect_flags |= OBD_CONNECT_LCL_CLIENT;
}
RETURN(rc);
}
-static void idmap_clear_mie_rmt_hash(struct list_head *list)
-{
- struct mdt_idmap_entry *e;
- int i;
-
- for (i = 0; i < MDT_IDMAP_HASHSIZE; i++) {
- while (!list_empty(&list[i])) {
- e = list_entry(list[i].next, struct mdt_idmap_entry,
- mie_rmt_hash);
- idmap_entry_free(e);
- }
- }
-}
-
void mdt_cleanup_idmap(struct mdt_export_data *med)
{
- struct mdt_idmap_table *tbl = med->med_idmap;
- int i;
-
LASSERT(med->med_rmtclient);
- LASSERT(tbl);
-
- spin_lock(&tbl->mit_lock);
- idmap_clear_mie_rmt_hash(tbl->mit_idmaps[RMT_UIDMAP_IDX]);
- idmap_clear_mie_rmt_hash(tbl->mit_idmaps[RMT_GIDMAP_IDX]);
-
- /* paranoid checking */
- for (i = 0; i < MDT_IDMAP_HASHSIZE; i++) {
- LASSERT(list_empty(&tbl->mit_idmaps[LCL_UIDMAP_IDX][i]));
- LASSERT(list_empty(&tbl->mit_idmaps[LCL_GIDMAP_IDX][i]));
- }
- spin_unlock(&tbl->mit_lock);
- OBD_FREE_PTR(tbl);
+ down(&med->med_idmap_sem);
+ if (med->med_idmap != NULL) {
+ lustre_idmap_fini(med->med_idmap);
med->med_idmap = NULL;
+ }
+ up(&med->med_idmap_sem);
}
static inline void mdt_revoke_export_locks(struct obd_export *exp)
ldlm_revoke_export_locks(exp);
}
-static
-struct mdt_idmap_entry *idmap_lookup_entry(struct list_head *mie_rmt_hash,
- uid_t mie_rmt_id, uid_t mie_lcl_id)
-{
- struct list_head *rmt_head =
- &mie_rmt_hash[MDT_IDMAP_HASHFUNC(mie_rmt_id)];
- struct mdt_idmap_entry *e;
-
- list_for_each_entry(e, rmt_head, mie_rmt_hash) {
- if ((e->mie_rmt_id == mie_rmt_id) &&
- (e->mie_lcl_id == mie_lcl_id))
- return e;
- }
- return NULL;
-}
-
-/*
- * return value
- * NULL: not found entry
- * ERR_PTR(-EACCES): found multi->single mapped entry
- * others: found normal entry
- */
-static
-struct mdt_idmap_entry *idmap_search_entry(struct list_head *mie_rmt_hash,
- uid_t mie_rmt_id,
- struct list_head *mie_lcl_hash,
- uid_t mie_lcl_id,
- const char *warn_msg)
-{
- struct list_head *rmt_head =
- &mie_rmt_hash[MDT_IDMAP_HASHFUNC(mie_rmt_id)];
- struct list_head *lcl_head =
- &mie_lcl_hash[MDT_IDMAP_HASHFUNC(mie_lcl_id)];
- struct mdt_idmap_entry *e;
-
- list_for_each_entry(e, rmt_head, mie_rmt_hash) {
- if (e->mie_rmt_id == mie_rmt_id) {
- if (e->mie_lcl_id == mie_lcl_id) {
- e->mie_refcount++;
- return e;
- } else {
- CERROR("%s: rmt id %u already be mapped to %u"
- " (new %u)\n", warn_msg, e->mie_rmt_id,
- e->mie_lcl_id, mie_lcl_id);
- return ERR_PTR(-EACCES);
- }
- }
- }
-
- list_for_each_entry(e, lcl_head, mie_lcl_hash) {
- if (e->mie_lcl_id == mie_lcl_id) {
- if (e->mie_rmt_id == mie_rmt_id) {
- e->mie_refcount++;
- return e;
- } else {
- CERROR("%s: lcl id %u already be mapped from %u"
- " (new %u)\n", warn_msg, e->mie_lcl_id,
- e->mie_rmt_id, mie_rmt_id);
- return ERR_PTR(-EACCES);
- }
- }
- }
-
- return NULL;
-}
-
-static
-struct mdt_idmap_entry *idmap_insert_entry(struct list_head *mie_rmt_hash,
- struct list_head *mie_lcl_hash,
- struct mdt_idmap_entry *new,
- const char *warn_msg)
-{
- struct list_head *rmt_head =
- &mie_rmt_hash[MDT_IDMAP_HASHFUNC(new->mie_rmt_id)];
- struct list_head *lcl_head =
- &mie_lcl_hash[MDT_IDMAP_HASHFUNC(new->mie_lcl_id)];
- struct mdt_idmap_entry *e;
-
- e = idmap_search_entry(mie_rmt_hash, new->mie_rmt_id,
- mie_lcl_hash, new->mie_lcl_id,
- warn_msg);
- if (e == NULL) {
- list_add_tail(&new->mie_rmt_hash, rmt_head);
- list_add_tail(&new->mie_lcl_hash, lcl_head);
- }
- return e;
-}
-
-static int idmap_remove_entry(struct list_head *mie_rmt_hash,
- struct list_head *mie_lcl_hash,
- __u32 mie_rmt_id, __u32 mie_lcl_id)
-{
- struct mdt_idmap_entry *e;
- int rc = -ENOENT;
-
- e = idmap_lookup_entry(mie_rmt_hash, mie_rmt_id, mie_lcl_id);
- if (e != NULL) {
- e->mie_refcount--;
- if ((rc = e->mie_refcount) <= 0)
- idmap_entry_free(e);
- }
- return rc;
-}
-
-static int mdt_idmap_add(struct mdt_idmap_table *tbl,
- uid_t ruid, uid_t luid,
- gid_t rgid, gid_t lgid)
-{
- struct mdt_idmap_entry *ue0, *ue1, *ge0, *ge1;
- ENTRY;
-
- LASSERT(tbl);
-
- spin_lock(&tbl->mit_lock);
- ue0 = idmap_search_entry(tbl->mit_idmaps[RMT_UIDMAP_IDX], ruid,
- tbl->mit_idmaps[LCL_UIDMAP_IDX], luid,
- "UID mapping");
- spin_unlock(&tbl->mit_lock);
- if (!ue0) {
- ue0 = idmap_entry_alloc(ruid, luid);
- if (!ue0)
- RETURN(-ENOMEM);
-
- spin_lock(&tbl->mit_lock);
- ue1 = idmap_insert_entry(tbl->mit_idmaps[RMT_UIDMAP_IDX],
- tbl->mit_idmaps[LCL_UIDMAP_IDX],
- ue0, "UID mapping");
- if (ue1 != NULL) {
- idmap_entry_free(ue0);
- ue0 = ue1;
- }
- spin_unlock(&tbl->mit_lock);
-
- if (IS_ERR(ue1))
- RETURN(PTR_ERR(ue1));
- } else if (IS_ERR(ue0)) {
- RETURN(PTR_ERR(ue0));
- }
-
- spin_lock(&tbl->mit_lock);
- ge0 = idmap_search_entry(tbl->mit_idmaps[RMT_GIDMAP_IDX], rgid,
- tbl->mit_idmaps[LCL_GIDMAP_IDX], lgid,
- "GID mapping");
- spin_unlock(&tbl->mit_lock);
- if (!ge0) {
- ge0 = idmap_entry_alloc(rgid, lgid);
- spin_lock(&tbl->mit_lock);
- if (!ge0) {
- ue0->mie_refcount--;
- if (ue0->mie_refcount <= 0)
- idmap_entry_free(ue0);
- spin_unlock(&tbl->mit_lock);
- RETURN(-ENOMEM);
- }
-
- ge1 = idmap_insert_entry(tbl->mit_idmaps[RMT_GIDMAP_IDX],
- tbl->mit_idmaps[LCL_GIDMAP_IDX],
- ge0, "GID mapping");
- if (ge1 != NULL) {
- ue0->mie_refcount--;
- if (ue0->mie_refcount <= 0)
- idmap_entry_free(ue0);
- idmap_entry_free(ge0);
- }
- spin_unlock(&tbl->mit_lock);
-
- if (IS_ERR(ge1))
- RETURN(PTR_ERR(ge1));
- } else if (IS_ERR(ge0)) {
- spin_lock(&tbl->mit_lock);
- ue0->mie_refcount--;
- if (ue0->mie_refcount <= 0)
- idmap_entry_free(ue0);
- spin_unlock(&tbl->mit_lock);
- RETURN(PTR_ERR(ge0));
- }
-
- RETURN(0);
-}
-
-static int mdt_idmap_del(struct mdt_idmap_table *tbl,
- uid_t ruid, uid_t luid,
- gid_t rgid, gid_t lgid)
-{
- ENTRY;
-
- if (!tbl)
- RETURN(0);
-
- spin_lock(&tbl->mit_lock);
- idmap_remove_entry(tbl->mit_idmaps[RMT_UIDMAP_IDX],
- tbl->mit_idmaps[LCL_UIDMAP_IDX],
- ruid, luid);
- idmap_remove_entry(tbl->mit_idmaps[RMT_GIDMAP_IDX],
- tbl->mit_idmaps[LCL_GIDMAP_IDX],
- rgid, lgid);
- spin_unlock(&tbl->mit_lock);
-
- RETURN(0);
-}
-
int mdt_handle_idmap(struct mdt_thread_info *info)
{
struct ptlrpc_request *req = mdt_info_req(info);
struct mdt_device *mdt = info->mti_mdt;
struct mdt_export_data *med;
struct ptlrpc_user_desc *pud = req->rq_user_desc;
- struct mdt_identity *identity;
+ struct md_identity *identity;
__u32 opc;
int rc = 0;
-
ENTRY;
if (!req->rq_export)
(opc != SEC_CTX_FINI) && (opc != MDS_CONNECT))
RETURN(0);
- LASSERT(pud);
LASSERT(med->med_idmap);
+ if (unlikely(!pud)) {
+ CERROR("remote client must run with rq_user_desc present\n");
+ RETURN(-EACCES);
+ }
+
if (req->rq_auth_mapped_uid == INVALID_UID) {
CERROR("invalid authorized mapped uid, please check "
"/etc/lustre/idmap.conf!\n");
case SEC_CTX_INIT:
case SEC_CTX_INIT_CONT:
case MDS_CONNECT:
- rc = mdt_idmap_add(med->med_idmap,
+ rc = lustre_idmap_add(med->med_idmap,
pud->pud_uid, identity->mi_uid,
pud->pud_gid, identity->mi_gid);
break;
case SEC_CTX_FINI:
- rc = mdt_idmap_del(med->med_idmap,
+ rc = lustre_idmap_del(med->med_idmap,
pud->pud_uid, identity->mi_uid,
pud->pud_gid, identity->mi_gid);
break;
mdt_revoke_export_locks(req->rq_export);
break;
}
- RETURN(0);
-}
-
-static __u32 idmap_lookup_id(struct list_head *hash, int reverse, __u32 id)
-{
- struct list_head *head = &hash[MDT_IDMAP_HASHFUNC(id)];
- struct mdt_idmap_entry *e;
-
- if (!reverse) {
- list_for_each_entry(e, head, mie_rmt_hash) {
- if (e->mie_rmt_id == id)
- return e->mie_lcl_id;
- }
- } else {
- list_for_each_entry(e, head, mie_lcl_hash) {
- if (e->mie_lcl_id == id)
- return e->mie_rmt_id;
- }
- }
- return MDT_IDMAP_NOTFOUND;
-}
-
-static int mdt_idmap_lookup_uid(struct mdt_idmap_table *tbl, int reverse,
- uid_t uid)
-{
- struct list_head *hash;
-
- if (!tbl)
- return MDT_IDMAP_NOTFOUND;
-
- hash = tbl->mit_idmaps[reverse ? LCL_UIDMAP_IDX : RMT_UIDMAP_IDX];
-
- spin_lock(&tbl->mit_lock);
- uid = idmap_lookup_id(hash, reverse, uid);
- spin_unlock(&tbl->mit_lock);
-
- return uid;
-}
-
-static int mdt_idmap_lookup_gid(struct mdt_idmap_table *tbl, int reverse,
- gid_t gid)
-{
- struct list_head *hash;
-
- if (!tbl)
- return MDT_IDMAP_NOTFOUND;
-
- hash = tbl->mit_idmaps[reverse ? LCL_GIDMAP_IDX : RMT_GIDMAP_IDX];
-
- spin_lock(&tbl->mit_lock);
- gid = idmap_lookup_id(hash, reverse, gid);
- spin_unlock(&tbl->mit_lock);
- return gid;
+ RETURN(0);
}
int ptlrpc_user_desc_do_idmap(struct ptlrpc_request *req,
struct ptlrpc_user_desc *pud)
{
struct mdt_export_data *med = mdt_req2med(req);
- struct mdt_idmap_table *idmap = med->med_idmap;
+ struct lustre_idmap_table *idmap = med->med_idmap;
uid_t uid, fsuid;
gid_t gid, fsgid;
if (!med->med_rmtclient)
return 0;
- uid = mdt_idmap_lookup_uid(idmap, 0, pud->pud_uid);
- if (uid == MDT_IDMAP_NOTFOUND) {
+ uid = lustre_idmap_lookup_uid(NULL, idmap, 0, pud->pud_uid);
+ if (uid == CFS_IDMAP_NOTFOUND) {
CERROR("no mapping for uid %u\n", pud->pud_uid);
return -EACCES;
}
if (pud->pud_uid == pud->pud_fsuid) {
fsuid = uid;
} else {
- fsuid = mdt_idmap_lookup_uid(idmap, 0, pud->pud_fsuid);
- if (fsuid == MDT_IDMAP_NOTFOUND) {
+ fsuid = lustre_idmap_lookup_uid(NULL, idmap, 0, pud->pud_fsuid);
+ if (fsuid == CFS_IDMAP_NOTFOUND) {
CERROR("no mapping for fsuid %u\n", pud->pud_fsuid);
return -EACCES;
}
}
- gid = mdt_idmap_lookup_gid(idmap, 0, pud->pud_gid);
- if (gid == MDT_IDMAP_NOTFOUND) {
+ gid = lustre_idmap_lookup_gid(NULL, idmap, 0, pud->pud_gid);
+ if (gid == CFS_IDMAP_NOTFOUND) {
CERROR("no mapping for gid %u\n", pud->pud_gid);
return -EACCES;
}
if (pud->pud_gid == pud->pud_fsgid) {
fsgid = gid;
} else {
- fsgid = mdt_idmap_lookup_gid(idmap, 0, pud->pud_fsgid);
- if (fsgid == MDT_IDMAP_NOTFOUND) {
+ fsgid = lustre_idmap_lookup_gid(NULL, idmap, 0, pud->pud_fsgid);
+ if (fsgid == CFS_IDMAP_NOTFOUND) {
CERROR("no mapping for fsgid %u\n", pud->pud_fsgid);
return -EACCES;
}
}
/*
- * Reverse map
- * Do not ignore rootsquash.
+ * Reverse mapping
*/
void mdt_body_reverse_idmap(struct mdt_thread_info *info, struct mdt_body *body)
{
struct ptlrpc_request *req = mdt_info_req(info);
struct md_ucred *uc = mdt_ucred(info);
struct mdt_export_data *med = mdt_req2med(req);
- struct mdt_idmap_table *idmap = med->med_idmap;
- uid_t uid;
- gid_t gid;
+ struct lustre_idmap_table *idmap = med->med_idmap;
if (!med->med_rmtclient)
return;
if (body->valid & OBD_MD_FLUID) {
- if (((uc->mu_valid == UCRED_OLD) ||
- (uc->mu_valid == UCRED_NEW)) &&
- !(uc->mu_squash & SQUASH_UID)) {
- if (body->uid == uc->mu_uid)
- uid = uc->mu_o_uid;
- else if (body->uid == uc->mu_fsuid)
- uid = uc->mu_o_fsuid;
- else
- uid = mdt_idmap_lookup_uid(idmap, 1, body->uid);
- } else {
- uid = mdt_idmap_lookup_uid(idmap, 1, body->uid);
- }
+ uid_t uid = lustre_idmap_lookup_uid(uc, idmap, 1, body->uid);
- if (uid == MDT_IDMAP_NOTFOUND) {
- uid = med->med_nllu;
+ if (uid == CFS_IDMAP_NOTFOUND) {
+ uid = NOBODY_UID;
if (body->valid & OBD_MD_FLMODE)
body->mode = (body->mode & ~S_IRWXU) |
((body->mode & S_IRWXO) << 6);
}
if (body->valid & OBD_MD_FLGID) {
- if (((uc->mu_valid == UCRED_OLD) ||
- (uc->mu_valid == UCRED_NEW)) &&
- !(uc->mu_squash & SQUASH_GID)) {
- if (body->gid == uc->mu_gid)
- gid = uc->mu_o_gid;
- else if (body->gid == uc->mu_fsgid)
- gid = uc->mu_o_fsgid;
- else
- gid = mdt_idmap_lookup_gid(idmap, 1, body->gid);
- } else {
- gid = mdt_idmap_lookup_gid(idmap, 1, body->gid);
- }
+ gid_t gid = lustre_idmap_lookup_gid(uc, idmap, 1, body->gid);
- if (gid == MDT_IDMAP_NOTFOUND) {
- gid = med->med_nllg;
+ if (gid == CFS_IDMAP_NOTFOUND) {
+ gid = NOBODY_GID;
if (body->valid & OBD_MD_FLMODE)
body->mode = (body->mode & ~S_IRWXG) |
((body->mode & S_IRWXO) << 3);
}
}
-/* NB: return error if no mapping, so this will look strange:
- * if client hasn't kinit the to map xid for the mapped xid, client
- * will always get -EPERM, and the same for rootsquash case. */
-int mdt_remote_perm_reverse_idmap(struct ptlrpc_request *req,
- struct mdt_remote_perm *perm)
-{
- struct mdt_export_data *med = mdt_req2med(req);
- uid_t uid, fsuid;
- gid_t gid, fsgid;
-
- LASSERT(med->med_rmtclient);
-
- uid = mdt_idmap_lookup_uid(med->med_idmap, 1, perm->rp_uid);
- if (uid == MDT_IDMAP_NOTFOUND) {
- CERROR("no mapping for uid %u\n", perm->rp_uid);
- return -EPERM;
- }
-
- gid = mdt_idmap_lookup_gid(med->med_idmap, 1, perm->rp_gid);
- if (gid == MDT_IDMAP_NOTFOUND) {
- CERROR("no mapping for gid %u\n", perm->rp_gid);
- return -EPERM;
- }
-
- if (perm->rp_uid != perm->rp_fsuid) {
- fsuid = mdt_idmap_lookup_uid(med->med_idmap, 1, perm->rp_fsuid);
- if (fsuid == MDT_IDMAP_NOTFOUND) {
- CERROR("no mapping for fsuid %u\n", perm->rp_fsuid);
- return -EPERM;
- }
- } else {
- fsuid = uid;
- }
-
- if (perm->rp_gid != perm->rp_fsgid) {
- fsgid = mdt_idmap_lookup_gid(med->med_idmap, 1, perm->rp_fsgid);
- if (fsgid == MDT_IDMAP_NOTFOUND) {
- CERROR("no mapping for fsgid %u\n", perm->rp_fsgid);
- return -EPERM;
- }
- } else {
- fsgid = gid;
- }
-
- perm->rp_uid = uid;
- perm->rp_gid = gid;
- perm->rp_fsuid = fsuid;
- perm->rp_fsgid = fsgid;
- return 0;
-}
-
-/* Process remote client and rootsquash */
+/* Do not ignore root_squash for non-setattr case. */
int mdt_fix_attr_ucred(struct mdt_thread_info *info, __u32 op)
{
struct ptlrpc_request *req = mdt_info_req(info);
struct md_ucred *uc = mdt_ucred(info);
struct lu_attr *attr = &info->mti_attr.ma_attr;
struct mdt_export_data *med = mdt_req2med(req);
- struct mdt_idmap_table *idmap = med->med_idmap;
-
- ENTRY;
+ struct lustre_idmap_table *idmap = med->med_idmap;
if ((uc->mu_valid != UCRED_OLD) && (uc->mu_valid != UCRED_NEW))
- RETURN(-EINVAL);
-
- if (!med->med_rmtclient && (uc->mu_squash == SQUASH_NONE))
- RETURN(0);
+ return -EINVAL;
if (op != REINT_SETATTR) {
if ((attr->la_valid & LA_UID) && (attr->la_uid != -1))
attr->la_uid = uc->mu_fsuid;
- if (op != REINT_CREATE) {
+ /* for S_ISGID, inherit gid from his parent, such work will be
+ * done in cmm/mdd layer, here set all cases as uc->mu_fsgid. */
if ((attr->la_valid & LA_GID) && (attr->la_gid != -1))
attr->la_gid = uc->mu_fsgid;
- } else {
- /* for S_ISGID, inherit gid from his parent */
- if (!(attr->la_mode & S_ISGID) && (attr->la_gid != -1))
- attr->la_gid = uc->mu_fsgid;
- }
} else if (med->med_rmtclient) {
/* NB: -1 case will be handled by mdt_fix_attr() later. */
if ((attr->la_valid & LA_UID) && (attr->la_uid != -1)) {
- uid_t uid;
-
- if (attr->la_uid == uc->mu_o_uid)
- uid = uc->mu_uid;
- else if (attr->la_uid == uc->mu_o_fsuid)
- uid = uc->mu_fsuid;
- else
- uid = mdt_idmap_lookup_uid(idmap, 0,
+ uid_t uid = lustre_idmap_lookup_uid(uc, idmap, 0,
attr->la_uid);
- if (uid == MDT_IDMAP_NOTFOUND) {
+ if (uid == CFS_IDMAP_NOTFOUND) {
CWARN("Deny chown to uid %u\n", attr->la_uid);
- RETURN(-EPERM);
+ return -EPERM;
}
attr->la_uid = uid;
}
if ((attr->la_valid & LA_GID) && (attr->la_gid != -1)) {
- gid_t gid;
-
- if (attr->la_gid == uc->mu_o_gid)
- gid = uc->mu_gid;
- else if (attr->la_gid == uc->mu_o_fsgid)
- gid = uc->mu_fsgid;
- else
- gid = mdt_idmap_lookup_gid(idmap, 0,
+ gid_t gid = lustre_idmap_lookup_gid(uc, idmap, 0,
attr->la_gid);
- if (gid == MDT_IDMAP_NOTFOUND) {
+ if (gid == CFS_IDMAP_NOTFOUND) {
CWARN("Deny chown to gid %u\n", attr->la_gid);
- RETURN(-EPERM);
+ return -EPERM;
}
attr->la_gid = gid;
}
}
- RETURN(0);
+ return 0;
}
#include <lustre_disk.h>
#include <lustre_sec.h>
#include <lvfs.h>
+#include <lustre_idmap.h>
+#include <lustre_eacl.h>
/* Data stored per client in the last_rcvd file. In le32 order. */
unsigned long mdt_client_bitmap[(LR_MAX_CLIENTS >> 3) / sizeof(long)];
struct upcall_cache *mdt_identity_cache;
- struct upcall_cache *mdt_rmtacl_cache;
- /* root squash */
- struct rootsquash_info *mdt_rootsquash_info;
+ /* sptlrpc rules */
+ rwlock_t mdt_sptlrpc_lock;
+ struct sptlrpc_rule_set mdt_sptlrpc_rset;
/* capability keys */
unsigned long mdt_capa_timeout;
void mdt_dump_lmm(int level, const struct lov_mds_md *lmm);
int mdt_check_ucred(struct mdt_thread_info *);
-
int mdt_init_ucred(struct mdt_thread_info *, struct mdt_body *);
-
int mdt_init_ucred_reint(struct mdt_thread_info *);
-
void mdt_exit_ucred(struct mdt_thread_info *);
-int groups_from_list(struct group_info *, gid_t *);
-
-void groups_sort(struct group_info *);
-
/* mdt_idmap.c */
int mdt_init_idmap(struct mdt_thread_info *);
extern struct upcall_cache_ops mdt_identity_upcall_cache_ops;
-struct mdt_identity *mdt_identity_get(struct upcall_cache *, __u32);
+struct md_identity *mdt_identity_get(struct upcall_cache *, __u32);
-void mdt_identity_put(struct upcall_cache *, struct mdt_identity *);
+void mdt_identity_put(struct upcall_cache *, struct md_identity *);
void mdt_flush_identity(struct upcall_cache *, int);
-__u32 mdt_identity_get_setxid_perm(struct mdt_identity *, __u32, lnet_nid_t);
+__u32 mdt_identity_get_perm(struct md_identity *, __u32, lnet_nid_t);
int mdt_pack_remote_perm(struct mdt_thread_info *, struct mdt_object *, void *);
-/* mdt/mdt_rmtacl.c */
-#define MDT_RMTACL_UPCALL_PATH "/usr/sbin/l_facl"
-
-extern struct upcall_cache_ops mdt_rmtacl_upcall_cache_ops;
-
-int mdt_rmtacl_upcall(struct mdt_thread_info *, char *, struct lu_buf *);
-
extern struct lu_context_key mdt_thread_key;
/* debug issues helper starts here*/
static inline void mdt_fail_write(const struct lu_env *env,
* Author: Mike Shaver <shaver@clusterfs.com>
* Author: Nikita Danilov <nikita@clusterfs.com>
* Author: Huang Hua <huanghua@clusterfs.com>
+ * Author: Fan Yong <fanyong@clusterfs.com>
*
*
* This file is part of the Lustre file system, http://www.lustre.org
REC_INIT = 2
} ucred_init_type_t;
-int groups_from_list(struct group_info *ginfo, gid_t *glist)
-{
- int i;
- int count = ginfo->ngroups;
-
- /* fill group_info from gid array */
- for (i = 0; i < ginfo->nblocks; i++) {
- int cp_count = min(NGROUPS_PER_BLOCK, count);
- int off = i * NGROUPS_PER_BLOCK;
- int len = cp_count * sizeof(*glist);
-
- if (memcpy(ginfo->blocks[i], glist + off, len))
- return -EFAULT;
-
- count -= cp_count;
- }
- return 0;
-}
-
-/* groups_sort() is copied from linux kernel! */
-/* a simple shell-metzner sort */
-void groups_sort(struct group_info *group_info)
-{
- int base, max, stride;
- int gidsetsize = group_info->ngroups;
-
- for (stride = 1; stride < gidsetsize; stride = 3 * stride + 1)
- ; /* nothing */
- stride /= 3;
-
- while (stride) {
- max = gidsetsize - stride;
- for (base = 0; base < max; base++) {
- int left = base;
- int right = left + stride;
- gid_t tmp = GROUP_AT(group_info, right);
-
- while (left >= 0 && GROUP_AT(group_info, left) > tmp) {
- GROUP_AT(group_info, right) =
- GROUP_AT(group_info, left);
- right = left;
- left -= stride;
- }
- GROUP_AT(group_info, right) = tmp;
- }
- stride /= 3;
- }
-}
-
void mdt_exit_ucred(struct mdt_thread_info *info)
{
struct md_ucred *uc = mdt_ucred(info);
}
}
-static int old_init_ucred(struct mdt_thread_info *info,
- struct mdt_body *body)
+/* XXX: root_squash will be redesigned in Lustre 1.7.
+ * Do not root_squash for inter-MDS operations */
+static int mdt_root_squash(struct mdt_thread_info *info)
{
- struct md_ucred *uc = mdt_ucred(info);
- struct mdt_device *mdt = info->mti_mdt;
- struct mdt_identity *identity = NULL;
-
- ENTRY;
-
- uc->mu_valid = UCRED_INVALID;
-
- if (!is_identity_get_disabled(mdt->mdt_identity_cache)) {
- /* get identity info of this user */
- identity = mdt_identity_get(mdt->mdt_identity_cache,
- body->fsuid);
- if (!identity) {
- CERROR("Deny access without identity: uid %d\n",
- body->fsuid);
- RETURN(-EACCES);
- }
- }
-
- uc->mu_valid = UCRED_OLD;
- uc->mu_squash = SQUASH_NONE;
- uc->mu_o_uid = uc->mu_uid = body->uid;
- uc->mu_o_gid = uc->mu_gid = body->gid;
- uc->mu_o_fsuid = uc->mu_fsuid = body->fsuid;
- uc->mu_o_fsgid = uc->mu_fsgid = body->fsgid;
- uc->mu_suppgids[0] = body->suppgid;
- uc->mu_suppgids[1] = -1;
- if (uc->mu_fsuid)
- uc->mu_cap = body->capability & ~CAP_FS_MASK;
- else
- uc->mu_cap = body->capability;
- uc->mu_ginfo = NULL;
- uc->mu_identity = identity;
-
- RETURN(0);
-}
-
-static int old_init_ucred_reint(struct mdt_thread_info *info)
-{
- struct md_ucred *uc = mdt_ucred(info);
- struct mdt_device *mdt = info->mti_mdt;
- struct mdt_identity *identity = NULL;
-
- ENTRY;
-
- uc->mu_valid = UCRED_INVALID;
-
- if (!is_identity_get_disabled(mdt->mdt_identity_cache)) {
- /* get identity info of this user */
- identity = mdt_identity_get(mdt->mdt_identity_cache,
- uc->mu_fsuid);
- if (!identity) {
- CERROR("Deny access without identity: uid %d\n",
- uc->mu_fsuid);
- RETURN(-EACCES);
- }
- }
-
- uc->mu_valid = UCRED_OLD;
- uc->mu_squash = SQUASH_NONE;
- uc->mu_o_uid = uc->mu_o_fsuid = uc->mu_uid = uc->mu_fsuid;
- uc->mu_o_gid = uc->mu_o_fsgid = uc->mu_gid = uc->mu_fsgid;
- if (uc->mu_fsuid)
- uc->mu_cap &= ~CAP_FS_MASK;
- uc->mu_ginfo = NULL;
- uc->mu_identity = identity;
-
- RETURN(0);
-}
-
-static int nid_nosquash(struct mdt_device *mdt, lnet_nid_t nid)
-{
- struct rootsquash_info *rsi = mdt->mdt_rootsquash_info;
- int i;
-
- for (i = 0; i < rsi->rsi_n_nosquash_nids; i++)
- if ((rsi->rsi_nosquash_nids[i] == nid) ||
- (rsi->rsi_nosquash_nids[i] == LNET_NID_ANY))
- return 1;
-
return 0;
}
-static int mdt_squash_root(struct mdt_device *mdt, struct md_ucred *ucred,
- struct ptlrpc_user_desc *pud, lnet_nid_t peernid)
-{
- struct rootsquash_info *rsi = mdt->mdt_rootsquash_info;
-
- if (!rsi || (!rsi->rsi_uid && !rsi->rsi_gid) ||
- nid_nosquash(mdt, peernid))
- return 0;
-
- CDEBUG(D_SEC, "squash req from "LPX64":"
- "(%u:%u-%u:%u/%x)=>(%u:%u-%u:%u/%x)\n", peernid,
- pud->pud_uid, pud->pud_gid,
- pud->pud_fsuid, pud->pud_fsgid, pud->pud_cap,
- pud->pud_uid ? pud->pud_uid : rsi->rsi_uid,
- pud->pud_uid ? pud->pud_gid : rsi->rsi_gid,
- pud->pud_fsuid ? pud->pud_fsuid : rsi->rsi_uid,
- pud->pud_fsuid ? pud->pud_fsgid : rsi->rsi_gid,
- pud->pud_cap & ~CAP_FS_MASK);
-
- if (rsi->rsi_uid) {
- if (!pud->pud_uid) {
- ucred->mu_uid = rsi->rsi_uid;
- ucred->mu_squash |= SQUASH_UID;
- } else {
- ucred->mu_uid = pud->pud_uid;
- }
-
- if (!pud->pud_fsuid) {
- ucred->mu_fsuid = rsi->rsi_uid;
- ucred->mu_squash |= SQUASH_UID;
- } else {
- ucred->mu_fsuid = pud->pud_fsuid;
- }
- } else {
- ucred->mu_uid = pud->pud_uid;
- ucred->mu_fsuid = pud->pud_fsuid;
- }
-
- if (rsi->rsi_gid) {
- int i;
-
- if (!pud->pud_gid) {
- ucred->mu_gid = rsi->rsi_gid;
- ucred->mu_squash |= SQUASH_GID;
- } else {
- ucred->mu_gid = pud->pud_gid;
- }
-
- if (!pud->pud_fsgid) {
- ucred->mu_fsgid = rsi->rsi_gid;
- ucred->mu_squash |= SQUASH_GID;
- } else {
- ucred->mu_fsgid = pud->pud_fsgid;
- }
-
- for (i = 0; i < 2; i++) {
- if (!ucred->mu_suppgids[i]) {
- ucred->mu_suppgids[i] = rsi->rsi_gid;
- ucred->mu_squash |= SQUASH_GID;
- }
- }
-
- for (i = 0; i < pud->pud_ngroups; i++) {
- if (!pud->pud_groups[i]) {
- pud->pud_groups[i] = rsi->rsi_gid;
- ucred->mu_squash |= SQUASH_GID;
- }
- }
- } else {
- ucred->mu_gid = pud->pud_gid;
- ucred->mu_fsgid = pud->pud_fsgid;
- }
-
- return 1;
-}
-
static int new_init_ucred(struct mdt_thread_info *info, ucred_init_type_t type,
void *buf)
{
struct mdt_device *mdt = info->mti_mdt;
struct ptlrpc_user_desc *pud = req->rq_user_desc;
struct md_ucred *ucred = mdt_ucred(info);
- struct mdt_identity *identity = NULL;
lnet_nid_t peernid = req->rq_peer.nid;
- __u32 setxid_perm = 0;
+ __u32 perm = 0;
int setuid;
int setgid;
int rc = 0;
RETURN(-EACCES);
if (req->rq_auth_mapped_uid != pud->pud_uid) {
- CERROR("remote client "LPU64": auth uid %u "
+ CERROR("remote client "LPU64": auth/mapped uid %u/%u "
"while client claim %u:%u/%u:%u\n",
- peernid, req->rq_auth_uid, pud->pud_uid,
- pud->pud_gid, pud->pud_fsuid, pud->pud_fsgid);
+ peernid, req->rq_auth_uid,
+ req->rq_auth_mapped_uid,
+ pud->pud_uid, pud->pud_gid,
+ pud->pud_fsuid, pud->pud_fsgid);
RETURN(-EACCES);
}
} else {
"enabled!\n");
RETURN(-EACCES);
} else {
- setxid_perm |= LUSTRE_SETGRP_PERM;
- goto check_squash;
+ ucred->mu_identity = NULL;
+ perm = CFS_SETUID_PERM | CFS_SETGID_PERM |
+ CFS_SETGRP_PERM;
}
- }
-
- identity = mdt_identity_get(mdt->mdt_identity_cache, pud->pud_uid);
- if (!identity) {
- CERROR("Deny access without identity: uid %d\n", pud->pud_uid);
+ } else {
+ ucred->mu_identity = mdt_identity_get(mdt->mdt_identity_cache,
+ pud->pud_uid);
+ if (!ucred->mu_identity) {
+ CERROR("Deny access without identity: uid %d\n",
+ pud->pud_uid);
RETURN(-EACCES);
- }
-
- setxid_perm = mdt_identity_get_setxid_perm(identity,
+ } else {
+ perm = mdt_identity_get_perm(ucred->mu_identity,
med->med_rmtclient,
peernid);
+ }
+ }
/* find out the setuid/setgid attempt */
setuid = (pud->pud_uid != pud->pud_fsuid);
- setgid = (pud->pud_gid != pud->pud_fsgid ||
- pud->pud_gid != identity->mi_gid);
+ setgid = ((pud->pud_gid != pud->pud_fsgid) ||
+ (ucred->mu_identity &&
+ (pud->pud_gid != ucred->mu_identity->mi_gid)));
/* check permission of setuid */
- if (setuid && !(setxid_perm & LUSTRE_SETUID_PERM)) {
+ if (setuid && !(perm & CFS_SETUID_PERM)) {
CWARN("mdt blocked setuid attempt (%u -> %u) from "
LPX64"\n", pud->pud_uid, pud->pud_fsuid, peernid);
GOTO(out, rc = -EACCES);
}
/* check permission of setgid */
- if (setgid && !(setxid_perm & LUSTRE_SETGID_PERM)) {
+ if (setgid && !(perm & CFS_SETGID_PERM)) {
CWARN("mdt blocked setgid attempt (%u:%u/%u:%u -> %u) "
"from "LPX64"\n", pud->pud_uid, pud->pud_gid,
- pud->pud_fsuid, pud->pud_fsgid, identity->mi_gid,
- peernid);
+ pud->pud_fsuid, pud->pud_fsgid,
+ ucred->mu_identity->mi_gid, peernid);
GOTO(out, rc = -EACCES);
}
-check_squash:
- /* FIXME: The exact behavior of root_squash is not defined. */
- ucred->mu_squash = SQUASH_NONE;
- if (mdt_squash_root(mdt, ucred, pud, peernid) == 0) {
- ucred->mu_uid = pud->pud_uid;
- ucred->mu_gid = pud->pud_gid;
- ucred->mu_fsuid = pud->pud_fsuid;
- ucred->mu_fsgid = pud->pud_fsgid;
- }
-
- /* remove fs privilege for non-root user */
- if (ucred->mu_fsuid)
- ucred->mu_cap = pud->pud_cap & ~CAP_FS_MASK;
- else
- ucred->mu_cap = pud->pud_cap;
-
/*
* NB: remote client not allowed to setgroups anyway.
*/
- if (!med->med_rmtclient && pud->pud_ngroups &&
- (setxid_perm & LUSTRE_SETGRP_PERM)) {
- struct group_info *ginfo;
-
+ if (!med->med_rmtclient && perm & CFS_SETGRP_PERM) {
+ if (pud->pud_ngroups) {
/* setgroups for local client */
- ginfo = groups_alloc(pud->pud_ngroups);
- if (!ginfo) {
+ ucred->mu_ginfo = groups_alloc(pud->pud_ngroups);
+ if (!ucred->mu_ginfo) {
CERROR("failed to alloc %d groups\n",
pud->pud_ngroups);
GOTO(out, rc = -ENOMEM);
}
- groups_from_list(ginfo, pud->pud_groups);
- groups_sort(ginfo);
- ucred->mu_ginfo = ginfo;
+
+ lustre_groups_from_list(ucred->mu_ginfo,
+ pud->pud_groups);
+ lustre_groups_sort(ucred->mu_ginfo);
} else {
ucred->mu_ginfo = NULL;
}
+ } else {
+ ucred->mu_suppgids[0] = -1;
+ ucred->mu_suppgids[1] = -1;
+ ucred->mu_ginfo = NULL;
+ }
- ucred->mu_identity = identity;
+ ucred->mu_uid = pud->pud_uid;
+ ucred->mu_gid = pud->pud_gid;
+ ucred->mu_fsuid = pud->pud_fsuid;
+ ucred->mu_fsgid = pud->pud_fsgid;
+
+ /* XXX: need to process root_squash here. */
+ mdt_root_squash(info);
+
+ /* remove fs privilege for non-root user */
+ if (ucred->mu_fsuid)
+ ucred->mu_cap = pud->pud_cap & ~CAP_FS_MASK;
+ else
+ ucred->mu_cap = pud->pud_cap;
ucred->mu_valid = UCRED_NEW;
EXIT;
out:
- if (rc && identity)
- mdt_identity_put(mdt->mdt_identity_cache, identity);
+ if (rc) {
+ if (ucred->mu_ginfo) {
+ groups_free(ucred->mu_ginfo);
+ ucred->mu_ginfo = NULL;
+ }
+ if (ucred->mu_identity) {
+ mdt_identity_put(mdt->mdt_identity_cache,
+ ucred->mu_identity);
+ ucred->mu_identity = NULL;
+ }
+ }
return rc;
}
struct mdt_device *mdt = info->mti_mdt;
struct ptlrpc_user_desc *pud = req->rq_user_desc;
struct md_ucred *ucred = mdt_ucred(info);
- struct mdt_identity *identity;
+ struct md_identity *identity = NULL;
lnet_nid_t peernid = req->rq_peer.nid;
+ __u32 perm = 0;
+ int setuid;
+ int setgid;
+ int rc = 0;
ENTRY;
if ((ucred->mu_valid == UCRED_OLD) || (ucred->mu_valid == UCRED_NEW))
RETURN(0);
- if (!req->rq_user_desc)
+ if (!req->rq_auth_gss || req->rq_auth_usr_mdt || !req->rq_user_desc)
RETURN(0);
/* sanity check: if we use strong authentication, we expect the
* uid which client claimed is true */
- if (req->rq_auth_gss) {
if (med->med_rmtclient) {
if (req->rq_auth_mapped_uid == INVALID_UID) {
CWARN("remote user not mapped, deny access!\n");
RETURN(-EACCES);
if (req->rq_auth_mapped_uid != pud->pud_uid) {
- CERROR("remote client "LPU64": auth uid %u "
+ CERROR("remote client "LPU64": auth/mapped uid %u/%u "
"while client claim %u:%u/%u:%u\n",
- peernid, req->rq_auth_uid, pud->pud_uid,
- pud->pud_gid, pud->pud_fsuid,
- pud->pud_fsgid);
+ peernid, req->rq_auth_uid,
+ req->rq_auth_mapped_uid,
+ pud->pud_uid, pud->pud_gid,
+ pud->pud_fsuid, pud->pud_fsgid);
RETURN(-EACCES);
}
} else {
RETURN(-EACCES);
}
}
- }
if (is_identity_get_disabled(mdt->mdt_identity_cache)) {
if (med->med_rmtclient) {
- CERROR("remote client must run with "
- "identity_get enabled!\n");
+ CERROR("remote client must run with identity_get "
+ "enabled!\n");
RETURN(-EACCES);
}
- } else {
+ RETURN(0);
+ }
+
+ identity = mdt_identity_get(mdt->mdt_identity_cache, pud->pud_uid);
+ if (!identity) {
+ CERROR("Deny access without identity: uid %d\n", pud->pud_uid);
+ RETURN(-EACCES);
+ }
+
+ perm = mdt_identity_get_perm(identity, med->med_rmtclient, peernid);
+ /* find out the setuid/setgid attempt */
+ setuid = (pud->pud_uid != pud->pud_fsuid);
+ setgid = (pud->pud_gid != pud->pud_fsgid ||
+ pud->pud_gid != identity->mi_gid);
+
+ /* check permission of setuid */
+ if (setuid && !(perm & CFS_SETUID_PERM)) {
+ CWARN("mdt blocked setuid attempt (%u -> %u) from "
+ LPX64"\n", pud->pud_uid, pud->pud_fsuid, peernid);
+ GOTO(out, rc = -EACCES);
+ }
+
+ /* check permission of setgid */
+ if (setgid && !(perm & CFS_SETGID_PERM)) {
+ CWARN("mdt blocked setgid attempt (%u:%u/%u:%u -> %u) "
+ "from "LPX64"\n", pud->pud_uid, pud->pud_gid,
+ pud->pud_fsuid, pud->pud_fsgid, identity->mi_gid,
+ peernid);
+ GOTO(out, rc = -EACCES);
+ }
+
+ EXIT;
+
+out:
+ mdt_identity_put(mdt->mdt_identity_cache, identity);
+ return rc;
+}
+
+static int old_init_ucred(struct mdt_thread_info *info,
+ struct mdt_body *body)
+{
+ struct md_ucred *uc = mdt_ucred(info);
+ struct mdt_device *mdt = info->mti_mdt;
+ struct md_identity *identity = NULL;
+
+ ENTRY;
+
+ uc->mu_valid = UCRED_INVALID;
+ uc->mu_o_uid = uc->mu_uid = body->uid;
+ uc->mu_o_gid = uc->mu_gid = body->gid;
+ uc->mu_o_fsuid = uc->mu_fsuid = body->fsuid;
+ uc->mu_o_fsgid = uc->mu_fsgid = body->fsgid;
+ uc->mu_suppgids[0] = body->suppgid;
+ uc->mu_suppgids[1] = -1;
+ uc->mu_ginfo = NULL;
+ if (!is_identity_get_disabled(mdt->mdt_identity_cache)) {
identity = mdt_identity_get(mdt->mdt_identity_cache,
- pud->pud_uid);
+ uc->mu_fsuid);
if (!identity) {
CERROR("Deny access without identity: uid %d\n",
- pud->pud_uid);
+ uc->mu_fsuid);
RETURN(-EACCES);
}
+ }
+ uc->mu_identity = identity;
+
+ /* XXX: need to process root_squash here. */
+ mdt_root_squash(info);
+
+ /* remove fs privilege for non-root user */
+ if (uc->mu_fsuid)
+ uc->mu_cap = body->capability & ~CAP_FS_MASK;
+ else
+ uc->mu_cap = body->capability;
+ uc->mu_valid = UCRED_OLD;
+
+ RETURN(0);
+}
+
+static int old_init_ucred_reint(struct mdt_thread_info *info)
+{
+ struct md_ucred *uc = mdt_ucred(info);
+ struct mdt_device *mdt = info->mti_mdt;
+ struct md_identity *identity = NULL;
+
+ ENTRY;
- mdt_identity_put(mdt->mdt_identity_cache, identity);
+ uc->mu_valid = UCRED_INVALID;
+ uc->mu_o_uid = uc->mu_o_fsuid = uc->mu_uid = uc->mu_fsuid;
+ uc->mu_o_gid = uc->mu_o_fsgid = uc->mu_gid = uc->mu_fsgid;
+ uc->mu_ginfo = NULL;
+ if (!is_identity_get_disabled(mdt->mdt_identity_cache)) {
+ identity = mdt_identity_get(mdt->mdt_identity_cache,
+ uc->mu_fsuid);
+ if (!identity) {
+ CERROR("Deny access without identity: uid %d\n",
+ uc->mu_fsuid);
+ RETURN(-EACCES);
+ }
}
+ uc->mu_identity = identity;
+
+ /* XXX: need to process root_squash here. */
+ mdt_root_squash(info);
+
+ /* remove fs privilege for non-root user */
+ if (uc->mu_fsuid)
+ uc->mu_cap &= ~CAP_FS_MASK;
+ uc->mu_valid = UCRED_OLD;
RETURN(0);
}
GOTO(out, rc = -EINVAL);
}
- if (sparam.idd_nperms > N_SETXID_PERMS_MAX) {
+ if (sparam.idd_nperms > N_PERMS_MAX) {
CERROR("%s: perm count %d more than maximum %d\n",
- obd->obd_name, sparam.idd_nperms, N_SETXID_PERMS_MAX);
+ obd->obd_name, sparam.idd_nperms, N_PERMS_MAX);
GOTO(out, rc = -EINVAL);
}
return rc ?: count;
}
-static int lprocfs_rd_rmtacl_expire(char *page, char **start, off_t off,
- int count, int *eof, void *data)
-{
- struct obd_device *obd = data;
- struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
-
- *eof = 1;
- return snprintf(page, count, "%lu\n",
- mdt->mdt_rmtacl_cache->uc_entry_expire / HZ);
-}
-
-static int lprocfs_wr_rmtacl_expire(struct file *file, const char *buffer,
- unsigned long count, void *data)
-{
- struct obd_device *obd = data;
- struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
- int rc, val;
-
- rc = lprocfs_write_helper(buffer, count, &val);
- if (rc)
- return rc;
-
- mdt->mdt_rmtacl_cache->uc_entry_expire = val * HZ;
- return count;
-}
-
-static int lprocfs_rd_rmtacl_acquire_expire(char *page, char **start,
- off_t off, int count, int *eof,
- void *data)
-{
- struct obd_device *obd = data;
- struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
-
- *eof = 1;
- return snprintf(page, count, "%lu\n",
- mdt->mdt_rmtacl_cache->uc_acquire_expire / HZ);
-}
-
-static int lprocfs_wr_rmtacl_acquire_expire(struct file *file,
- const char *buffer,
- unsigned long count,
- void *data)
-{
- struct obd_device *obd = data;
- struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
- int rc, val;
-
- rc = lprocfs_write_helper(buffer, count, &val);
- if (rc)
- return rc;
-
- mdt->mdt_rmtacl_cache->uc_acquire_expire = val * HZ;
- return count;
-}
-
-static int lprocfs_rd_rmtacl_upcall(char *page, char **start, off_t off,
- int count, int *eof, void *data)
-{
- struct obd_device *obd = data;
- struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
-
- *eof = 1;
- return snprintf(page, count, "%s\n",
- mdt->mdt_rmtacl_cache->uc_upcall);
-}
-
-static int lprocfs_wr_rmtacl_upcall(struct file *file, const char *buffer,
- unsigned long count, void *data)
-{
- struct obd_device *obd = data;
- struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
- struct upcall_cache *hash = mdt->mdt_rmtacl_cache;
- char kernbuf[UC_CACHE_UPCALL_MAXPATH] = { '\0' };
-
- if (count >= UC_CACHE_UPCALL_MAXPATH) {
- CERROR("%s: remote ACL upcall too long\n", obd->obd_name);
- return -EINVAL;
- }
-
- if (copy_from_user(kernbuf, buffer,
- min(count, UC_CACHE_UPCALL_MAXPATH - 1)))
- return -EFAULT;
-
- /* Remove any extraneous bits from the upcall (e.g. linefeeds) */
- sscanf(kernbuf, "%s", hash->uc_upcall);
-
- if (strcmp(hash->uc_name, obd->obd_name) != 0)
- CWARN("%s: write to upcall name %s\n",
- obd->obd_name, hash->uc_upcall);
- CWARN("%s: remote ACL upcall set to %s\n", obd->obd_name, hash->uc_upcall);
-
- return count;
-}
-
-static int lprocfs_wr_rmtacl_info(struct file *file, const char *buffer,
- unsigned long count, void *data)
-{
- struct obd_device *obd = data;
- struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
- struct rmtacl_downcall_data sparam, *param = &sparam;
- int size = 0, rc = 0;
-
- if (count < sizeof(*param)) {
- CERROR("%s: invalid data size %lu\n", obd->obd_name, count);
- return count;
- }
-
- if (copy_from_user(&sparam, buffer, sizeof(sparam))) {
- CERROR("%s: bad remote acl data\n", obd->obd_name);
- GOTO(out, rc = -EFAULT);
- }
-
- if (sparam.add_magic != RMTACL_DOWNCALL_MAGIC) {
- CERROR("%s: MDT remote acl downcall bad params\n", obd->obd_name);
- GOTO(out, rc = -EINVAL);
- }
-
- if (sparam.add_buflen) {
- size = offsetof(struct rmtacl_downcall_data,
- add_buf[sparam.add_buflen]);
- OBD_ALLOC(param, size);
- if (!param) {
- CERROR("%s: fail to alloc %d bytes for ino "LPU64"\n",
- obd->obd_name, size, sparam.add_key);
- param = &sparam;
- param->add_buflen = 0;
- } else if (copy_from_user(param, buffer, size)) {
- CERROR("%s: ino "LPU64" bad remote acl data\n",
- obd->obd_name, sparam.add_key);
- OBD_FREE(param, size);
- param = &sparam;
- param->add_buflen = 0;
- }
- }
-
- rc = upcall_cache_downcall(mdt->mdt_rmtacl_cache, 0, param->add_key,
- param);
-
-out:
- if (param && (param != &sparam))
- OBD_FREE(param, size);
-
- return rc ?: count;
-}
-
-static int lprocfs_rd_rootsquash_uid(char *page, char **start, off_t off,
- int count, int *eof, void *data)
-{
- struct obd_device *obd = data;
- struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
- struct rootsquash_info *rsi = mdt->mdt_rootsquash_info;
-
- *eof = 1;
- return snprintf(page, count, "%u\n",
- rsi ? rsi->rsi_uid : 0);
-}
-
-static int lprocfs_wr_rootsquash_uid(struct file *file, const char *buffer,
- unsigned long count, void *data)
-{
- struct obd_device *obd = data;
- struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
- int val, rc;
-
- rc = lprocfs_write_helper(buffer, count, &val);
- if (rc)
- return rc;
-
- if (!mdt->mdt_rootsquash_info)
- OBD_ALLOC_PTR(mdt->mdt_rootsquash_info);
- if (!mdt->mdt_rootsquash_info)
- return -ENOMEM;
-
- mdt->mdt_rootsquash_info->rsi_uid = val;
- return count;
-}
-
-static int lprocfs_rd_rootsquash_gid(char *page, char **start, off_t off,
- int count, int *eof, void *data)
-{
- struct obd_device *obd = data;
- struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
- struct rootsquash_info *rsi = mdt->mdt_rootsquash_info;
-
- *eof = 1;
- return snprintf(page, count, "%u\n",
- rsi ? rsi->rsi_gid : 0);
-}
-
-static int lprocfs_wr_rootsquash_gid(struct file *file, const char *buffer,
- unsigned long count, void *data)
-{
- struct obd_device *obd = data;
- struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
- int val, rc;
-
- rc = lprocfs_write_helper(buffer, count, &val);
- if (rc)
- return rc;
-
- if (!mdt->mdt_rootsquash_info)
- OBD_ALLOC_PTR(mdt->mdt_rootsquash_info);
- if (!mdt->mdt_rootsquash_info)
- return -ENOMEM;
-
- mdt->mdt_rootsquash_info->rsi_gid = val;
- return count;
-}
-
-static int lprocfs_rd_nosquash_nids(char *page, char **start, off_t off,
- int count, int *eof, void *data)
-{
- struct obd_device *obd = data;
- struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
- struct rootsquash_info *rsi = mdt->mdt_rootsquash_info;
- int i, ret;
-
- ret = snprintf(page, count, "rootsquash skip list:\n");
- for (i = 0; rsi && (i < rsi->rsi_n_nosquash_nids); i++) {
- ret += snprintf(page + ret, count - ret, "%s\n",
- libcfs_nid2str(rsi->rsi_nosquash_nids[i]));
- }
-
- *eof = 1;
- return ret;
-}
-
-static inline void remove_newline(char *str)
-{
- int len = strlen(str);
-
- if (str[len - 1] == '\n')
- str[len - 1] = '\0';
-}
-
-/* XXX: This macro is copied from lnet/libcfs/nidstring.c */
-#define LNET_NIDSTR_SIZE 32 /* size of each one (see below for usage) */
-
-static void do_process_nosquash_nids(struct mdt_device *m, char *buf)
-{
- struct rootsquash_info *rsi = m->mdt_rootsquash_info;
- char str[LNET_NIDSTR_SIZE], *end;
- lnet_nid_t nid;
-
- LASSERT(rsi);
- rsi->rsi_n_nosquash_nids = 0;
- while (rsi->rsi_n_nosquash_nids < N_NOSQUASH_NIDS) {
- end = strchr(buf, ',');
- memset(str, 0, sizeof(str));
- if (end)
- strncpy(str, buf, min_t(int, sizeof(str), end - buf));
- else
- strncpy(str, buf, min_t(int, sizeof(str), strlen(buf)));
-
- if (!strcmp(str, "*")) {
- nid = LNET_NID_ANY;
- } else {
- nid = libcfs_str2nid(str);
- if (nid == LNET_NID_ANY)
- goto ignore;
- }
- rsi->rsi_nosquash_nids[rsi->rsi_n_nosquash_nids++] = nid;
-ignore:
- if (!end || (*(end + 1) == 0))
- return;
- buf = end + 1;
- }
-}
-
-static int lprocfs_wr_nosquash_nids(struct file *file, const char *buffer,
- unsigned long count, void *data)
-{
- struct obd_device *obd = data;
- struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
- char skips[LNET_NIDSTR_SIZE * N_NOSQUASH_NIDS] = "";
- unsigned long size = sizeof(skips);
-
- if (count > size) {
- CERROR("parameter exceeds max limit %lu\n", size);
- return -EINVAL;
- }
-
- if (copy_from_user(skips, buffer, min(size, count)))
- return -EFAULT;
-
- if (!mdt->mdt_rootsquash_info)
- OBD_ALLOC_PTR(mdt->mdt_rootsquash_info);
- if (!mdt->mdt_rootsquash_info)
- return -ENOMEM;
-
- remove_newline(skips);
- do_process_nosquash_nids(mdt, skips);
- return count;
-}
-
/* for debug only */
static int lprocfs_rd_capa(char *page, char **start, off_t off,
int count, int *eof, void *data)
lprocfs_wr_identity_upcall, 0 },
{ "identity_flush", 0, lprocfs_wr_identity_flush, 0 },
{ "identity_info", 0, lprocfs_wr_identity_info, 0 },
- { "rmtacl_expire", lprocfs_rd_rmtacl_expire,
- lprocfs_wr_rmtacl_expire, 0 },
- { "rmtacl_acquire_expire", lprocfs_rd_rmtacl_acquire_expire,
- lprocfs_wr_rmtacl_acquire_expire, 0 },
- { "rmtacl_upcall", lprocfs_rd_rmtacl_upcall,
- lprocfs_wr_rmtacl_upcall, 0 },
- { "rmtacl_info", 0, lprocfs_wr_rmtacl_info, 0 },
- { "rootsquash_uid", lprocfs_rd_rootsquash_uid,
- lprocfs_wr_rootsquash_uid, 0 },
- { "rootsquash_gid", lprocfs_rd_rootsquash_gid,
- lprocfs_wr_rootsquash_gid, 0 },
- { "nosquash_nids", lprocfs_rd_nosquash_nids,
- lprocfs_wr_nosquash_nids, 0 },
{ "capa", lprocfs_rd_capa,
lprocfs_wr_capa, 0 },
{ "capa_timeout", lprocfs_rd_capa_timeout,
+++ /dev/null
-/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
- * vim:expandtab:shiftwidth=8:tabstop=8:
- *
- * Copyright (C) 2004-2006 Cluster File Systems, Inc.
- * Author: Lai Siyao <lsy@clusterfs.com>
- * Author: Fan Yong <fanyong@clusterfs.com>
- *
- * 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.
- */
-
-#ifndef EXPORT_SYMTAB
-#define EXPORT_SYMTAB
-#endif
-#define DEBUG_SUBSYSTEM S_MDS
-
-#ifndef AUTOCONF_INCLUDED
-#include <linux/config.h>
-#endif
-#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/kp30.h>
-#include <obd.h>
-#include <obd_class.h>
-#include <obd_support.h>
-#include <lustre_net.h>
-#include <lustre_import.h>
-#include <lustre_dlm.h>
-#include <lustre_lib.h>
-#include <lustre_ucache.h>
-
-#include "mdt_internal.h"
-
-#define MAX_CMD_LEN 256
-
-static __u64 rmtacl_key = 0;
-static spinlock_t rmtacl_key_lock = SPIN_LOCK_UNLOCKED;
-
-/*
- * For remote acl operation, do NOT cache!
- * Use different key for each remote acl operation.
- */
-static __u64 mdt_rmtacl_getkey(void)
-{
- __u64 key;
-
- spin_lock(&rmtacl_key_lock);
- key = ++rmtacl_key;
- spin_unlock(&rmtacl_key_lock);
-
- return key;
-}
-
-static void mdt_rmtacl_entry_init(struct upcall_cache_entry *entry, void *args)
-{
- struct rmtacl_upcall_data *data = args;
- struct mdt_rmtacl *acl = &entry->u.acl;
- char *cmd;
-
- acl->ra_uid = data->aud_uid;
- acl->ra_gid = data->aud_gid;
- /* we use address of this cache entry as handle */
- acl->ra_handle = (__u32)entry;
- OBD_ALLOC(cmd, strlen(data->aud_cmd) + 1);
- if (!cmd)
- return; /* upcall will fail later! */
-
- strcpy(cmd, data->aud_cmd);
- acl->ra_cmd = cmd;
-}
-
-static void mdt_rmtacl_entry_free(struct upcall_cache *cache,
- struct upcall_cache_entry *entry)
-{
- struct mdt_rmtacl *acl = &entry->u.acl;
- int len;
-
- if (acl->ra_cmd) {
- len = strlen(acl->ra_cmd) + 1;
- OBD_FREE(acl->ra_cmd, len);
- }
-
- if (acl->ra_buf) {
- len = strlen(acl->ra_buf) + 1;
- OBD_FREE(acl->ra_buf, len);
- }
-}
-
-static int mdt_rmtacl_upcall_compare(struct upcall_cache *cache,
- struct upcall_cache_entry *entry,
- __u64 key, void *args)
-{
- struct rmtacl_upcall_data *data = args;
-
- LASSERT(entry && data);
- LASSERT(entry->u.acl.ra_cmd && data->aud_cmd);
- return strncmp(entry->u.acl.ra_cmd, data->aud_cmd, MAX_CMD_LEN);
-}
-
-static int mdt_rmtacl_downcall_compare(struct upcall_cache *cache,
- struct upcall_cache_entry *entry,
- __u64 key, void *args)
-{
- struct rmtacl_downcall_data *data = args;
-
- return entry->u.acl.ra_handle - data->add_handle;
-}
-
-static int mdt_rmtacl_do_upcall(struct upcall_cache *cache,
- struct upcall_cache_entry *entry)
-{
- struct mdt_rmtacl *acl = &entry->u.acl;
- char uidstr[8] = "";
- char gidstr[8] = "";
- char handle[20] = "";
- char keystr[20] = "";
- char *argv[] = {
- [0] = cache->uc_upcall,
- [1] = uidstr,
- [2] = gidstr,
- [3] = cache->uc_name,
- [4] = keystr,
- [5] = handle,
- [6] = acl->ra_cmd,
- [7] = NULL
- };
- char *envp[] = {
- [0] = "HOME=/",
- [1] = "PATH=/bin:/usr/bin:/sbin:/usr/sbin",
- [2] = NULL
- };
- int rc;
- ENTRY;
-
- if (!acl->ra_cmd)
- RETURN(-ENOMEM);
-
- snprintf(uidstr, sizeof(uidstr), "%u", acl->ra_uid);
- snprintf(gidstr, sizeof(gidstr), "%u", acl->ra_gid);
- snprintf(keystr, sizeof(keystr), LPU64, entry->ue_key);
- snprintf(handle, sizeof(handle), "%u", acl->ra_handle);
-
- LASSERTF(strcmp(cache->uc_upcall, "NONE"), "no upcall set!");
-
- CDEBUG(D_INFO, "%s: remote acl upcall %s %s %s %s %s %s %s\n",
- cache->uc_name, argv[0], argv[1], argv[2], argv[3], argv[4],
- argv[5], argv[6]);
-
- rc = USERMODEHELPER(argv[0], argv, envp);
- if (rc < 0) {
- CERROR("%s: error invoking upcall %s %s %s %s %s %s %s: rc %d; "
- "check /proc/fs/lustre/mdt/%s/rmtacl_upcall\n",
- cache->uc_name, argv[0], argv[1], argv[2], argv[3],
- argv[4], argv[5], argv[6], rc, cache->uc_name);
- } else {
- CDEBUG(D_HA, "%s: invoked upcall %s %s %s %s %s %s %s\n",
- cache->uc_name, argv[0], argv[1], argv[2], argv[3],
- argv[4], argv[5], argv[6]);
- rc = 0;
- }
- RETURN(rc);
-}
-
-static int mdt_rmtacl_parse_downcall(struct upcall_cache *cache,
- struct upcall_cache_entry *entry,
- void *args)
-{
- struct mdt_rmtacl *acl = &entry->u.acl;
- struct rmtacl_downcall_data *data;
- char *buf;
- int len;
- ENTRY;
-
- data = (struct rmtacl_downcall_data *)args;
- LASSERT(data);
-
- len = strlen(data->add_buf) + 1;
- OBD_ALLOC(buf, len);
- if (!buf)
- RETURN(-ENOMEM);
-
- memcpy(buf, data->add_buf, len);
- acl->ra_buf = buf;
-
- CDEBUG(D_OTHER, "parse mdt acl@%p: %s %s\n",
- acl, acl->ra_cmd, acl->ra_buf);
-
- RETURN(0);
-}
-
-struct upcall_cache_ops mdt_rmtacl_upcall_cache_ops = {
- .init_entry = mdt_rmtacl_entry_init,
- .free_entry = mdt_rmtacl_entry_free,
- .upcall_compare = mdt_rmtacl_upcall_compare,
- .downcall_compare = mdt_rmtacl_downcall_compare,
- .do_upcall = mdt_rmtacl_do_upcall,
- .parse_downcall = mdt_rmtacl_parse_downcall,
-};
-
-int mdt_rmtacl_upcall(struct mdt_thread_info *info, char *cmd,
- struct lu_buf *buf)
-{
- struct mdt_device *mdt = info->mti_mdt;
- struct md_ucred *uc = mdt_ucred(info);
- struct rmtacl_upcall_data data;
- struct upcall_cache_entry *entry;
- __u64 key;
- int rc = 0;
- ENTRY;
-
- data.aud_uid = uc->mu_fsuid;
- data.aud_gid = uc->mu_fsgid;
- data.aud_cmd = cmd;
-
- key = mdt_rmtacl_getkey();
-
- entry = upcall_cache_get_entry(mdt->mdt_rmtacl_cache, key, &data);
- if (IS_ERR(entry))
- GOTO(out, rc = PTR_ERR(entry));
-
- if (buf->lb_len <= strlen(entry->u.acl.ra_buf))
- GOTO(out, rc = -EFAULT);
-
- memcpy(buf->lb_buf, entry->u.acl.ra_buf, strlen(entry->u.acl.ra_buf));
- /* remote acl operation expire at once! */
- UC_CACHE_SET_EXPIRED(entry);
- upcall_cache_put_entry(mdt->mdt_rmtacl_cache, entry);
-
-out:
- if (rc)
- sprintf(buf->lb_buf, "server processing error: %d\n", rc);
- RETURN(0);
-}
!strncmp(xattr_name, user_string, sizeof(user_string) - 1))
RETURN(-EOPNOTSUPP);
- if (!strcmp(xattr_name, XATTR_NAME_LUSTRE_ACL))
- size = RMTACL_SIZE_MAX;
- else
size = mo_xattr_get(info->mti_env,
mdt_object_child(info->mti_object),
&LU_BUF_NULL, xattr_name);
RETURN(size);
}
-static int do_remote_getfacl(struct mdt_thread_info *info, struct lu_buf *buf)
-{
- struct ptlrpc_request *req = mdt_info_req(info);
- char *cmd;
- int rc;
- ENTRY;
-
- if (!buf->lb_buf || (buf->lb_len != RMTACL_SIZE_MAX))
- RETURN(-EINVAL);
-
- cmd = req_capsule_client_get(&info->mti_pill, &RMF_EADATA);
- if (!cmd) {
- CERROR("missing getfacl command!\n");
- RETURN(-EFAULT);
- }
-
- rc = mdt_rmtacl_upcall(info, cmd, buf);
- if (rc)
- CERROR("remote acl upcall failed: %d\n", rc);
-
- lustre_shrink_reply(req, REPLY_REC_OFF + 1, strlen(buf->lb_buf) + 1, 0);
- RETURN(rc ?: strlen(buf->lb_buf) + 1);
-}
-
int mdt_getxattr(struct mdt_thread_info *info)
{
+ struct ptlrpc_request *req = mdt_info_req(info);
+ struct mdt_export_data *med = mdt_req2med(req);
+ struct md_ucred *uc = mdt_ucred(info);
struct mdt_body *reqbody;
struct mdt_body *repbody = NULL;
struct md_object *next;
if (rc)
RETURN(err_serious(rc));
+ next = mdt_object_child(info->mti_object);
+
+ if (info->mti_body->valid & OBD_MD_FLRMTRGETFACL) {
+ __u32 perm = mdt_identity_get_perm(uc->mu_identity,
+ med->med_rmtclient,
+ req->rq_peer.nid);
+
+ LASSERT(med->med_rmtclient);
+ if (!(perm & CFS_RMTACL_PERM))
+ GOTO(out, rc = err_serious(-EPERM));
+
+ rc = mo_permission(info->mti_env, NULL, next, NULL,
+ MAY_RGETFACL);
+ if (rc)
+ GOTO(out, rc = err_serious(rc));
+ }
+
easize = mdt_getxattr_pack_reply(info);
if (easize < 0)
GOTO(out, rc = err_serious(easize));
buf = &info->mti_buf;
buf->lb_buf = req_capsule_server_get(&info->mti_pill, &RMF_EADATA);
buf->lb_len = easize;
- next = mdt_object_child(info->mti_object);
if (info->mti_body->valid & OBD_MD_FLXATTR) {
+ int flags = CFS_IC_NOTHING;
char *xattr_name = req_capsule_client_get(&info->mti_pill,
&RMF_NAME);
CDEBUG(D_INODE, "getxattr %s\n", xattr_name);
- if (!strcmp(xattr_name, XATTR_NAME_LUSTRE_ACL))
- rc = do_remote_getfacl(info, buf);
- else
rc = mo_xattr_get(info->mti_env, next, buf, xattr_name);
-
- if (rc < 0)
+ if (rc < 0) {
CERROR("getxattr failed: %d\n", rc);
+ GOTO(out, rc);
+ }
+
+ if (info->mti_body->valid &
+ (OBD_MD_FLRMTLSETFACL | OBD_MD_FLRMTLGETFACL))
+ flags = CFS_IC_ALL;
+ else if (info->mti_body->valid & OBD_MD_FLRMTRGETFACL)
+ flags = CFS_IC_MAPPED;
+
+ if (rc > 0 && flags != CFS_IC_NOTHING) {
+ int rc1;
+
+ LASSERT(med->med_rmtclient);
+ rc1 = lustre_posix_acl_xattr_id2client(uc,
+ med->med_idmap,
+ (posix_acl_xattr_header *)(buf->lb_buf),
+ rc, flags);
+ if (unlikely(rc1 < 0))
+ rc = rc1;
+ }
} else if (info->mti_body->valid & OBD_MD_FLXATTRLS) {
CDEBUG(D_INODE, "listxattr\n");
return rc;
}
-/* return EADATA length to the caller. negative value means error */
-static int mdt_setxattr_pack_reply(struct mdt_thread_info * info)
-{
- struct req_capsule *pill = &info->mti_pill ;
- __u64 valid = info->mti_body->valid;
- int rc = 0, rc1;
-
- if ((valid & OBD_MD_FLXATTR) == OBD_MD_FLXATTR) {
- char *xattr_name;
-
- xattr_name = req_capsule_client_get(pill, &RMF_NAME);
- if (!xattr_name)
- return -EFAULT;
-
- if (!strcmp(xattr_name, XATTR_NAME_LUSTRE_ACL))
- rc = RMTACL_SIZE_MAX;
- }
-
- req_capsule_set_size(pill, &RMF_EADATA, RCL_SERVER, rc);
-
- rc1 = req_capsule_pack(pill);
-
- return rc = rc1 ? rc1 : rc;
-}
-
-static int do_remote_setfacl(struct mdt_thread_info *info)
+static int mdt_rmtlsetfacl(struct mdt_thread_info *info, char *xattr_name,
+ ext_acl_xattr_header *header,
+ posix_acl_xattr_header **out)
{
struct ptlrpc_request *req = mdt_info_req(info);
+ struct mdt_export_data *med = mdt_req2med(req);
+ struct md_ucred *uc = mdt_ucred(info);
+ struct md_object *next = mdt_object_child(info->mti_object);
struct lu_buf *buf = &info->mti_buf;
- char *cmd;
int rc;
ENTRY;
- cmd = req_capsule_client_get(&info->mti_pill, &RMF_EADATA);
- if (!cmd) {
- CERROR("missing setfacl command!\n");
- RETURN(-EFAULT);
+ rc = lustre_ext_acl_xattr_id2server(uc, med->med_idmap, header);
+ if (rc)
+ RETURN(rc);
+
+ rc = mo_xattr_get(info->mti_env, next, &LU_BUF_NULL, xattr_name);
+ if (rc == -ENODATA)
+ rc = 0;
+ else if (rc < 0)
+ RETURN(rc);
+
+ buf->lb_len = rc;
+ if (buf->lb_len > 0) {
+ OBD_ALLOC(buf->lb_buf, buf->lb_len);
+ if (unlikely(buf->lb_buf == NULL))
+ RETURN(-ENOMEM);
+
+ rc = mo_xattr_get(info->mti_env, next, buf, xattr_name);
+ if (rc < 0) {
+ CERROR("getxattr failed: %d\n", rc);
+ GOTO(_out, rc);
}
+ } else
+ buf->lb_buf = NULL;
- buf->lb_buf = req_capsule_server_get(&info->mti_pill, &RMF_EADATA);
- LASSERT(buf->lb_buf);
- buf->lb_len = RMTACL_SIZE_MAX;
+ rc = lustre_acl_xattr_merge2posix((posix_acl_xattr_header *)(buf->lb_buf),
+ buf->lb_len, header, out);
+ EXIT;
- rc = mdt_rmtacl_upcall(info, cmd, buf);
- if (rc)
- CERROR("remote acl upcall failed: %d\n", rc);
+_out:
+ if (rc <= 0 && buf->lb_buf != NULL)
+ OBD_FREE(buf->lb_buf, buf->lb_len);
- lustre_shrink_reply(req, REPLY_REC_OFF, strlen(buf->lb_buf) + 1, 0);
- RETURN(rc);
+ return rc;
}
int mdt_setxattr(struct mdt_thread_info *info)
{
struct ptlrpc_request *req = mdt_info_req(info);
+ struct mdt_export_data *med = mdt_req2med(req);
+ struct md_ucred *uc = mdt_ucred(info);
struct mdt_body *reqbody;
const char user_string[] = "user.";
const char trust_string[] = "trusted.";
struct lu_buf *buf = &info->mti_buf;
__u64 valid = body->valid;
char *xattr_name;
- int xattr_len;
+ int xattr_len = 0;
__u64 lockpart;
int rc;
+ posix_acl_xattr_header *new_xattr = NULL;
ENTRY;
CDEBUG(D_INODE, "setxattr "DFID"\n", PFID(&body->fid1));
if (rc)
RETURN(err_serious(rc));
- rc = mdt_setxattr_pack_reply(info);
+ if (valid & OBD_MD_FLRMTRSETFACL) {
+ __u32 perm = mdt_identity_get_perm(uc->mu_identity,
+ med->med_rmtclient,
+ req->rq_peer.nid);
+
+ LASSERT(med->med_rmtclient);
+ if (!(perm & CFS_RMTACL_PERM))
+ GOTO(out, rc = err_serious(-EPERM));
+ }
+
+ rc = req_capsule_pack(pill);
if (rc < 0)
GOTO(out, rc = err_serious(rc));
CDEBUG(D_INODE, "%s xattr %s\n",
body->valid & OBD_MD_FLXATTR ? "set" : "remove", xattr_name);
- if (((valid & OBD_MD_FLXATTR) == OBD_MD_FLXATTR) &&
- (!strcmp(xattr_name, XATTR_NAME_LUSTRE_ACL))) {
- rc = do_remote_setfacl(info);
- GOTO(out, rc);
- }
-
if (strncmp(xattr_name, trust_string, sizeof(trust_string) - 1) == 0) {
if (strcmp(xattr_name + 8, XATTR_NAME_LOV) == 0)
GOTO(out, rc = -EACCES);
int flags = 0;
xattr = req_capsule_client_get(pill, &RMF_EADATA);
+ if (valid & OBD_MD_FLRMTLSETFACL) {
+ LASSERT(med->med_rmtclient);
+ xattr_len = mdt_rmtlsetfacl(info, xattr_name,
+ (ext_acl_xattr_header *)xattr,
+ &new_xattr);
+ if (xattr_len < 0)
+ GOTO(out_unlock, rc = xattr_len);
+
+ xattr = (char *)new_xattr;
+ }
+
if (body->flags & XATTR_REPLACE)
flags |= LU_XATTR_REPLACE;
}
EXIT;
out_unlock:
+ if (unlikely(new_xattr != NULL))
+ lustre_posix_acl_xattr_free(new_xattr, xattr_len);
mdt_object_unlock(info, obj, lh, rc);
out:
mdt_exit_ucred(info);
CDEBUG(D_INFO, "log %s: requeue (l=%d r=%d sp=%d st=%x)\n",
cld->cld_logname, later, atomic_read(&cld->cld_refcount),
cld->cld_stopping, rq_state);
-
+
/* Hold lock for rq_state */
spin_lock(&config_list_lock);
cld->cld_lostlock = 1;
#include <obd.h>
#include <obd_class.h>
#include <lprocfs_status.h>
+#include <lustre_param.h>
#include "mgs_internal.h"
#ifdef LPROCFS
return rc;
}
+static void seq_show_srpc_rule(struct seq_file *seq, const char *tgtname,
+ struct sptlrpc_rule_set *rset)
+{
+ struct sptlrpc_rule *r;
+ char dirbuf[10];
+ char flvrbuf[40];
+ char *net;
+ int i;
+
+ for (i = 0; i < rset->srs_nrule; i++) {
+ r = &rset->srs_rules[i];
+
+ if (r->sr_netid == LNET_NIDNET(LNET_NID_ANY))
+ net = "default";
+ else
+ net = libcfs_net2str(r->sr_netid);
+
+ if (r->sr_from == LUSTRE_SP_ANY && r->sr_to == LUSTRE_SP_ANY)
+ dirbuf[0] = '\0';
+ else
+ snprintf(dirbuf, sizeof(dirbuf), ".%s2%s",
+ sptlrpc_part2name(r->sr_from),
+ sptlrpc_part2name(r->sr_to));
+
+ sptlrpc_flavor2name(&r->sr_flvr, flvrbuf, sizeof(flvrbuf));
+ seq_printf(seq, "%s.srpc.flavor.%s%s=%s\n", tgtname,
+ net, dirbuf, flvrbuf);
+ }
+}
+
static int mgs_live_seq_show(struct seq_file *seq, void *v)
{
- struct fs_db *fsdb = seq->private;
+ struct fs_db *fsdb = seq->private;
+ struct mgs_tgt_srpc_conf *srpc_tgt;
int i;
down(&fsdb->fsdb_sem);
if (test_bit(i, fsdb->fsdb_ost_index_map))
seq_printf(seq, "%s-OST%04x\n", fsdb->fsdb_name, i);
+ seq_printf(seq, "\nSecure RPC Config Rules:\n");
+#if 0
+ seq_printf(seq, "%s.%s=%s\n", fsdb->fsdb_name,
+ PARAM_SRPC_UDESC, fsdb->fsdb_srpc_fl_udesc ? "yes" : "no");
+#endif
+ for (srpc_tgt = fsdb->fsdb_srpc_tgt; srpc_tgt;
+ srpc_tgt = srpc_tgt->mtsc_next) {
+ seq_show_srpc_rule(seq, srpc_tgt->mtsc_tgt,
+ &srpc_tgt->mtsc_rset);
+ }
+ seq_show_srpc_rule(seq, fsdb->fsdb_name, &fsdb->fsdb_srpc_gen);
+
up(&fsdb->fsdb_sem);
return 0;
}
exp = class_conn2export(conn);
LASSERT(exp);
+ exp->exp_flvr.sf_rpc = SPTLRPC_FLVR_NULL;
+
if (data != NULL) {
data->ocd_connect_flags &= MGS_CONNECT_SUPPORTED;
exp->exp_connect_flags = data->ocd_connect_flags;
struct vfsmount *inmnt,
struct list_head *dentry_list);
+struct mgs_tgt_srpc_conf {
+ struct mgs_tgt_srpc_conf *mtsc_next;
+ char *mtsc_tgt;
+ struct sptlrpc_rule_set mtsc_rset;
+};
+
#define INDEX_MAP_SIZE 8192 /* covers indicies to FFFF */
#define FSDB_LOG_EMPTY 0x0001 /* missing client log */
#define FSDB_OLDLOG14 0x0002 /* log starts in old (1.4) style */
/* end COMPAT_146 */
__u32 fsdb_flags;
__u32 fsdb_gen;
+
+ /* in-memory copy of the srpc rules, guarded by fsdb_sem */
+ struct sptlrpc_rule_set fsdb_srpc_gen;
+ struct mgs_tgt_srpc_conf *fsdb_srpc_tgt;
+ unsigned int fsdb_srpc_fl_udesc:1;
};
int mgs_init_fsdb_list(struct obd_device *obd);
#include <lustre_sec.h>
#include "mgs_internal.h"
+static int mgs_get_fsdb_srpc_from_llog(struct obd_device *obd,
+ struct fs_db *fsdb);
+static int mgs_get_srpc_conf_log(struct fs_db *fsdb, const char *tgt,
+ enum lustre_sec_part from,
+ enum lustre_sec_part to,
+ struct sptlrpc_conf_log *log);
+
/********************** Class functions ********************/
/* Caller must list_del and OBD_FREE each dentry from the list */
RETURN(rc);
}
+static void mgs_free_fsdb_srpc(struct fs_db *fsdb)
+{
+ struct mgs_tgt_srpc_conf *tgtconf;
+
+ /* free target-specific rules */
+ while (fsdb->fsdb_srpc_tgt) {
+ tgtconf = fsdb->fsdb_srpc_tgt;
+ fsdb->fsdb_srpc_tgt = tgtconf->mtsc_next;
+
+ LASSERT(tgtconf->mtsc_tgt);
+
+ sptlrpc_rule_set_free(&tgtconf->mtsc_rset);
+ OBD_FREE(tgtconf->mtsc_tgt, strlen(tgtconf->mtsc_tgt) + 1);
+ OBD_FREE_PTR(tgtconf);
+ }
+
+ /* free general rules */
+ sptlrpc_rule_set_free(&fsdb->fsdb_srpc_gen);
+}
+
static struct fs_db *mgs_find_fsdb(struct obd_device *obd, char *fsname)
{
struct mgs_obd *mgs = &obd->u.mgs;
if (rc)
GOTO(err, rc);
+ fsdb->fsdb_srpc_fl_udesc = 1;
sema_init(&fsdb->fsdb_sem, 1);
list_add(&fsdb->fsdb_list, &mgs->mgs_fs_db_list);
lproc_mgs_add_live(obd, fsdb);
name_destroy(&fsdb->fsdb_mdtlov);
name_destroy(&fsdb->fsdb_mdtlmv);
name_destroy(&fsdb->fsdb_mdc);
+ mgs_free_fsdb_srpc(fsdb);
OBD_FREE_PTR(fsdb);
}
return rc;
}
+ /* populate srpc rules from params llog */
+ rc = mgs_get_fsdb_srpc_from_llog(obd, fsdb);
+ if (rc) {
+ CERROR("Can't get db from params log %d\n", rc);
+ mgs_free_fsdb(obd, fsdb);
+ return rc;
+ }
+
*dbh = fsdb;
return 0;
return record_base(obd,llh,devname,0,LCFG_SETUP,s1,s2,s3,s4);
}
-static inline int record_sec_flavor(struct obd_device *obd,
- struct llog_handle *llh, char *devname,
- struct sec_flavor_config *conf)
+static inline int record_sptlrpc_conf(struct obd_device *obd,
+ struct llog_handle *llh,
+ char *devname,
+ struct sptlrpc_conf_log *srpc_log)
{
struct lustre_cfg_bufs bufs;
struct lustre_cfg *lcfg;
int rc;
lustre_cfg_bufs_reset(&bufs, devname);
- lustre_cfg_bufs_set(&bufs, 1, conf, sizeof(*conf));
- lcfg = lustre_cfg_new(LCFG_SEC_FLAVOR, &bufs);
+ lustre_cfg_bufs_set(&bufs, 1, srpc_log, sizeof(*srpc_log));
+ lcfg = lustre_cfg_new(LCFG_SPTLRPC_CONF, &bufs);
rc = record_lcfg(obd, llh, lcfg);
/* Could use fsdb index maps instead of directory listing */
list_for_each_entry_safe(dirent, n, &dentry_list, lld_list) {
list_del(&dirent->lld_list);
- if (strncmp(fsname, dirent->lld_name, len) == 0) {
+ /* don't write to sptlrpc rule log */
+ if (strncmp(fsname, dirent->lld_name, len) == 0 &&
+ strstr(dirent->lld_name, "-sptlrpc") == NULL) {
CDEBUG(D_MGS, "Changing log %s\n", dirent->lld_name);
/* Erase any old settings of this same parameter */
mgs_modify(obd, fsdb, mti, dirent->lld_name, devname,
struct mgs_target_info *comp_mti;
struct fs_db *comp_fsdb;
struct obd_device *comp_obd;
- struct sec_flavor_config comp_sec;
};
static int mgs_write_log_mdc_to_mdt(struct obd_device *, struct fs_db *,
- struct mgs_target_info *,
- struct sec_flavor_config *, char *);
+ struct mgs_target_info *, char *);
static int mgs_steal_llog_handler(struct llog_handle *llh,
struct llog_rec_hdr *rec,
int cfg_len = rec->lrh_len;
char *cfg_buf = (char*) (rec + 1);
struct lustre_cfg *lcfg;
- struct sec_flavor_config *sec_conf;
int rc = 0;
struct llog_handle *mdt_llh = NULL;
static int got_an_osc_or_mdc = 0;
tmti = ((struct temp_comp*)data)->comp_tmti;
fsdb = ((struct temp_comp*)data)->comp_fsdb;
obd = ((struct temp_comp*)data)->comp_obd;
- sec_conf = &((struct temp_comp*)data)->comp_sec;
if (rec->lrh_type != OBD_CFG_REC) {
CERROR("unhandled lrh_type: %#x\n", rec->lrh_type);
RETURN(rc);
}
- if (lcfg->lcfg_command == LCFG_SEC_FLAVOR) {
- memcpy(sec_conf, lustre_cfg_buf(lcfg, 1), sizeof(*sec_conf));
+ /* ignore client side sptlrpc_conf_log */
+ if (lcfg->lcfg_command == LCFG_SPTLRPC_CONF)
RETURN(rc);
- }
if (lcfg->lcfg_command == LCFG_ADD_MDC) {
int index;
strlen(mti->mti_fsname));
tmti->mti_stripe_index = index;
- mgs_write_log_mdc_to_mdt(obd, fsdb, tmti, sec_conf,
- mti->mti_svname);
+ mgs_write_log_mdc_to_mdt(obd, fsdb, tmti, mti->mti_svname);
memset(tmti, 0, sizeof(*tmti));
RETURN(rc);
}
return rc;
}
-static
-void extract_sec_flavor(char *params, char *key, char **ptr)
-{
- char *val = NULL, *tail;
- int len;
-
- *ptr = NULL;
-
- if (class_find_param(params, key, &val))
- return;
-
- tail = strchr(val, ' ');
- if (tail == NULL)
- len = strlen(val);
- else
- len = tail - val;
-
- OBD_ALLOC(*ptr, len + 1);
- if (*ptr == NULL)
- return;
-
- memcpy(*ptr, val, len);
- (*ptr)[len] = '\0';
-}
-
static int mgs_write_log_mdc_to_lmv(struct obd_device *obd, struct fs_db *fsdb,
struct mgs_target_info *mti,
- struct sec_flavor_config *sec_conf,
char *logname, char *lmvname)
{
struct llog_handle *llh = NULL;
+ struct sptlrpc_conf_log *srpc_log;
char *mdcname, *nodeuuid, *mdcuuid, *lmvuuid;
char index[5];
int i, rc;
CDEBUG(D_MGS, "adding mdc for %s to log %s:lmv(%s)\n",
mti->mti_svname, logname, lmvname);
+ srpc_log = sptlrpc_conf_log_alloc();
+ if (IS_ERR(srpc_log))
+ RETURN(PTR_ERR(srpc_log));
+ srpc_log->scl_part = LUSTRE_SP_CLI;
+
+ rc = mgs_get_srpc_conf_log(fsdb, mti->mti_svname,
+ LUSTRE_SP_CLI, LUSTRE_SP_MDT, srpc_log);
+ if (rc)
+ goto out_srpc;
+
name_create(&nodeuuid, libcfs_nid2str(mti->mti_nids[0]), "");
name_create(&mdcname, mti->mti_svname, "-mdc");
name_create(&mdcuuid, mdcname, "_UUID");
rc = record_attach(obd, llh, mdcname, LUSTRE_MDC_NAME, lmvuuid);
rc = record_setup(obd, llh, mdcname, mti->mti_uuid, nodeuuid, 0, 0);
- rc = record_sec_flavor(obd, llh, mdcname, sec_conf);
+ rc = record_sptlrpc_conf(obd, llh, mdcname, srpc_log);
rc = mgs_write_log_failnids(obd, mti, llh, mdcname);
snprintf(index, sizeof(index), "%d", mti->mti_stripe_index);
rc = record_mdc_add(obd, llh, lmvname, mdcuuid, mti->mti_uuid,
name_destroy(&mdcuuid);
name_destroy(&mdcname);
name_destroy(&nodeuuid);
+out_srpc:
+ sptlrpc_conf_log_free(srpc_log);
RETURN(rc);
}
/* add new mdc to already existent MDS */
static int mgs_write_log_mdc_to_mdt(struct obd_device *obd, struct fs_db *fsdb,
- struct mgs_target_info *mti,
- struct sec_flavor_config *sec_conf,
- char *logname)
+ struct mgs_target_info *mti, char *logname)
{
struct llog_handle *llh = NULL;
+ struct sptlrpc_conf_log *srpc_log;
char *nodeuuid, *mdcname, *mdcuuid, *mdtuuid;
int idx = mti->mti_stripe_index;
char index[9];
CDEBUG(D_MGS, "adding mdc index %d to %s\n", idx, logname);
+ srpc_log = sptlrpc_conf_log_alloc();
+ if (IS_ERR(srpc_log))
+ RETURN(PTR_ERR(srpc_log));
+ srpc_log->scl_part = LUSTRE_SP_MDT;
+
+ rc = mgs_get_srpc_conf_log(fsdb, mti->mti_svname,
+ LUSTRE_SP_MDT, LUSTRE_SP_MDT, srpc_log);
+ if (rc)
+ goto out_srpc;
+
name_create(&nodeuuid, libcfs_nid2str(mti->mti_nids[0]), "");
snprintf(index, sizeof(index), "-mdc%04x", idx);
name_create(&mdcname, logname, index);
}
rc = record_attach(obd, llh, mdcname, LUSTRE_MDC_NAME, mdcuuid);
rc = record_setup(obd, llh, mdcname, mti->mti_uuid, nodeuuid, 0, 0);
- rc = record_sec_flavor(obd, llh, mdcname, sec_conf);
+ rc = record_sptlrpc_conf(obd, llh, mdcname, srpc_log);
rc = mgs_write_log_failnids(obd, mti, llh, mdcname);
snprintf(index, sizeof(index), "%d", idx);
name_destroy(&mdcname);
name_destroy(&nodeuuid);
name_destroy(&mdtuuid);
+out_srpc:
+ sptlrpc_conf_log_free(srpc_log);
RETURN(rc);
}
struct llog_handle *llh = NULL;
char *uuid, *lovname;
char mdt_index[5];
+ struct sptlrpc_conf_log *srpc_log;
char *ptr = mti->mti_params;
int rc = 0, failout = 0;
ENTRY;
+ srpc_log = sptlrpc_conf_log_alloc();
+ if (IS_ERR(srpc_log))
+ RETURN(PTR_ERR(srpc_log));
+ srpc_log->scl_part = LUSTRE_SP_MDT;
+
+ rc = mgs_get_srpc_conf_log(fsdb, mti->mti_svname,
+ LUSTRE_SP_ANY, LUSTRE_SP_MDT, srpc_log);
+ if (rc)
+ GOTO(out_srpc, rc);
+
OBD_ALLOC(uuid, sizeof(struct obd_uuid));
if (uuid == NULL)
- RETURN(-ENOMEM);
+ GOTO(out_srpc, rc = -ENOMEM);
if (class_find_param(ptr, PARAM_FAILMODE, &ptr) == 0)
failout = (strncmp(ptr, "failout", 7) == 0);
rc = record_mount_opt(obd, llh, log, lovname, NULL);
rc = record_setup(obd, llh, log, uuid, mdt_index, lovname,
failout ? "n" : "f");
+ rc = record_sptlrpc_conf(obd, llh, log, srpc_log);
rc = record_marker(obd, llh, fsdb, CM_END, log, "add mdt");
rc = record_end_log(obd, &llh);
out:
name_destroy(&lovname);
OBD_FREE(uuid, sizeof(struct obd_uuid));
+out_srpc:
+ sptlrpc_conf_log_free(srpc_log);
RETURN(rc);
}
static int mgs_write_log_mdt(struct obd_device *obd, struct fs_db *fsdb,
struct mgs_target_info *mti)
{
- char *cliname, *sec;
struct llog_handle *llh = NULL;
+ char *cliname;
struct temp_comp comp = { 0 };
- struct sec_flavor_config sec_conf_mdt, sec_conf_cli;
char mdt_index[9];
int rc, i = 0;
ENTRY;
"%s_UUID", mti->mti_svname);
}
- /* security flavor */
- extract_sec_flavor(mti->mti_params, PARAM_SEC_RPC_MDT, &sec);
- rc = sptlrpc_parse_flavor(LUSTRE_MDT, LUSTRE_MDT, sec, &sec_conf_mdt);
- name_destroy(&sec);
- if (rc)
- RETURN(rc);
-
- extract_sec_flavor(mti->mti_params, PARAM_SEC_RPC_CLI, &sec);
- rc = sptlrpc_parse_flavor(LUSTRE_CLI, LUSTRE_MDT, sec, &sec_conf_cli);
- name_destroy(&sec);
- if (rc)
- RETURN(rc);
-
/* add mdt */
rc = mgs_write_log_mdt0(obd, fsdb, mti);
rc = mgs_steal_llog_for_mdt_from_client(obd, cliname,
&comp);
- rc = mgs_write_log_mdc_to_lmv(obd, fsdb, mti, &sec_conf_cli,
- cliname, fsdb->fsdb_clilmv);
+ rc = mgs_write_log_mdc_to_lmv(obd, fsdb, mti, cliname,
+ fsdb->fsdb_clilmv);
/* add mountopts */
rc = record_start_log(obd, &llh, cliname);
if (rc)
sprintf(mdt_index,"-MDT%04x",i);
name_create(&mdtname, mti->mti_fsname, mdt_index);
- rc = mgs_write_log_mdc_to_mdt(obd, fsdb, mti,
- &sec_conf_mdt, mdtname);
+ rc = mgs_write_log_mdc_to_mdt(obd, fsdb, mti, mdtname);
name_destroy(&mdtname);
}
}
static int mgs_write_log_osc_to_lov(struct obd_device *obd, struct fs_db *fsdb,
struct mgs_target_info *mti,
char *logname, char *suffix, char *lovname,
- struct sec_flavor_config *sec_conf,
- int flags)
+ enum lustre_sec_part sec_part, int flags)
{
struct llog_handle *llh = NULL;
+ struct sptlrpc_conf_log *srpc_log;
char *nodeuuid, *oscname, *oscuuid, *lovuuid, *svname;
char index[5];
int i, rc;
CDEBUG(D_INFO, "adding osc for %s to log %s\n",
mti->mti_svname, logname);
+ srpc_log = sptlrpc_conf_log_alloc();
+ if (IS_ERR(srpc_log))
+ RETURN(PTR_ERR(srpc_log));
+ srpc_log->scl_part = sec_part;
+
+ rc = mgs_get_srpc_conf_log(fsdb, mti->mti_svname,
+ sec_part, LUSTRE_SP_OST, srpc_log);
+ if (rc)
+ goto out_srpc;
+
if (mgs_log_is_empty(obd, logname)) {
/* The first item in the log must be the lov, so we have
somewhere to add our osc. */
}
rc = record_attach(obd, llh, oscname, LUSTRE_OSC_NAME, lovuuid);
rc = record_setup(obd, llh, oscname, mti->mti_uuid, nodeuuid, 0, 0);
- rc = record_sec_flavor(obd, llh, oscname, sec_conf);
+ rc = record_sptlrpc_conf(obd, llh, oscname, srpc_log);
rc = mgs_write_log_failnids(obd, mti, llh, oscname);
snprintf(index, sizeof(index), "%d", mti->mti_stripe_index);
rc = record_lov_add(obd, llh, lovname, mti->mti_uuid, index, "1");
name_destroy(&oscname);
name_destroy(&svname);
name_destroy(&nodeuuid);
+out_srpc:
+ sptlrpc_conf_log_free(srpc_log);
RETURN(rc);
}
struct mgs_target_info *mti)
{
struct llog_handle *llh = NULL;
- char *logname, *lovname, *sec;
+ struct sptlrpc_conf_log *srpc_log;
+ char *logname, *lovname;
char mdt_index[9];
char *ptr = mti->mti_params;
- struct sec_flavor_config sec_conf_mdt, sec_conf_cli;
int rc, flags = 0, failout = 0, i;
ENTRY;
RETURN(-EALREADY);
}
- /* security flavors */
- extract_sec_flavor(mti->mti_params, PARAM_SEC_RPC_MDT, &sec);
- rc = sptlrpc_parse_flavor(LUSTRE_MDT, LUSTRE_OST, sec, &sec_conf_mdt);
- name_destroy(&sec);
- if (rc)
- RETURN(rc);
+ srpc_log = sptlrpc_conf_log_alloc();
+ if (IS_ERR(srpc_log))
+ RETURN(PTR_ERR(srpc_log));
+ srpc_log->scl_part = LUSTRE_SP_OST;
- extract_sec_flavor(mti->mti_params, PARAM_SEC_RPC_CLI, &sec);
- rc = sptlrpc_parse_flavor(LUSTRE_CLI, LUSTRE_OST, sec, &sec_conf_cli);
- name_destroy(&sec);
+ rc = mgs_get_srpc_conf_log(fsdb, mti->mti_svname,
+ LUSTRE_SP_ANY, LUSTRE_SP_OST, srpc_log);
if (rc)
- RETURN(rc);
+ goto out_srpc;
/*
attach obdfilter ost1 ost1_UUID
rc = record_setup(obd, llh, mti->mti_svname,
"dev"/*ignored*/, "type"/*ignored*/,
failout ? "n" : "f", 0/*options*/);
+ rc = record_sptlrpc_conf(obd, llh, mti->mti_svname, srpc_log);
rc = record_marker(obd, llh, fsdb, CM_END, mti->mti_svname, "add ost");
rc = record_end_log(obd, &llh);
name_create(&lovname, logname, "-mdtlov");
mgs_write_log_osc_to_lov(obd, fsdb, mti, logname,
mdt_index, lovname,
- &sec_conf_mdt, flags);
+ LUSTRE_SP_MDT, flags);
name_destroy(&logname);
name_destroy(&lovname);
}
/* Append ost info to the client log */
name_create(&logname, mti->mti_fsname, "-client");
mgs_write_log_osc_to_lov(obd, fsdb, mti, logname, "",
- fsdb->fsdb_clilov, &sec_conf_cli, 0);
+ fsdb->fsdb_clilov, LUSTRE_SP_CLI, 0);
name_destroy(&logname);
-
+out_srpc:
+ sptlrpc_conf_log_free(srpc_log);
RETURN(rc);
}
return rc;
}
+/*
+ * populate rules which applied to a target device
+ */
+static int mgs_get_srpc_conf_log(struct fs_db *fsdb, const char *tgt,
+ enum lustre_sec_part from,
+ enum lustre_sec_part to,
+ struct sptlrpc_conf_log *log)
+{
+ struct mgs_tgt_srpc_conf *tgtconf;
+ struct sptlrpc_rule_set *tgt_rset;
+ int found_tgt = 0, rc;
+
+ for (tgtconf = fsdb->fsdb_srpc_tgt; tgtconf;
+ tgtconf = tgtconf->mtsc_next) {
+ if (!strcmp(tgt, tgtconf->mtsc_tgt)) {
+ found_tgt = 1;
+ break;
+ }
+ }
+
+ if (found_tgt)
+ tgt_rset = &tgtconf->mtsc_rset;
+ else
+ tgt_rset = NULL;
+
+ rc = sptlrpc_conf_log_populate(&fsdb->fsdb_srpc_gen, tgt_rset,
+ from, to, fsdb->fsdb_srpc_fl_udesc, log);
+ if (rc)
+ CERROR("failed to populate srpc log for %s: %d\n", tgt, rc);
+
+ return rc;
+}
+
+struct mgs_msl_data {
+ struct obd_device *mmd_obd;
+ struct fs_db *mmd_fsdb;
+ struct mgs_target_info *mmd_mti;
+ int mmd_skip;
+ int mmd_attached;
+ int mmd_server;
+ enum lustre_sec_part mmd_tgtpart;
+ char mmd_tgtname[MTI_NAME_MAXLEN];
+};
+
+static void mgs_msl_data_cleanup(struct mgs_msl_data *mmd)
+{
+ mmd->mmd_attached = 0;
+ mmd->mmd_tgtname[0] = '\0';
+}
+
+static int mgs_msl_tgt_uuid2name(char *tgtname, char *tgtuuid)
+{
+ char *ptr;
+
+ if (tgtuuid == NULL) {
+ CERROR("missing target UUID???\n");
+ return -EINVAL;
+ }
+
+ ptr = strstr(tgtuuid, "_UUID");
+ if (ptr == NULL) {
+ CERROR("unrecognized UUID: %s\n", tgtuuid);
+ return -EINVAL;
+ }
+
+ *ptr = '\0';;
+ strncpy(tgtname, tgtuuid, MTI_NAME_MAXLEN);
+ tgtname[MTI_NAME_MAXLEN - 1] = '\0';
+
+ return 0;
+}
+
+static int mgs_modify_srpc_log_handler(struct llog_handle *llh,
+ struct llog_rec_hdr *rec,
+ void *data)
+{
+ struct mgs_msl_data *mmd = (struct mgs_msl_data *)data;
+ struct cfg_marker *marker;
+ struct lustre_cfg *lcfg = (struct lustre_cfg *)(rec + 1);
+ int cfg_len, rc;
+ ENTRY;
+
+ if (rec->lrh_type != OBD_CFG_REC) {
+ CERROR("unhandled lrh_type: %#x\n", rec->lrh_type);
+ RETURN(-EINVAL);
+ }
+
+ cfg_len = rec->lrh_len - sizeof(struct llog_rec_hdr) -
+ sizeof(struct llog_rec_tail);
+
+ rc = lustre_cfg_sanity_check(lcfg, cfg_len);
+ if (rc) {
+ CERROR("Insane cfg\n");
+ RETURN(rc);
+ }
+
+ if (lcfg->lcfg_command == LCFG_MARKER) {
+ marker = lustre_cfg_buf(lcfg, 1);
+
+ if (marker->cm_flags & CM_START &&
+ marker->cm_flags & CM_SKIP)
+ mmd->mmd_skip = 1;
+ if (marker->cm_flags & CM_END)
+ mmd->mmd_skip = 0;
+
+ RETURN(0);
+ }
+
+ if (mmd->mmd_skip)
+ RETURN(0);
+
+ switch (lcfg->lcfg_command) {
+ case LCFG_ATTACH:
+ mmd->mmd_attached = 1;
+
+ if (!strcmp(lustre_cfg_string(lcfg, 1), LUSTRE_OST_NAME)) {
+ mmd->mmd_server = 1;
+ mmd->mmd_tgtpart = LUSTRE_SP_OST;
+ } else if (!strcmp(lustre_cfg_string(lcfg, 1),
+ LUSTRE_MDT_NAME)) {
+ mmd->mmd_server = 1;
+ mmd->mmd_tgtpart = LUSTRE_SP_MDT;
+ } else if (!strcmp(lustre_cfg_string(lcfg, 1),
+ LUSTRE_OSC_NAME)) {
+ mmd->mmd_server = 0;
+ mmd->mmd_tgtpart = LUSTRE_SP_OST;
+ } else if (!strcmp(lustre_cfg_string(lcfg, 1),
+ LUSTRE_MDC_NAME)) {
+ mmd->mmd_server = 0;
+ mmd->mmd_tgtpart = LUSTRE_SP_MDT;
+ } else {
+ mmd->mmd_attached = 0;
+ }
+
+ if (mmd->mmd_attached && mmd->mmd_server) {
+ rc = mgs_msl_tgt_uuid2name(mmd->mmd_tgtname,
+ lustre_cfg_string(lcfg, 2));
+ if (rc) {
+ mgs_msl_data_cleanup(mmd);
+ break;
+ }
+ }
+
+ break;
+ case LCFG_SETUP:
+ if (!mmd->mmd_attached)
+ break;
+
+ /* already got tgtname at LCFG_ATTACH */
+ if (mmd->mmd_server)
+ break;
+
+ rc = mgs_msl_tgt_uuid2name(mmd->mmd_tgtname,
+ lustre_cfg_string(lcfg, 1));
+ if (rc) {
+ mgs_msl_data_cleanup(mmd);
+ break;
+ }
+
+ break;
+ case LCFG_SPTLRPC_CONF: {
+ struct sptlrpc_conf_log *log;
+ enum lustre_sec_part from;
+
+ if (!mmd->mmd_attached)
+ break;
+
+ log = sptlrpc_conf_log_extract(lcfg);
+ if (log == NULL) {
+ CERROR("missing sptlrpc config log???\n");
+ mgs_msl_data_cleanup(mmd);
+ break;
+ }
+
+ if (mmd->mmd_server)
+ from = LUSTRE_SP_ANY;
+ else
+ from = log->scl_part;
+
+ /* cleanup the old log */
+ sptlrpc_conf_log_cleanup(log);
+
+ /* populate new log */
+ rc = mgs_get_srpc_conf_log(mmd->mmd_fsdb, mmd->mmd_tgtname,
+ from, mmd->mmd_tgtpart, log);
+ if (rc) {
+ mgs_msl_data_cleanup(mmd);
+ break;
+ }
+
+ /* Overwrite the log */
+ rec->lrh_len = cfg_len;
+ rc = llog_write_rec(llh, rec, NULL, 0, (void *)lcfg,
+ rec->lrh_index);
+ if (rc)
+ CERROR("overwrite sptlrpc conf log failed: %d\n", rc);
+
+ /* append new one */
+ rc = record_marker(mmd->mmd_obd, llh, mmd->mmd_fsdb, CM_START,
+ mmd->mmd_mti->mti_svname, "sptlrpc config");
+ rc = record_sptlrpc_conf(mmd->mmd_obd, llh,
+ lustre_cfg_string(lcfg, 0), log);
+ rc = record_marker(mmd->mmd_obd, llh, mmd->mmd_fsdb, CM_END,
+ mmd->mmd_mti->mti_svname, "sptlrpc config");
+
+ mgs_msl_data_cleanup(mmd);
+ break;
+ }
+ default:
+ /* ignore all others */
+ break;
+ }
+
+ RETURN(rc);
+}
+
+static int mgs_modify_srpc_log(struct obd_device *obd,
+ struct fs_db *fsdb,
+ struct mgs_target_info *mti,
+ char *logname)
+{
+ struct llog_handle *llh;
+ struct lvfs_run_ctxt saved;
+ struct mgs_msl_data *mmd;
+ int rc, rc2;
+ ENTRY;
+
+ CDEBUG(D_MGS, "modify sptlrpc log for %s\n", logname);
+
+ push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
+
+ rc = llog_create(llog_get_context(obd, LLOG_CONFIG_ORIG_CTXT),
+ &llh, NULL, logname);
+ if (rc)
+ GOTO(out_pop, rc);
+
+ rc = llog_init_handle(llh, LLOG_F_IS_PLAIN, NULL);
+ if (rc)
+ GOTO(out_close, rc);
+
+ if (llog_get_size(llh) <= 1)
+ GOTO(out_close, rc = 0);
+
+ OBD_ALLOC_PTR(mmd);
+ if (!mmd)
+ GOTO(out_close, rc = -ENOMEM);
+
+ mmd->mmd_obd = obd;
+ mmd->mmd_fsdb = fsdb;
+ mmd->mmd_mti = mti;
+
+ rc = llog_process(llh, mgs_modify_srpc_log_handler, (void *) mmd, NULL);
+
+ OBD_FREE_PTR(mmd);
+
+out_close:
+ rc2 = llog_close(llh);
+ if (!rc)
+ rc = rc2;
+
+out_pop:
+ pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
+ if (rc)
+ CERROR("modify sptlrpc log %s failed %d\n", logname, rc);
+
+ RETURN(rc);
+}
+
+/*
+ * for each of log, remove old conf at first
+ */
+static int mgs_modify_srpc_log_all(struct obd_device *obd,
+ struct fs_db *fsdb,
+ struct mgs_target_info *mti)
+{
+ char tgt_index[9];
+ char *logname;
+ int i, rc = 0, rc2;
+ ENTRY;
+
+ for (i = 0; i < INDEX_MAP_SIZE * 8; i++){
+ if (test_bit(i, fsdb->fsdb_mdt_index_map)) {
+ sprintf(tgt_index,"-MDT%04x",i);
+
+ name_create(&logname, mti->mti_fsname, tgt_index);
+ rc2 = mgs_modify(obd, fsdb, mti, logname,
+ mti->mti_fsname, "sptlrpc config",
+ CM_SKIP);
+ rc2 = mgs_modify_srpc_log(obd, fsdb, mti, logname);
+ name_destroy(&logname);
+
+ if (rc2 && rc == 0)
+ rc = rc2;
+ }
+ }
+
+ for (i = 0; i < INDEX_MAP_SIZE * 8; i++){
+ if (test_bit(i, fsdb->fsdb_ost_index_map)) {
+ sprintf(tgt_index,"-OST%04x",i);
+
+ name_create(&logname, mti->mti_fsname, tgt_index);
+ rc2 = mgs_modify(obd, fsdb, mti, logname,
+ mti->mti_fsname, "sptlrpc config",
+ CM_SKIP);
+ rc2 = mgs_modify_srpc_log(obd, fsdb, mti, logname);
+ name_destroy(&logname);
+
+ if (rc2 && rc == 0)
+ rc = rc2;
+ }
+ }
+
+ name_create(&logname, mti->mti_fsname, "-client");
+ rc2 = mgs_modify(obd, fsdb, mti, logname,
+ mti->mti_fsname, "sptlrpc config", CM_SKIP);
+ rc2 = mgs_modify_srpc_log(obd, fsdb, mti, logname);
+ name_destroy(&logname);
+
+ if (rc2 && rc == 0)
+ rc = rc2;
+
+ RETURN(rc);
+}
+
+static int mgs_srpc_set_param_disk(struct obd_device *obd,
+ struct fs_db *fsdb,
+ struct mgs_target_info *mti,
+ char *param)
+{
+ struct llog_handle *llh = NULL;
+ char *logname;
+ char *comment, *ptr;
+ struct lustre_cfg_bufs bufs;
+ struct lustre_cfg *lcfg;
+ int rc, len;
+ ENTRY;
+
+ /* get comment */
+ ptr = strchr(param, '=');
+ LASSERT(ptr);
+ len = ptr - param;
+
+ OBD_ALLOC(comment, len + 1);
+ if (comment == NULL)
+ RETURN(-ENOMEM);
+ strncpy(comment, param, len);
+ comment[len] = '\0';
+
+ /* prepare lcfg */
+ lustre_cfg_bufs_reset(&bufs, mti->mti_svname);
+ lustre_cfg_bufs_set_string(&bufs, 1, param);
+ lcfg = lustre_cfg_new(0, &bufs);
+ if (lcfg == NULL)
+ GOTO(out_comment, rc = -ENOMEM);
+
+ /* construct log name */
+ rc = name_create(&logname, mti->mti_fsname, "-sptlrpc");
+ if (rc)
+ GOTO(out_lcfg, rc);
+
+ if (mgs_log_is_empty(obd, logname)) {
+ rc = record_start_log(obd, &llh, logname);
+ record_end_log(obd, &llh);
+ if (rc)
+ GOTO(out, rc);
+ }
+
+ /* obsolete old one */
+ mgs_modify(obd, fsdb, mti, logname, mti->mti_svname, comment, CM_SKIP);
+
+ /* write the new one */
+ rc = mgs_write_log_direct(obd, fsdb, logname, lcfg,
+ mti->mti_svname, comment);
+ if (rc)
+ CERROR("err %d writing log %s\n", rc, logname);
+
+out:
+ name_destroy(&logname);
+out_lcfg:
+ lustre_cfg_free(lcfg);
+out_comment:
+ OBD_FREE(comment, len + 1);
+ RETURN(rc);
+}
+
+static int mgs_srpc_set_param_udesc_mem(struct fs_db *fsdb,
+ char *param)
+{
+ char *ptr;
+
+ /* disable the adjustable udesc parameter for now, i.e. use default
+ * setting that client always ship udesc to MDT if possible. to enable
+ * it simply remove the following line */
+ goto error_out;
+
+ ptr = strchr(param, '=');
+ if (ptr == NULL)
+ goto error_out;
+ *ptr++ = '\0';
+
+ if (strcmp(param, PARAM_SRPC_UDESC))
+ goto error_out;
+
+ if (strcmp(ptr, "yes") == 0) {
+ fsdb->fsdb_srpc_fl_udesc = 1;
+ CWARN("Enable user descriptor shipping from client to MDT\n");
+ } else if (strcmp(ptr, "no") == 0) {
+ fsdb->fsdb_srpc_fl_udesc = 0;
+ CWARN("Disable user descriptor shipping from client to MDT\n");
+ } else {
+ *(ptr - 1) = '=';
+ goto error_out;
+ }
+ return 0;
+
+error_out:
+ CERROR("Invalid param: %s\n", param);
+ return -EINVAL;
+}
+
+static int mgs_srpc_set_param_mem(struct fs_db *fsdb,
+ const char *svname,
+ char *param)
+{
+ struct sptlrpc_rule rule;
+ struct sptlrpc_rule_set *rset;
+ int rc;
+ ENTRY;
+
+ if (strncmp(param, PARAM_SRPC, sizeof(PARAM_SRPC) - 1) != 0) {
+ CERROR("Invalid sptlrpc parameter: %s\n", param);
+ RETURN(-EINVAL);
+ }
+
+ if (strncmp(param, PARAM_SRPC_UDESC,
+ sizeof(PARAM_SRPC_UDESC) - 1) == 0) {
+ RETURN(mgs_srpc_set_param_udesc_mem(fsdb, param));
+ }
+
+ if (strncmp(param, PARAM_SRPC_FLVR, sizeof(PARAM_SRPC_FLVR) - 1) != 0) {
+ CERROR("Invalid sptlrpc flavor parameter: %s\n", param);
+ RETURN(-EINVAL);
+ }
+
+ param += sizeof(PARAM_SRPC_FLVR) - 1;
+
+ rc = sptlrpc_parse_rule(param, &rule);
+ if (rc)
+ RETURN(rc);
+
+ /* preapre room for this coming rule. svcname format should be:
+ * - fsname: general rule
+ * - fsname-tgtname: target-specific rule
+ */
+ if (strchr(svname, '-')) {
+ struct mgs_tgt_srpc_conf *tgtconf;
+ int found = 0;
+
+ for (tgtconf = fsdb->fsdb_srpc_tgt; tgtconf != NULL;
+ tgtconf = tgtconf->mtsc_next) {
+ if (!strcmp(tgtconf->mtsc_tgt, svname)) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found) {
+ int name_len;
+
+ OBD_ALLOC_PTR(tgtconf);
+ if (tgtconf == NULL)
+ RETURN(-ENOMEM);
+
+ name_len = strlen(svname);
+
+ OBD_ALLOC(tgtconf->mtsc_tgt, name_len + 1);
+ if (tgtconf->mtsc_tgt == NULL) {
+ OBD_FREE_PTR(tgtconf);
+ RETURN(-ENOMEM);
+ }
+ memcpy(tgtconf->mtsc_tgt, svname, name_len);
+
+ tgtconf->mtsc_next = fsdb->fsdb_srpc_tgt;
+ fsdb->fsdb_srpc_tgt = tgtconf;
+ }
+
+ rset = &tgtconf->mtsc_rset;
+ } else {
+ rset = &fsdb->fsdb_srpc_gen;
+ }
+
+ /* limit the maximum number of rules, but allow deletion in any case */
+ if (rset->srs_nrule >= SPTLRPC_CONF_LOG_MAX / 2 &&
+ rule.sr_flvr.sf_rpc != SPTLRPC_FLVR_INVALID) {
+ CERROR("too many (%d) rules already for %s\n",
+ rset->srs_nrule, svname);
+ RETURN(-E2BIG);
+ }
+
+ rc = sptlrpc_rule_set_merge(rset, &rule, 1);
+
+ RETURN(rc);
+}
+
+static int mgs_srpc_set_param(struct obd_device *obd,
+ struct fs_db *fsdb,
+ struct mgs_target_info *mti,
+ char *param)
+{
+ char *copy;
+ int rc, copy_size;
+ ENTRY;
+
+ /* keep a copy of original param, which could be destroied
+ * during parsing */
+ copy_size = strlen(param) + 1;
+ OBD_ALLOC(copy, copy_size);
+ if (copy == NULL)
+ return -ENOMEM;
+ memcpy(copy, param, copy_size);
+
+ rc = mgs_srpc_set_param_mem(fsdb, mti->mti_svname, param);
+ if (rc)
+ goto out_free;
+
+ /* previous steps guaranteed the syntax is correct */
+ rc = mgs_srpc_set_param_disk(obd, fsdb, mti, copy);
+ if (rc)
+ goto out_free;
+
+ /* now apply the new rules to all existing config logs */
+ rc = mgs_modify_srpc_log_all(obd, fsdb, mti);
+
+out_free:
+ OBD_FREE(copy, copy_size);
+ RETURN(rc);
+}
+
+struct mgs_srpc_read_data {
+ struct fs_db *msrd_fsdb;
+ int msrd_skip;
+};
+
+static int mgs_srpc_read_handler(struct llog_handle *llh,
+ struct llog_rec_hdr *rec,
+ void *data)
+{
+ struct mgs_srpc_read_data *msrd = (struct mgs_srpc_read_data *) data;
+ struct cfg_marker *marker;
+ struct lustre_cfg *lcfg = (struct lustre_cfg *)(rec + 1);
+ char *svname, *param;
+ int cfg_len, rc;
+ ENTRY;
+
+ if (rec->lrh_type != OBD_CFG_REC) {
+ CERROR("unhandled lrh_type: %#x\n", rec->lrh_type);
+ RETURN(-EINVAL);
+ }
+
+ cfg_len = rec->lrh_len - sizeof(struct llog_rec_hdr) -
+ sizeof(struct llog_rec_tail);
+
+ rc = lustre_cfg_sanity_check(lcfg, cfg_len);
+ if (rc) {
+ CERROR("Insane cfg\n");
+ RETURN(rc);
+ }
+
+ if (lcfg->lcfg_command == LCFG_MARKER) {
+ marker = lustre_cfg_buf(lcfg, 1);
+
+ if (marker->cm_flags & CM_START &&
+ marker->cm_flags & CM_SKIP)
+ msrd->msrd_skip = 1;
+ if (marker->cm_flags & CM_END)
+ msrd->msrd_skip = 0;
+
+ RETURN(0);
+ }
+
+ if (msrd->msrd_skip)
+ RETURN(0);
+
+ if (lcfg->lcfg_command != 0) {
+ CERROR("invalid command (%x)\n", lcfg->lcfg_command);
+ RETURN(0);
+ }
+
+ svname = lustre_cfg_string(lcfg, 0);
+ if (svname == NULL) {
+ CERROR("svname is empty\n");
+ RETURN(0);
+ }
+
+ param = lustre_cfg_string(lcfg, 1);
+ if (param == NULL) {
+ CERROR("param is empty\n");
+ RETURN(0);
+ }
+
+ rc = mgs_srpc_set_param_mem(msrd->msrd_fsdb, svname, param);
+ if (rc)
+ CERROR("read sptlrpc record error (%d): %s\n", rc, param);
+
+ RETURN(0);
+}
+
+static int mgs_get_fsdb_srpc_from_llog(struct obd_device *obd,
+ struct fs_db *fsdb)
+{
+ struct llog_handle *llh = NULL;
+ struct lvfs_run_ctxt saved;
+ char *logname;
+ struct mgs_srpc_read_data msrd;
+ int rc;
+ ENTRY;
+
+ /* construct log name */
+ rc = name_create(&logname, fsdb->fsdb_name, "-sptlrpc");
+ if (rc)
+ RETURN(rc);
+
+ if (mgs_log_is_empty(obd, logname))
+ GOTO(out, rc = 0);
+
+ push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
+
+ rc = llog_create(llog_get_context(obd, LLOG_CONFIG_ORIG_CTXT),
+ &llh, NULL, logname);
+ if (rc)
+ GOTO(out_pop, rc);
+
+ rc = llog_init_handle(llh, LLOG_F_IS_PLAIN, NULL);
+ if (rc)
+ GOTO(out_close, rc);
+
+ if (llog_get_size(llh) <= 1)
+ GOTO(out_close, rc = 0);
+
+ msrd.msrd_fsdb = fsdb;
+ msrd.msrd_skip = 0;
+
+ rc = llog_process(llh, mgs_srpc_read_handler, (void *) &msrd, NULL);
+
+out_close:
+ llog_close(llh);
+out_pop:
+ pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
+out:
+ name_destroy(&logname);
+
+ if (rc)
+ CERROR("failed to read sptlrpc config database: %d\n", rc);
+ RETURN(rc);
+}
+
static int mgs_write_log_params(struct obd_device *obd, struct fs_db *fsdb,
struct mgs_target_info *mti)
{
}
GOTO(end_while, rc);
}
- /* Processed in mgs_write_log_mdt/mgs_write_log_ost */
- if (class_match_param(ptr, PARAM_SEC_RPC_MDT, NULL) == 0 ||
- class_match_param(ptr, PARAM_SEC_RPC_CLI, NULL) == 0)
+
+ if (class_match_param(ptr, PARAM_SRPC, NULL) == 0) {
+ rc = mgs_srpc_set_param(obd, fsdb, mti, ptr);
GOTO(end_while, rc);
+ }
if (class_match_param(ptr, PARAM_FAILNODE, NULL) == 0) {
/* Add a failover nidlist */
obdclass-all-objs += lprocfs_status.o lustre_handles.o lustre_peer.o
obdclass-all-objs += statfs_pack.o obdo.o obd_config.o obd_mount.o mea.o
obdclass-all-objs += lu_object.o dt_object.o hash.o capa.o lu_time.o
+obdclass-all-objs += acl.o idmap.o
obdclass-objs := $(obdclass-linux-objs) $(obdclass-all-objs)
--- /dev/null
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ * lustre/obdclass/acl.c
+ * Lustre Access Control List.
+ * Author: Fan Yong <fanyong@clusterfs.com>
+ *
+ * Copyright (c) 2004-2007 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.
+ */
+#ifndef EXPORT_SYMTAB
+# define EXPORT_SYMTAB
+#endif
+
+#define DEBUG_SUBSYSTEM S_SEC
+
+#include <linux/lustre_acl.h>
+#include <lustre_eacl.h>
+#include <obd_support.h>
+
+#ifdef CONFIG_FS_POSIX_ACL
+
+#define CFS_ACL_XATTR_VERSION POSIX_ACL_XATTR_VERSION
+
+enum {
+ ES_UNK = 0, /* unknown stat */
+ ES_UNC = 1, /* ACL entry is not changed */
+ ES_MOD = 2, /* ACL entry is modified */
+ ES_ADD = 3, /* ACL entry is added */
+ ES_DEL = 4 /* ACL entry is deleted */
+};
+
+static inline void lustre_ext_acl_le_to_cpu(ext_acl_xattr_entry *d,
+ ext_acl_xattr_entry *s)
+{
+ d->e_tag = le16_to_cpu(s->e_tag);
+ d->e_perm = le16_to_cpu(s->e_perm);
+ d->e_id = le32_to_cpu(s->e_id);
+ d->e_stat = le32_to_cpu(s->e_stat);
+}
+
+static inline void lustre_ext_acl_cpu_to_le(ext_acl_xattr_entry *d,
+ ext_acl_xattr_entry *s)
+{
+ d->e_tag = cpu_to_le16(s->e_tag);
+ d->e_perm = cpu_to_le16(s->e_perm);
+ d->e_id = cpu_to_le32(s->e_id);
+ d->e_stat = cpu_to_le32(s->e_stat);
+}
+
+static inline void lustre_posix_acl_le_to_cpu(posix_acl_xattr_entry *d,
+ posix_acl_xattr_entry *s)
+{
+ d->e_tag = le16_to_cpu(s->e_tag);
+ d->e_perm = le16_to_cpu(s->e_perm);
+ d->e_id = le32_to_cpu(s->e_id);
+}
+
+static inline void lustre_posix_acl_cpu_to_le(posix_acl_xattr_entry *d,
+ posix_acl_xattr_entry *s)
+{
+ d->e_tag = cpu_to_le16(s->e_tag);
+ d->e_perm = cpu_to_le16(s->e_perm);
+ d->e_id = cpu_to_le32(s->e_id);
+}
+
+/*
+ * Check permission based on POSIX ACL.
+ */
+int lustre_posix_acl_permission(struct md_ucred *mu, struct lu_attr *la,
+ int want, posix_acl_xattr_entry *entry,
+ int count)
+{
+ posix_acl_xattr_entry *pa, *pe, *mask_obj;
+ posix_acl_xattr_entry ae, me;
+ int found = 0;
+
+ if (count <= 0)
+ return -EACCES;
+
+ for (pa = &entry[0], pe = &entry[count - 1]; pa <= pe; pa++) {
+ lustre_posix_acl_le_to_cpu(&ae, pa);
+ switch (ae.e_tag) {
+ case ACL_USER_OBJ:
+ /* (May have been checked already) */
+ if (la->la_uid == mu->mu_fsuid)
+ goto check_perm;
+ break;
+ case ACL_USER:
+ if (ae.e_id == mu->mu_fsuid)
+ goto mask;
+ break;
+ case ACL_GROUP_OBJ:
+ if (lustre_in_group_p(mu, la->la_gid)) {
+ found = 1;
+ if ((ae.e_perm & want) == want)
+ goto mask;
+ }
+ break;
+ case ACL_GROUP:
+ if (lustre_in_group_p(mu, ae.e_id)) {
+ found = 1;
+ if ((ae.e_perm & want) == want)
+ goto mask;
+ }
+ break;
+ case ACL_MASK:
+ break;
+ case ACL_OTHER:
+ if (found)
+ return -EACCES;
+ else
+ goto check_perm;
+ default:
+ return -EIO;
+ }
+ }
+ return -EIO;
+
+mask:
+ for (mask_obj = pa + 1; mask_obj <= pe; mask_obj++) {
+ lustre_posix_acl_le_to_cpu(&me, mask_obj);
+ if (me.e_tag == ACL_MASK) {
+ if ((ae.e_perm & me.e_perm & want) == want)
+ return 0;
+
+ return -EACCES;
+ }
+ }
+
+check_perm:
+ if ((ae.e_perm & want) == want)
+ return 0;
+
+ return -EACCES;
+}
+EXPORT_SYMBOL(lustre_posix_acl_permission);
+
+/*
+ * Modify the ACL for the chmod.
+ */
+int lustre_posix_acl_chmod_masq(posix_acl_xattr_entry *entry, __u32 mode,
+ int count)
+{
+ posix_acl_xattr_entry *group_obj = NULL, *mask_obj = NULL, *pa, *pe;
+
+ for (pa = &entry[0], pe = &entry[count - 1]; pa <= pe; pa++) {
+ switch (le16_to_cpu(pa->e_tag)) {
+ case ACL_USER_OBJ:
+ pa->e_perm = cpu_to_le16((mode & S_IRWXU) >> 6);
+ break;
+ case ACL_USER:
+ case ACL_GROUP:
+ break;
+ case ACL_GROUP_OBJ:
+ group_obj = pa;
+ break;
+ case ACL_MASK:
+ mask_obj = pa;
+ break;
+ case ACL_OTHER:
+ pa->e_perm = cpu_to_le16(mode & S_IRWXO);
+ break;
+ default:
+ return -EIO;
+ }
+ }
+
+ if (mask_obj) {
+ mask_obj->e_perm = cpu_to_le16((mode & S_IRWXG) >> 3);
+ } else {
+ if (!group_obj)
+ return -EIO;
+ group_obj->e_perm = cpu_to_le16((mode & S_IRWXG) >> 3);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(lustre_posix_acl_chmod_masq);
+
+/*
+ * Modify acl when creating a new object.
+ */
+int lustre_posix_acl_create_masq(posix_acl_xattr_entry *entry, __u32 *pmode,
+ int count)
+{
+ posix_acl_xattr_entry *group_obj = NULL, *mask_obj = NULL, *pa, *pe;
+ posix_acl_xattr_entry ae;
+ __u32 mode = *pmode;
+ int not_equiv = 0;
+
+ for (pa = &entry[0], pe = &entry[count - 1]; pa <= pe; pa++) {
+ lustre_posix_acl_le_to_cpu(&ae, pa);
+ switch (ae.e_tag) {
+ case ACL_USER_OBJ:
+ ae.e_perm &= (mode >> 6) | ~S_IRWXO;
+ pa->e_perm = cpu_to_le16(ae.e_perm);
+ mode &= (ae.e_perm << 6) | ~S_IRWXU;
+ break;
+ case ACL_USER:
+ case ACL_GROUP:
+ not_equiv = 1;
+ break;
+ case ACL_GROUP_OBJ:
+ group_obj = pa;
+ break;
+ case ACL_OTHER:
+ ae.e_perm &= mode | ~S_IRWXO;
+ pa->e_perm = cpu_to_le16(ae.e_perm);
+ mode &= ae.e_perm | ~S_IRWXO;
+ break;
+ case ACL_MASK:
+ mask_obj = pa;
+ not_equiv = 1;
+ break;
+ default:
+ return -EIO;
+ }
+ }
+
+ if (mask_obj) {
+ ae.e_perm = le16_to_cpu(mask_obj->e_perm) &
+ ((mode >> 3) | ~S_IRWXO);
+ mode &= (ae.e_perm << 3) | ~S_IRWXG;
+ mask_obj->e_perm = cpu_to_le16(ae.e_perm);
+ } else {
+ if (!group_obj)
+ return -EIO;
+ ae.e_perm = le16_to_cpu(group_obj->e_perm) &
+ ((mode >> 3) | ~S_IRWXO);
+ mode &= (ae.e_perm << 3) | ~S_IRWXG;
+ group_obj->e_perm = cpu_to_le16(ae.e_perm);
+ }
+
+ *pmode = (*pmode & ~S_IRWXUGO) | mode;
+ return not_equiv;
+}
+EXPORT_SYMBOL(lustre_posix_acl_create_masq);
+
+/* if "new_count == 0", then "new = {a_version, NULL}", NOT NULL. */
+static int lustre_posix_acl_xattr_reduce_space(posix_acl_xattr_header **header,
+ int old_count, int new_count)
+{
+ int old_size = CFS_ACL_XATTR_SIZE(old_count, posix_acl_xattr);
+ int new_size = CFS_ACL_XATTR_SIZE(new_count, posix_acl_xattr);
+ posix_acl_xattr_header *new;
+
+ if (unlikely(old_count <= new_count))
+ return old_size;
+
+ OBD_ALLOC(new, new_size);
+ if (unlikely(new == NULL))
+ return -ENOMEM;
+
+ memcpy(new, *header, new_size);
+ OBD_FREE(*header, old_size);
+ *header = new;
+ return new_size;
+}
+
+/* if "new_count == 0", then "new = {0, NULL}", NOT NULL. */
+static int lustre_ext_acl_xattr_reduce_space(ext_acl_xattr_header **header,
+ int old_count)
+{
+ int ext_count = le32_to_cpu((*header)->a_count);
+ int ext_size = CFS_ACL_XATTR_SIZE(ext_count, ext_acl_xattr);
+ int old_size = CFS_ACL_XATTR_SIZE(old_count, ext_acl_xattr);
+ ext_acl_xattr_header *new;
+
+ if (unlikely(old_count <= ext_count))
+ return 0;
+
+ OBD_ALLOC(new, ext_size);
+ if (unlikely(new == NULL))
+ return -ENOMEM;
+
+ memcpy(new, *header, ext_size);
+ OBD_FREE(*header, old_size);
+ *header = new;
+ return 0;
+}
+
+/*
+ * Generate new extended ACL based on the posix ACL.
+ */
+ext_acl_xattr_header *
+lustre_posix_acl_xattr_2ext(posix_acl_xattr_header *header, int size)
+{
+ int count, i, esize;
+ ext_acl_xattr_header *new;
+ ENTRY;
+
+ if (unlikely(size < 0))
+ RETURN(ERR_PTR(-EINVAL));
+ else if (!size)
+ count = 0;
+ else
+ count = CFS_ACL_XATTR_COUNT(size, posix_acl_xattr);
+ esize = CFS_ACL_XATTR_SIZE(count, ext_acl_xattr);
+ OBD_ALLOC(new, esize);
+ if (unlikely(new == NULL))
+ RETURN(ERR_PTR(-ENOMEM));
+
+ new->a_count = cpu_to_le32(count);
+ for (i = 0; i < count; i++) {
+ new->a_entries[i].e_tag = header->a_entries[i].e_tag;
+ new->a_entries[i].e_perm = header->a_entries[i].e_perm;
+ new->a_entries[i].e_id = header->a_entries[i].e_id;
+ new->a_entries[i].e_stat = cpu_to_le32(ES_UNK);
+ }
+
+ RETURN(new);
+}
+EXPORT_SYMBOL(lustre_posix_acl_xattr_2ext);
+
+/*
+ * Filter out the "nobody" entries in the posix ACL.
+ */
+int lustre_posix_acl_xattr_filter(posix_acl_xattr_header *header, int size,
+ posix_acl_xattr_header **out)
+{
+ int count, i, j, rc = 0;
+ __u32 id;
+ posix_acl_xattr_header *new;
+ ENTRY;
+
+ if (unlikely(size < 0))
+ RETURN(-EINVAL);
+ else if (!size)
+ RETURN(0);
+
+ OBD_ALLOC(new, size);
+ if (unlikely(new == NULL))
+ RETURN(-ENOMEM);
+
+ new->a_version = cpu_to_le32(CFS_ACL_XATTR_VERSION);
+ count = CFS_ACL_XATTR_COUNT(size, posix_acl_xattr);
+ for (i = 0, j = 0; i < count; i++) {
+ id = le32_to_cpu(header->a_entries[i].e_id);
+ switch (le16_to_cpu(header->a_entries[i].e_tag)) {
+ case ACL_USER_OBJ:
+ case ACL_GROUP_OBJ:
+ case ACL_MASK:
+ case ACL_OTHER:
+ if (id != ACL_UNDEFINED_ID)
+ GOTO(_out, rc = -EIO);
+
+ memcpy(&new->a_entries[j++], &header->a_entries[i],
+ sizeof(posix_acl_xattr_entry));
+ break;
+ case ACL_USER:
+ if (id != NOBODY_UID)
+ memcpy(&new->a_entries[j++],
+ &header->a_entries[i],
+ sizeof(posix_acl_xattr_entry));
+ break;
+ case ACL_GROUP:
+ if (id != NOBODY_GID)
+ memcpy(&new->a_entries[j++],
+ &header->a_entries[i],
+ sizeof(posix_acl_xattr_entry));
+ break;
+ default:
+ GOTO(_out, rc = -EIO);
+ }
+ }
+
+ /* free unused space. */
+ rc = lustre_posix_acl_xattr_reduce_space(&new, count, j);
+ if (rc >= 0) {
+ size = rc;
+ *out = new;
+ rc = 0;
+ }
+ EXIT;
+
+_out:
+ if (rc) {
+ OBD_FREE(new, size);
+ size = rc;
+ }
+ return size;
+}
+EXPORT_SYMBOL(lustre_posix_acl_xattr_filter);
+
+/*
+ * Convert server-side uid/gid in the posix ACL items to the client-side ones.
+ * convert rule:
+ * @CFS_IC_NOTHING
+ * nothing to be converted.
+ * @CFS_IC_ALL
+ * mapped ids are converted to client-side ones,
+ * unmapped ones are converted to "nobody".
+ * @CFS_IC_MAPPED
+ * only mapped ids are converted to "nobody".
+ * @CFS_IC_UNMAPPED
+ * only unmapped ids are converted to "nobody".
+ */
+int lustre_posix_acl_xattr_id2client(struct md_ucred *mu,
+ struct lustre_idmap_table *t,
+ posix_acl_xattr_header *header,
+ int size, int flags)
+{
+ int count, i;
+ __u32 id;
+ ENTRY;
+
+ if (unlikely(size < 0))
+ RETURN(-EINVAL);
+ else if (!size)
+ RETURN(0);
+
+ if (unlikely(flags == CFS_IC_NOTHING))
+ RETURN(0);
+
+ count = CFS_ACL_XATTR_COUNT(size, posix_acl_xattr);
+ for (i = 0; i < count; i++) {
+ id = le32_to_cpu(header->a_entries[i].e_id);
+ switch (le16_to_cpu(header->a_entries[i].e_tag)) {
+ case ACL_USER_OBJ:
+ case ACL_GROUP_OBJ:
+ case ACL_MASK:
+ case ACL_OTHER:
+ if (id != ACL_UNDEFINED_ID)
+ RETURN(-EIO);
+ break;
+ case ACL_USER:
+ id = lustre_idmap_lookup_uid(mu, t, 1, id);
+ if (flags == CFS_IC_ALL) {
+ if (id == CFS_IDMAP_NOTFOUND)
+ id = NOBODY_UID;
+ header->a_entries[i].e_id = cpu_to_le32(id);
+ } else if (flags == CFS_IC_MAPPED) {
+ if (id != CFS_IDMAP_NOTFOUND)
+ header->a_entries[i].e_id =
+ cpu_to_le32(NOBODY_UID);
+ } else if (flags == CFS_IC_UNMAPPED) {
+ if (id == CFS_IDMAP_NOTFOUND)
+ header->a_entries[i].e_id =
+ cpu_to_le32(NOBODY_UID);
+ }
+ break;
+ case ACL_GROUP:
+ id = lustre_idmap_lookup_gid(mu, t, 1, id);
+ if (flags == CFS_IC_ALL) {
+ if (id == CFS_IDMAP_NOTFOUND)
+ id = NOBODY_GID;
+ header->a_entries[i].e_id = cpu_to_le32(id);
+ } else if (flags == CFS_IC_MAPPED) {
+ if (id != CFS_IDMAP_NOTFOUND)
+ header->a_entries[i].e_id =
+ cpu_to_le32(NOBODY_GID);
+ } else if (flags == CFS_IC_UNMAPPED) {
+ if (id == CFS_IDMAP_NOTFOUND)
+ header->a_entries[i].e_id =
+ cpu_to_le32(NOBODY_GID);
+ }
+ break;
+ default:
+ RETURN(-EIO);
+ }
+ }
+ RETURN(0);
+}
+EXPORT_SYMBOL(lustre_posix_acl_xattr_id2client);
+
+/*
+ * Release the posix ACL space.
+ */
+void lustre_posix_acl_xattr_free(posix_acl_xattr_header *header, int size)
+{
+ OBD_FREE(header, size);
+}
+EXPORT_SYMBOL(lustre_posix_acl_xattr_free);
+
+/*
+ * Converts client-side uid/gid in the extended ACL items to server-side ones.
+ * convert rule:
+ * mapped ids are converted to server-side ones,
+ * unmapped ones cause "EPERM" error.
+ */
+int lustre_ext_acl_xattr_id2server(struct md_ucred *mu,
+ struct lustre_idmap_table *t,
+ ext_acl_xattr_header *header)
+
+{
+ int i, count = le32_to_cpu(header->a_count);
+ __u32 id;
+ ENTRY;
+
+ for (i = 0; i < count; i++) {
+ id = le32_to_cpu(header->a_entries[i].e_id);
+ switch (le16_to_cpu(header->a_entries[i].e_tag)) {
+ case ACL_USER_OBJ:
+ case ACL_GROUP_OBJ:
+ case ACL_MASK:
+ case ACL_OTHER:
+ if (id != ACL_UNDEFINED_ID)
+ RETURN(-EIO);
+ break;
+ case ACL_USER:
+ id = lustre_idmap_lookup_uid(mu, t, 0, id);
+ if (id == CFS_IDMAP_NOTFOUND)
+ RETURN(-EPERM);
+ else
+ header->a_entries[i].e_id = cpu_to_le32(id);
+ break;
+ case ACL_GROUP:
+ id = lustre_idmap_lookup_gid(mu, t, 0, id);
+ if (id == CFS_IDMAP_NOTFOUND)
+ RETURN(-EPERM);
+ else
+ header->a_entries[i].e_id = cpu_to_le32(id);
+ break;
+ default:
+ RETURN(-EIO);
+ }
+ }
+ RETURN(0);
+}
+EXPORT_SYMBOL(lustre_ext_acl_xattr_id2server);
+
+/*
+ * Release the extended ACL space.
+ */
+void lustre_ext_acl_xattr_free(ext_acl_xattr_header *header)
+{
+ OBD_FREE(header, CFS_ACL_XATTR_SIZE(le32_to_cpu(header->a_count), \
+ ext_acl_xattr));
+}
+EXPORT_SYMBOL(lustre_ext_acl_xattr_free);
+
+static ext_acl_xattr_entry *
+lustre_ext_acl_xattr_search(ext_acl_xattr_header *header,
+ posix_acl_xattr_entry *entry, int *pos)
+{
+ int once, start, end, i, j, count = le32_to_cpu(header->a_count);
+
+ once = 0;
+ start = *pos;
+ end = count;
+
+again:
+ for (i = start; i < end; i++) {
+ if (header->a_entries[i].e_tag == entry->e_tag &&
+ header->a_entries[i].e_id == entry->e_id) {
+ j = i;
+ if (++i >= count)
+ i = 0;
+ *pos = i;
+ return &header->a_entries[j];
+ }
+ }
+
+ if (!once) {
+ once = 1;
+ start = 0;
+ end = *pos;
+ goto again;
+ }
+
+ return NULL;
+}
+
+/*
+ * Merge the posix ACL and the extended ACL into new posix ACL.
+ */
+int lustre_acl_xattr_merge2posix(posix_acl_xattr_header *posix_header, int size,
+ ext_acl_xattr_header *ext_header,
+ posix_acl_xattr_header **out)
+{
+ int posix_count, posix_size, i, j;
+ int ext_count = le32_to_cpu(ext_header->a_count), pos = 0, rc = 0;
+ posix_acl_xattr_entry pe = {ACL_MASK, 0, ACL_UNDEFINED_ID};
+ posix_acl_xattr_header *new;
+ ext_acl_xattr_entry *ee, ae;
+ ENTRY;
+
+ lustre_posix_acl_cpu_to_le(&pe, &pe);
+ ee = lustre_ext_acl_xattr_search(ext_header, &pe, &pos);
+ if (ee == NULL || le32_to_cpu(ee->e_stat) == ES_DEL) {
+ /* there are only base ACL entries at most. */
+ posix_count = 3;
+ posix_size = CFS_ACL_XATTR_SIZE(posix_count, posix_acl_xattr);
+ OBD_ALLOC(new, posix_size);
+ if (unlikely(new == NULL))
+ RETURN(-ENOMEM);
+
+ new->a_version = cpu_to_le32(CFS_ACL_XATTR_VERSION);
+ for (i = 0, j = 0; i < ext_count; i++) {
+ lustre_ext_acl_le_to_cpu(&ae,
+ &ext_header->a_entries[i]);
+ switch (ae.e_tag) {
+ case ACL_USER_OBJ:
+ case ACL_GROUP_OBJ:
+ case ACL_OTHER:
+ if (ae.e_id != ACL_UNDEFINED_ID)
+ GOTO(_out, rc = -EIO);
+
+ if (ae.e_stat != ES_DEL) {
+ new->a_entries[j].e_tag =
+ ext_header->a_entries[i].e_tag;
+ new->a_entries[j].e_perm =
+ ext_header->a_entries[i].e_perm;
+ new->a_entries[j++].e_id =
+ ext_header->a_entries[i].e_id;
+ }
+ break;
+ case ACL_MASK:
+ case ACL_USER:
+ case ACL_GROUP:
+ if (ae.e_stat == ES_DEL)
+ break;
+ default:
+ GOTO(_out, rc = -EIO);
+ }
+ }
+ } else {
+ /* maybe there are valid ACL_USER or ACL_GROUP entries in the
+ * original server-side ACL, they are regarded as ES_UNC stat.*/
+ int ori_posix_count;
+
+ if (unlikely(size < 0))
+ RETURN(-EINVAL);
+ else if (!size)
+ ori_posix_count = 0;
+ else
+ ori_posix_count =
+ CFS_ACL_XATTR_COUNT(size, posix_acl_xattr);
+ posix_count = ori_posix_count + ext_count;
+ posix_size =
+ CFS_ACL_XATTR_SIZE(posix_count, posix_acl_xattr);
+ OBD_ALLOC(new, posix_size);
+ if (unlikely(new == NULL))
+ RETURN(-ENOMEM);
+
+ new->a_version = cpu_to_le32(CFS_ACL_XATTR_VERSION);
+ /* 1. process the unchanged ACL entries
+ * in the original server-side ACL. */
+ pos = 0;
+ for (i = 0, j = 0; i < ori_posix_count; i++) {
+ ee = lustre_ext_acl_xattr_search(ext_header,
+ &posix_header->a_entries[i], &pos);
+ if (ee == NULL)
+ memcpy(&new->a_entries[j++],
+ &posix_header->a_entries[i],
+ sizeof(posix_acl_xattr_entry));
+ }
+
+ /* 2. process the non-deleted entries
+ * from client-side extended ACL. */
+ for (i = 0; i < ext_count; i++) {
+ if (le16_to_cpu(ext_header->a_entries[i].e_stat) !=
+ ES_DEL) {
+ new->a_entries[j].e_tag =
+ ext_header->a_entries[i].e_tag;
+ new->a_entries[j].e_perm =
+ ext_header->a_entries[i].e_perm;
+ new->a_entries[j++].e_id =
+ ext_header->a_entries[i].e_id;
+ }
+ }
+ }
+
+ /* free unused space. */
+ rc = lustre_posix_acl_xattr_reduce_space(&new, posix_count, j);
+ if (rc >= 0) {
+ posix_size = rc;
+ *out = new;
+ rc = 0;
+ }
+ EXIT;
+
+_out:
+ if (rc) {
+ OBD_FREE(new, posix_size);
+ posix_size = rc;
+ }
+ return posix_size;
+}
+EXPORT_SYMBOL(lustre_acl_xattr_merge2posix);
+
+/*
+ * Merge the posix ACL and the extended ACL into new extended ACL.
+ */
+ext_acl_xattr_header *
+lustre_acl_xattr_merge2ext(posix_acl_xattr_header *posix_header, int size,
+ ext_acl_xattr_header *ext_header)
+{
+ int ori_ext_count, posix_count, ext_count, ext_size;
+ int i, j, pos = 0, rc = 0;
+ posix_acl_xattr_entry pae;
+ ext_acl_xattr_header *new;
+ ext_acl_xattr_entry *ee, eae;
+ ENTRY;
+
+ if (unlikely(size < 0))
+ RETURN(ERR_PTR(-EINVAL));
+ else if (!size)
+ posix_count = 0;
+ else
+ posix_count = CFS_ACL_XATTR_COUNT(size, posix_acl_xattr);
+ ori_ext_count = le32_to_cpu(ext_header->a_count);
+ ext_count = posix_count + ori_ext_count;
+ ext_size = CFS_ACL_XATTR_SIZE(ext_count, ext_acl_xattr);
+
+ OBD_ALLOC(new, ext_size);
+ if (unlikely(new == NULL))
+ RETURN(ERR_PTR(-ENOMEM));
+
+ for (i = 0, j = 0; i < posix_count; i++) {
+ lustre_posix_acl_le_to_cpu(&pae, &posix_header->a_entries[i]);
+ switch (pae.e_tag) {
+ case ACL_USER_OBJ:
+ case ACL_GROUP_OBJ:
+ case ACL_MASK:
+ case ACL_OTHER:
+ if (pae.e_id != ACL_UNDEFINED_ID)
+ GOTO(out, rc = -EIO);
+ case ACL_USER:
+ /* ignore "nobody" entry. */
+ if (pae.e_id == NOBODY_UID)
+ break;
+
+ new->a_entries[j].e_tag =
+ posix_header->a_entries[i].e_tag;
+ new->a_entries[j].e_perm =
+ posix_header->a_entries[i].e_perm;
+ new->a_entries[j].e_id =
+ posix_header->a_entries[i].e_id;
+ ee = lustre_ext_acl_xattr_search(ext_header,
+ &posix_header->a_entries[i], &pos);
+ if (ee) {
+ if (posix_header->a_entries[i].e_perm !=
+ ee->e_perm)
+ /* entry modified. */
+ ee->e_perm =
+ new->a_entries[j++].e_stat =
+ cpu_to_le32(ES_MOD);
+ else
+ /* entry unchanged. */
+ ee->e_perm =
+ new->a_entries[j++].e_stat =
+ cpu_to_le32(ES_UNC);
+ } else {
+ /* new entry. */
+ new->a_entries[j++].e_stat =
+ cpu_to_le32(ES_ADD);
+ }
+ break;
+ case ACL_GROUP:
+ /* ignore "nobody" entry. */
+ if (pae.e_id == NOBODY_GID)
+ break;
+ new->a_entries[j].e_tag =
+ posix_header->a_entries[i].e_tag;
+ new->a_entries[j].e_perm =
+ posix_header->a_entries[i].e_perm;
+ new->a_entries[j].e_id =
+ posix_header->a_entries[i].e_id;
+ ee = lustre_ext_acl_xattr_search(ext_header,
+ &posix_header->a_entries[i], &pos);
+ if (ee) {
+ if (posix_header->a_entries[i].e_perm !=
+ ee->e_perm)
+ /* entry modified. */
+ ee->e_perm =
+ new->a_entries[j++].e_stat =
+ cpu_to_le32(ES_MOD);
+ else
+ /* entry unchanged. */
+ ee->e_perm =
+ new->a_entries[j++].e_stat =
+ cpu_to_le32(ES_UNC);
+ } else {
+ /* new entry. */
+ new->a_entries[j++].e_stat =
+ cpu_to_le32(ES_ADD);
+ }
+ break;
+ default:
+ GOTO(out, rc = -EIO);
+ }
+ }
+
+ /* process deleted entries. */
+ for (i = 0; i < ori_ext_count; i++) {
+ lustre_ext_acl_le_to_cpu(&eae, &ext_header->a_entries[i]);
+ if (eae.e_stat == ES_UNK) {
+ /* ignore "nobody" entry. */
+ if ((eae.e_tag == ACL_USER && eae.e_id == NOBODY_UID) ||
+ (eae.e_tag == ACL_GROUP && eae.e_id == NOBODY_GID))
+ continue;
+
+ new->a_entries[j].e_tag =
+ ext_header->a_entries[i].e_tag;
+ new->a_entries[j].e_perm =
+ ext_header->a_entries[i].e_perm;
+ new->a_entries[j].e_id = ext_header->a_entries[i].e_id;
+ new->a_entries[j++].e_stat = cpu_to_le32(ES_DEL);
+ }
+ }
+
+ new->a_count = cpu_to_le32(j);
+ /* free unused space. */
+ rc = lustre_ext_acl_xattr_reduce_space(&new, ext_count);
+ EXIT;
+
+out:
+ if (rc) {
+ OBD_FREE(new, ext_size);
+ new = ERR_PTR(rc);
+ }
+ return new;
+}
+EXPORT_SYMBOL(lustre_acl_xattr_merge2ext);
+
+#endif
INIT_HLIST_NODE(&export->exp_uuid_hash);
INIT_HLIST_NODE(&export->exp_nid_hash);
+ export->exp_sp_peer = LUSTRE_SP_ANY;
+ export->exp_flvr.sf_rpc = SPTLRPC_FLVR_INVALID;
export->exp_client_uuid = *cluuid;
obd_init_export(export);
imp->imp_last_success_conn = 0;
imp->imp_state = LUSTRE_IMP_NEW;
imp->imp_obd = class_incref(obd);
+ sema_init(&imp->imp_sec_mutex, 1);
cfs_waitq_init(&imp->imp_recovery_waitq);
atomic_set(&imp->imp_refcount, 2);
--- /dev/null
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ * lustre/obdclass/idmap.c
+ * Lustre user identity mapping.
+ * Author: Fan Yong <fanyong@clusterfs.com>
+ *
+ * Copyright (C) 2004-2007 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.
+ */
+
+#ifndef EXPORT_SYMTAB
+# define EXPORT_SYMTAB
+#endif
+
+#define DEBUG_SUBSYSTEM S_SEC
+
+#include <lustre_idmap.h>
+#include <obd_support.h>
+
+#define lustre_get_group_info(group_info) do { \
+ atomic_inc(&(group_info)->usage); \
+} while (0)
+
+#define lustre_put_group_info(group_info) do { \
+ if (atomic_dec_and_test(&(group_info)->usage)) \
+ groups_free(group_info); \
+} while (0)
+
+/*
+ * groups_search() is copied from linux kernel!
+ * A simple bsearch.
+ */
+static int lustre_groups_search(struct group_info *group_info, gid_t grp)
+{
+ int left, right;
+
+ if (!group_info)
+ return 0;
+
+ left = 0;
+ right = group_info->ngroups;
+ while (left < right) {
+ int mid = (left + right) / 2;
+ int cmp = grp - CFS_GROUP_AT(group_info, mid);
+
+ if (cmp > 0)
+ left = mid + 1;
+ else if (cmp < 0)
+ right = mid;
+ else
+ return 1;
+ }
+ return 0;
+}
+
+void lustre_groups_from_list(struct group_info *ginfo, gid_t *glist)
+{
+ int i;
+ int count = ginfo->ngroups;
+
+ /* fill group_info from gid array */
+ for (i = 0; i < ginfo->nblocks && count > 0; i++) {
+ int cp_count = min(CFS_NGROUPS_PER_BLOCK, count);
+ int off = i * CFS_NGROUPS_PER_BLOCK;
+ int len = cp_count * sizeof(*glist);
+
+ memcpy(ginfo->blocks[i], glist + off, len);
+ count -= cp_count;
+ }
+}
+EXPORT_SYMBOL(lustre_groups_from_list);
+
+/* groups_sort() is copied from linux kernel! */
+/* a simple shell-metzner sort */
+void lustre_groups_sort(struct group_info *group_info)
+{
+ int base, max, stride;
+ int gidsetsize = group_info->ngroups;
+
+ for (stride = 1; stride < gidsetsize; stride = 3 * stride + 1)
+ ; /* nothing */
+ stride /= 3;
+
+ while (stride) {
+ max = gidsetsize - stride;
+ for (base = 0; base < max; base++) {
+ int left = base;
+ int right = left + stride;
+ gid_t tmp = CFS_GROUP_AT(group_info, right);
+
+ while (left >= 0 &&
+ CFS_GROUP_AT(group_info, left) > tmp) {
+ CFS_GROUP_AT(group_info, right) =
+ CFS_GROUP_AT(group_info, left);
+ right = left;
+ left -= stride;
+ }
+ CFS_GROUP_AT(group_info, right) = tmp;
+ }
+ stride /= 3;
+ }
+}
+EXPORT_SYMBOL(lustre_groups_sort);
+
+int lustre_in_group_p(struct md_ucred *mu, gid_t grp)
+{
+ int rc = 1;
+
+ if (grp != mu->mu_fsgid) {
+ struct group_info *group_info = NULL;
+
+ if (mu->mu_ginfo || !mu->mu_identity ||
+ mu->mu_valid == UCRED_OLD)
+ if (grp == mu->mu_suppgids[0] ||
+ grp == mu->mu_suppgids[1])
+ return 1;
+
+ if (mu->mu_ginfo)
+ group_info = mu->mu_ginfo;
+ else if (mu->mu_identity)
+ group_info = mu->mu_identity->mi_ginfo;
+
+ if (!group_info)
+ return 0;
+
+ lustre_get_group_info(group_info);
+ rc = lustre_groups_search(group_info, grp);
+ lustre_put_group_info(group_info);
+ }
+ return rc;
+}
+EXPORT_SYMBOL(lustre_in_group_p);
+
+struct lustre_idmap_entry {
+ struct list_head lie_rmt_uid_hash; /* hashed as lie_rmt_uid; */
+ struct list_head lie_lcl_uid_hash; /* hashed as lie_lcl_uid; */
+ struct list_head lie_rmt_gid_hash; /* hashed as lie_rmt_gid; */
+ struct list_head lie_lcl_gid_hash; /* hashed as lie_lcl_gid; */
+ uid_t lie_rmt_uid; /* remote uid */
+ uid_t lie_lcl_uid; /* local uid */
+ gid_t lie_rmt_gid; /* remote gid */
+ gid_t lie_lcl_gid; /* local gid */
+};
+
+static inline __u32 lustre_idmap_hashfunc(__u32 id)
+{
+ return id & (CFS_IDMAP_HASHSIZE - 1);
+}
+
+static
+struct lustre_idmap_entry *idmap_entry_alloc(uid_t rmt_uid, uid_t lcl_uid,
+ gid_t rmt_gid, gid_t lcl_gid)
+{
+ struct lustre_idmap_entry *e;
+
+ OBD_ALLOC_PTR(e);
+ if (e == NULL)
+ return NULL;
+
+ INIT_LIST_HEAD(&e->lie_rmt_uid_hash);
+ INIT_LIST_HEAD(&e->lie_lcl_uid_hash);
+ INIT_LIST_HEAD(&e->lie_rmt_gid_hash);
+ INIT_LIST_HEAD(&e->lie_lcl_gid_hash);
+ e->lie_rmt_uid = rmt_uid;
+ e->lie_lcl_uid = lcl_uid;
+ e->lie_rmt_gid = rmt_gid;
+ e->lie_lcl_gid = lcl_gid;
+
+ return e;
+}
+
+static void idmap_entry_free(struct lustre_idmap_entry *e)
+{
+ if (!list_empty(&e->lie_rmt_uid_hash))
+ list_del(&e->lie_rmt_uid_hash);
+ if (!list_empty(&e->lie_lcl_uid_hash))
+ list_del(&e->lie_lcl_uid_hash);
+ if (!list_empty(&e->lie_rmt_gid_hash))
+ list_del(&e->lie_rmt_gid_hash);
+ if (!list_empty(&e->lie_lcl_gid_hash))
+ list_del(&e->lie_lcl_gid_hash);
+ OBD_FREE_PTR(e);
+}
+
+/*
+ * return value
+ * NULL: not found entry
+ * ERR_PTR(-EACCES): found 1(remote):N(local) mapped entry
+ * others: found normal entry
+ */
+static
+struct lustre_idmap_entry *idmap_search_entry(struct lustre_idmap_table *t,
+ uid_t rmt_uid, uid_t lcl_uid,
+ gid_t rmt_gid, gid_t lcl_gid)
+{
+ struct list_head *head;
+ struct lustre_idmap_entry *e;
+
+ head = &t->lit_idmaps[RMT_UIDMAP_IDX][lustre_idmap_hashfunc(rmt_uid)];
+ list_for_each_entry(e, head, lie_rmt_uid_hash)
+ if (e->lie_rmt_uid == rmt_uid) {
+ if (e->lie_lcl_uid == lcl_uid) {
+ if (e->lie_rmt_gid == rmt_gid &&
+ e->lie_lcl_gid == lcl_gid)
+ /* must be quaternion match */
+ return e;
+ } else {
+ /* 1:N uid mapping */
+ CERROR("rmt uid %u already be mapped to %u"
+ " (new %u)\n", e->lie_rmt_uid,
+ e->lie_lcl_uid, lcl_uid);
+ return ERR_PTR(-EACCES);
+ }
+ }
+
+ head = &t->lit_idmaps[RMT_GIDMAP_IDX][lustre_idmap_hashfunc(rmt_gid)];
+ list_for_each_entry(e, head, lie_rmt_gid_hash)
+ if (e->lie_rmt_gid == rmt_gid) {
+ if (e->lie_lcl_gid == lcl_gid) {
+ if (unlikely(e->lie_rmt_uid == rmt_uid &&
+ e->lie_lcl_uid == lcl_uid))
+ /* after uid mapping search above,
+ * we should never come here */
+ LBUG();
+ } else {
+ /* 1:N gid mapping */
+ CERROR("rmt gid %u already be mapped to %u"
+ " (new %u)\n", e->lie_rmt_gid,
+ e->lie_lcl_gid, lcl_gid);
+ return ERR_PTR(-EACCES);
+ }
+ }
+
+ return NULL;
+}
+
+static __u32 idmap_lookup_uid(struct list_head *hash, int reverse, __u32 uid)
+{
+ struct list_head *head = &hash[lustre_idmap_hashfunc(uid)];
+ struct lustre_idmap_entry *e;
+
+ if (!reverse) {
+ list_for_each_entry(e, head, lie_rmt_uid_hash)
+ if (e->lie_rmt_uid == uid)
+ return e->lie_lcl_uid;
+ } else {
+ list_for_each_entry(e, head, lie_lcl_uid_hash)
+ if (e->lie_lcl_uid == uid)
+ return e->lie_rmt_uid;
+ }
+
+ return CFS_IDMAP_NOTFOUND;
+}
+
+static __u32 idmap_lookup_gid(struct list_head *hash, int reverse, __u32 gid)
+{
+ struct list_head *head = &hash[lustre_idmap_hashfunc(gid)];
+ struct lustre_idmap_entry *e;
+
+ if (!reverse) {
+ list_for_each_entry(e, head, lie_rmt_gid_hash)
+ if (e->lie_rmt_gid == gid)
+ return e->lie_lcl_gid;
+ } else {
+ list_for_each_entry(e, head, lie_lcl_gid_hash)
+ if (e->lie_lcl_gid == gid)
+ return e->lie_rmt_gid;
+ }
+
+ return CFS_IDMAP_NOTFOUND;
+}
+
+int lustre_idmap_add(struct lustre_idmap_table *t,
+ uid_t ruid, uid_t luid,
+ gid_t rgid, gid_t lgid)
+{
+ struct lustre_idmap_entry *e0, *e1;
+
+ LASSERT(t);
+
+ spin_lock(&t->lit_lock);
+ e0 = idmap_search_entry(t, ruid, luid, rgid, lgid);
+ spin_unlock(&t->lit_lock);
+ if (!e0) {
+ e0 = idmap_entry_alloc(ruid, luid, rgid, lgid);
+ if (!e0)
+ return -ENOMEM;
+
+ spin_lock(&t->lit_lock);
+ e1 = idmap_search_entry(t, ruid, luid, rgid, lgid);
+ if (e1 == NULL) {
+ list_add_tail(&e0->lie_rmt_uid_hash,
+ &t->lit_idmaps[RMT_UIDMAP_IDX]
+ [lustre_idmap_hashfunc(ruid)]);
+ list_add_tail(&e0->lie_lcl_uid_hash,
+ &t->lit_idmaps[LCL_UIDMAP_IDX]
+ [lustre_idmap_hashfunc(luid)]);
+ list_add_tail(&e0->lie_rmt_gid_hash,
+ &t->lit_idmaps[RMT_GIDMAP_IDX]
+ [lustre_idmap_hashfunc(rgid)]);
+ list_add_tail(&e0->lie_lcl_gid_hash,
+ &t->lit_idmaps[LCL_GIDMAP_IDX]
+ [lustre_idmap_hashfunc(lgid)]);
+ }
+ spin_unlock(&t->lit_lock);
+ if (e1 != NULL) {
+ idmap_entry_free(e0);
+ if (IS_ERR(e1))
+ return PTR_ERR(e1);
+ }
+ } else if (IS_ERR(e0)) {
+ return PTR_ERR(e0);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(lustre_idmap_add);
+
+int lustre_idmap_del(struct lustre_idmap_table *t,
+ uid_t ruid, uid_t luid,
+ gid_t rgid, gid_t lgid)
+{
+ struct lustre_idmap_entry *e;
+ int rc = 0;
+
+ LASSERT(t);
+
+ spin_lock(&t->lit_lock);
+ e = idmap_search_entry(t, ruid, luid, rgid, lgid);
+ if (IS_ERR(e))
+ rc = PTR_ERR(e);
+ else if (e)
+ idmap_entry_free(e);
+ spin_unlock(&t->lit_lock);
+
+ return rc;
+}
+EXPORT_SYMBOL(lustre_idmap_del);
+
+int lustre_idmap_lookup_uid(struct md_ucred *mu,
+ struct lustre_idmap_table *t,
+ int reverse, uid_t uid)
+{
+ struct list_head *hash;
+
+ if (mu && (mu->mu_valid == UCRED_OLD || mu->mu_valid == UCRED_NEW)) {
+ if (!reverse) {
+ if (uid == mu->mu_o_uid)
+ return mu->mu_uid;
+ else if (uid == mu->mu_o_fsuid)
+ return mu->mu_fsuid;
+ } else {
+ if (uid == mu->mu_uid)
+ return mu->mu_o_uid;
+ else if (uid == mu->mu_fsuid)
+ return mu->mu_o_fsuid;
+ }
+ }
+
+ if (t == NULL)
+ return CFS_IDMAP_NOTFOUND;
+
+ hash = t->lit_idmaps[reverse ? LCL_UIDMAP_IDX : RMT_UIDMAP_IDX];
+
+ spin_lock(&t->lit_lock);
+ uid = idmap_lookup_uid(hash, reverse, uid);
+ spin_unlock(&t->lit_lock);
+
+ return uid;
+}
+EXPORT_SYMBOL(lustre_idmap_lookup_uid);
+
+int lustre_idmap_lookup_gid(struct md_ucred *mu, struct lustre_idmap_table *t,
+ int reverse, gid_t gid)
+{
+ struct list_head *hash;
+
+ if (mu && (mu->mu_valid == UCRED_OLD || mu->mu_valid == UCRED_NEW)) {
+ if (!reverse) {
+ if (gid == mu->mu_o_gid)
+ return mu->mu_gid;
+ else if (gid == mu->mu_o_fsgid)
+ return mu->mu_fsgid;
+ } else {
+ if (gid == mu->mu_gid)
+ return mu->mu_o_gid;
+ else if (gid == mu->mu_fsgid)
+ return mu->mu_o_fsgid;
+ }
+ }
+
+ if (t == NULL)
+ return CFS_IDMAP_NOTFOUND;
+
+ hash = t->lit_idmaps[reverse ? LCL_GIDMAP_IDX : RMT_GIDMAP_IDX];
+
+ spin_lock(&t->lit_lock);
+ gid = idmap_lookup_gid(hash, reverse, gid);
+ spin_unlock(&t->lit_lock);
+
+ return gid;
+}
+EXPORT_SYMBOL(lustre_idmap_lookup_gid);
+
+struct lustre_idmap_table *lustre_idmap_init(void)
+{
+ struct lustre_idmap_table *t;
+ int i, j;
+
+ OBD_ALLOC_PTR(t);
+ if(unlikely(t == NULL))
+ return (ERR_PTR(-ENOMEM));
+
+ spin_lock_init(&t->lit_lock);
+ for (i = 0; i < ARRAY_SIZE(t->lit_idmaps); i++)
+ for (j = 0; j < ARRAY_SIZE(t->lit_idmaps[i]); j++)
+ INIT_LIST_HEAD(&t->lit_idmaps[i][j]);
+
+ return t;
+}
+EXPORT_SYMBOL(lustre_idmap_init);
+
+void lustre_idmap_fini(struct lustre_idmap_table *t)
+{
+ struct list_head *list;
+ struct lustre_idmap_entry *e;
+ int i;
+ LASSERT(t);
+
+ list = t->lit_idmaps[RMT_UIDMAP_IDX];
+ spin_lock(&t->lit_lock);
+ for (i = 0; i < CFS_IDMAP_HASHSIZE; i++)
+ while (!list_empty(&list[i])) {
+ e = list_entry(list[i].next, struct lustre_idmap_entry,
+ lie_rmt_uid_hash);
+ idmap_entry_free(e);
+ }
+ spin_unlock(&t->lit_lock);
+
+ OBD_FREE_PTR(t);
+}
+EXPORT_SYMBOL(lustre_idmap_fini);
RETURN(rc);
}
-int class_sec_flavor(struct obd_device *obd, struct lustre_cfg *lcfg)
-{
- struct sec_flavor_config *conf;
- ENTRY;
-
- if (strcmp(obd->obd_type->typ_name, LUSTRE_MDC_NAME) &&
- strcmp(obd->obd_type->typ_name, LUSTRE_OSC_NAME)) {
- CERROR("Can't set security flavor on obd %s\n",
- obd->obd_type->typ_name);
- RETURN(-EINVAL);
- }
-
- if (LUSTRE_CFG_BUFLEN(lcfg, 1) != sizeof(*conf)) {
- CERROR("invalid data\n");
- RETURN(-EINVAL);
- }
-
- conf = &obd->u.cli.cl_sec_conf;
- memcpy(conf, lustre_cfg_buf(lcfg, 1), sizeof(*conf));
-
-#ifdef __BIG_ENDIAN
- __swab32s(&conf->sfc_rpc_flavor);
- __swab32s(&conf->sfc_bulk_csum);
- __swab32s(&conf->sfc_bulk_priv);
- __swab32s(&conf->sfc_flags);
-#endif
-
- RETURN(0);
-}
-
CFS_LIST_HEAD(lustre_profile_list);
struct lustre_profile *class_get_profile(const char * prof)
err = class_del_conn(obd, lcfg);
GOTO(out, err = 0);
}
- case LCFG_SEC_FLAVOR: {
- err = class_sec_flavor(obd, lcfg);
- GOTO(out, err = 0);
- }
default: {
err = obd_process_config(obd, sizeof(*lcfg), lcfg);
GOTO(out, err);
return(0);
}
-static
-int mti_set_sec_opts(struct mgs_target_info *mti, struct lustre_mount_data *lmd)
-{
- char *s1, *s2;
-
- if (lmd->lmd_sec_mdt == NULL && lmd->lmd_sec_cli == NULL) {
- /* just let on-disk params do its work. but we have an
- * assumption that any changes of on-disk data by tune2fs
- * should lead to server rewrite log.
- */
- return 0;
- }
-
- /* filter out existing sec options */
- s1 = mti->mti_params;
- while (*s1) {
- int clear;
-
- while (*s1 == ' ')
- s1++;
-
- if (strncmp(s1, PARAM_SEC_RPC_MDT,
- sizeof(PARAM_SEC_RPC_MDT) - 1) == 0 ||
- strncmp(s1, PARAM_SEC_RPC_CLI,
- sizeof(PARAM_SEC_RPC_CLI) - 1) == 0)
- clear = 1;
- else
- clear = 0;
-
- s2 = strchr(s1, ' ');
- if (s2 == NULL) {
- if (clear)
- *s1 = '\0';
- break;
- }
- s2++;
- if (clear)
- memmove(s1, s2, strlen(s2) + 1);
- else
- s1 = s2;
- }
-
- /* append sec options from lmd */
- /* FIXME add flag LDD_F_UPDATE after mountconf start supporting
- * log updating.
- */
- if (lmd->lmd_sec_mdt) {
- if (strlen(mti->mti_params) + strlen(lmd->lmd_sec_mdt) +
- sizeof(PARAM_SEC_RPC_MDT) + 1 >= sizeof(mti->mti_params)) {
- CERROR("security params too big for mti\n");
- return -ENOMEM;
- }
- strcat(mti->mti_params, " "PARAM_SEC_RPC_MDT);
- strcat(mti->mti_params, lmd->lmd_sec_mdt);
- //mti->mti_flags |= LDD_F_UPDATE;
- }
- if (lmd->lmd_sec_cli) {
- if (strlen(mti->mti_params) + strlen(lmd->lmd_sec_cli) +
- sizeof(PARAM_SEC_RPC_CLI) + 2 > sizeof(mti->mti_params)) {
- CERROR("security params too big for mti\n");
- return -ENOMEM;
- }
- strcat(mti->mti_params, " "PARAM_SEC_RPC_CLI);
- strcat(mti->mti_params, lmd->lmd_sec_cli);
- //mti->mti_flags |= LDD_F_UPDATE;
- }
-
- return 0;
-}
-
static int server_sb2mti(struct super_block *sb, struct mgs_target_info *mti)
{
struct lustre_sb_info *lsi = s2lsi(sb);
struct lustre_disk_data *ldd = lsi->lsi_ldd;
- struct lustre_mount_data *lmd = lsi->lsi_lmd;
lnet_process_id_t id;
int i = 0;
ENTRY;
RETURN(-ENOMEM);
}
memcpy(mti->mti_params, ldd->ldd_params, sizeof(mti->mti_params));
-
- RETURN(mti_set_sec_opts(mti, lmd));
+ RETURN(0);
}
/* Register an old or new target with the MGS. If needed MGS will construct
/* Default umount style */
lsi->lsi_flags = LSI_UMOUNT_FAILOVER;
- lsi->lsi_lmd->lmd_nllu = NOBODY_UID;
- lsi->lsi_lmd->lmd_nllg = NOBODY_GID;
RETURN(lsi);
}
if (lsi->lsi_lmd->lmd_profile != NULL)
OBD_FREE(lsi->lsi_lmd->lmd_profile,
strlen(lsi->lsi_lmd->lmd_profile) + 1);
- if (lsi->lsi_lmd->lmd_sec_mdt != NULL)
- OBD_FREE(lsi->lsi_lmd->lmd_sec_mdt,
- strlen(lsi->lsi_lmd->lmd_sec_mdt) + 1);
- if (lsi->lsi_lmd->lmd_sec_cli != NULL)
- OBD_FREE(lsi->lsi_lmd->lmd_sec_cli,
- strlen(lsi->lsi_lmd->lmd_sec_cli) + 1);
if (lsi->lsi_lmd->lmd_opts != NULL)
OBD_FREE(lsi->lsi_lmd->lmd_opts,
strlen(lsi->lsi_lmd->lmd_opts) + 1);
PRINT_CMD(PRINT_MASK, "profile: %s\n", lmd->lmd_profile);
PRINT_CMD(PRINT_MASK, "device: %s\n", lmd->lmd_dev);
PRINT_CMD(PRINT_MASK, "flags: %x\n", lmd->lmd_flags);
- if (lmd->lmd_sec_mdt)
- PRINT_CMD(PRINT_MASK, "sec_mdt: %s\n", lmd->lmd_sec_mdt);
- if (lmd->lmd_sec_cli)
- PRINT_CMD(PRINT_MASK, "sec_cli: %s\n", lmd->lmd_sec_cli);
if (lmd->lmd_opts)
PRINT_CMD(PRINT_MASK, "options: %s\n", lmd->lmd_opts);
for (i = 0; i < lmd->lmd_exclude_count; i++) {
RETURN(rc);
}
-static
-int lmd_set_sec_opts(char **set, char *opts, int length)
-{
- if (*set)
- OBD_FREE(*set, strlen(*set) + 1);
-
- OBD_ALLOC(*set, length + 1);
- if (*set == NULL)
- return -ENOMEM;
-
- memcpy(*set, opts, length);
- (*set)[length] = '\0';
-
- return 0;
-}
-
-static
-int lmd_parse_sec_opts(struct lustre_mount_data *lmd, char *ptr)
-{
- char *tail;
- char **set = NULL;
- int length;
-
- /* check peer name */
- if (strncmp(ptr, "sec_mdt=", 8) == 0) {
- set = &lmd->lmd_sec_mdt;
- ptr += 8;
- } else if (strncmp(ptr, "sec_cli=", 8) == 0) {
- set = &lmd->lmd_sec_cli;
- ptr += 8;
- } else if (strncmp(ptr, "sec=", 4) == 0) {
- /* leave 'set' be null */
- ptr += 4;
- } else {
- CERROR("invalid security options: %s\n", ptr);
- return -EINVAL;
- }
-
- tail = strchr(ptr, ',');
- if (tail == NULL)
- length = strlen(ptr);
- else
- length = tail - ptr;
-
- if (set) {
- if (lmd_set_sec_opts(set, ptr, length))
- return -EINVAL;
- } else {
- if (lmd->lmd_sec_mdt == NULL &&
- lmd_set_sec_opts(&lmd->lmd_sec_mdt, ptr, length))
- return -EINVAL;
-
- if (lmd->lmd_sec_cli == NULL &&
- lmd_set_sec_opts(&lmd->lmd_sec_cli, ptr, length))
- return -EINVAL;
- }
-
- return 0;
-}
-
/* mount -v -t lustre uml1:uml2:/lustre-client /mnt/lustre */
static int lmd_parse(char *options, struct lustre_mount_data *lmd)
{
if (rc)
goto invalid;
clear++;
- } else if (strncmp(s1, "nllu=", 5) == 0) {
- lmd->lmd_nllu = simple_strtoul(s1 + 5, NULL, 10);
- clear++;
- } else if (strncmp(s1, "nllg=", 5) == 0) {
- lmd->lmd_nllg = simple_strtoul(s1 + 5, NULL, 10);
- clear++;
- } else if (strncmp(s1, "sec", 3) == 0) {
- rc = lmd_parse_sec_opts(lmd, s1);
- if (rc)
- goto invalid;
- clear++;
}
/* Linux 2.4 doesn't pass the device, so we stuck it at the
end of the options. */
INIT_LIST_HEAD(&filter->fo_llog_list);
spin_lock_init(&filter->fo_llog_list_lock);
+ filter->fo_sptlrpc_lock = RW_LOCK_UNLOCKED;
+ sptlrpc_rule_set_init(&filter->fo_sptlrpc_rset);
+
filter->fo_fl_oss_capa = 0;
INIT_LIST_HEAD(&filter->fo_capa_keys);
filter->fo_capa_hash = init_capa_hash();
ldlm_namespace_free(obd->obd_namespace, obd->obd_force);
+ sptlrpc_rule_set_free(&filter->fo_sptlrpc_rset);
+
if (obd->u.obt.obt_sb == NULL)
RETURN(0);
RETURN(0);
}
-static int filter_reconnect(struct obd_export *exp, struct obd_device *obd,
+static int filter_reconnect(const struct lu_env *env,
+ struct obd_export *exp, struct obd_device *obd,
struct obd_uuid *cluuid,
struct obd_connect_data *data)
{
struct lprocfs_static_vars lvars;
int rc = 0;
- lprocfs_filter_init_vars(&lvars);
+ switch (lcfg->lcfg_command) {
+ case LCFG_SPTLRPC_CONF: {
+ struct filter_obd *filter = &obd->u.filter;
+ struct sptlrpc_conf_log *log;
+ struct sptlrpc_rule_set tmp_rset;
+
+ log = sptlrpc_conf_log_extract(lcfg);
+ if (IS_ERR(log)) {
+ rc = PTR_ERR(log);
+ break;
+ }
+
+ sptlrpc_rule_set_init(&tmp_rset);
+
+ rc = sptlrpc_rule_set_from_log(&tmp_rset, log);
+ if (rc) {
+ CERROR("obd %s: failed get sptlrpc rules: %d\n",
+ obd->obd_name, rc);
+ break;
+ }
+
+ write_lock(&filter->fo_sptlrpc_lock);
+ sptlrpc_rule_set_free(&filter->fo_sptlrpc_rset);
+ filter->fo_sptlrpc_rset = tmp_rset;
+ write_unlock(&filter->fo_sptlrpc_lock);
+
+ sptlrpc_target_update_exp_flavor(obd, &tmp_rset);
+ break;
+ }
+ default:
+ lprocfs_filter_init_vars(&lvars);
+
+ rc = class_process_proc_param(PARAM_OST, lvars.obd_vars,
+ lcfg, obd);
+ break;
+ }
- rc = class_process_proc_param(PARAM_OST, lvars.obd_vars, lcfg, obd);
return rc;
}
{ "prealloc_next_id", osc_rd_prealloc_next_id, 0, 0 },
{ "prealloc_last_id", osc_rd_prealloc_last_id, 0, 0 },
{ "checksums", osc_rd_checksum, osc_wr_checksum, 0 },
- { "sptlrpc", sptlrpc_lprocfs_rd, 0, 0 },
{ "resend_count", osc_rd_resend_count, osc_wr_resend_count, 0},
{ 0 }
};
/* size[REQ_REC_OFF] still sizeof (*body) */
if (opc == OST_WRITE) {
- if (unlikely(cli->cl_checksum)) {
+ if (unlikely(cli->cl_checksum) &&
+ req->rq_flvr.sf_bulk_csum == BULK_CSUM_ALG_NULL) {
body->oa.o_valid |= OBD_MD_FLCKSUM;
body->oa.o_cksum = osc_checksum_bulk(requested_nob,
page_count, pga,
size[REPLY_REC_OFF + 1] = sizeof(__u32) * niocount;
ptlrpc_req_set_repsize(req, 3, size);
} else {
- if (unlikely(cli->cl_checksum))
+ if (unlikely(cli->cl_checksum) &&
+ req->rq_flvr.sf_bulk_csum == BULK_CSUM_ALG_NULL)
body->oa.o_valid |= OBD_MD_FLCKSUM;
/* 1 RC for the whole I/O */
ptlrpc_req_set_repsize(req, 2, size);
RETURN(rc);
}
-static int osc_reconnect(struct obd_export *exp, struct obd_device *obd,
+static int osc_reconnect(const struct lu_env *env,
+ struct obd_export *exp, struct obd_device *obd,
struct obd_uuid *cluuid,
struct obd_connect_data *data)
{
lprocfs_osc_init_vars(&lvars);
if (lprocfs_obd_setup(obd, lvars.obd_vars) == 0) {
lproc_osc_attach_seqstat(obd);
+ sptlrpc_lprocfs_cliobd_attach(obd);
ptlrpc_lprocfs_register_obd(obd);
}
lprocfs_osc_init_vars(&lvars);
- rc = class_process_proc_param(PARAM_OSC, lvars.obd_vars, lcfg, obd);
+ switch (lcfg->lcfg_command) {
+ case LCFG_SPTLRPC_CONF:
+ rc = sptlrpc_cliobd_process_config(obd, lcfg);
+ break;
+ default:
+ rc = class_process_proc_param(PARAM_OSC, lvars.obd_vars,
+ lcfg, obd);
+ break;
+ }
+
return(rc);
}
}
no_reply = rc != 0;
- if (rc == 0) {
- /* let client retry if unwrap failed */
- rc = sptlrpc_svc_unwrap_bulk(req, desc);
- }
+ if (rc == 0)
+ sptlrpc_svc_unwrap_bulk(req, desc);
repbody = lustre_msg_buf(req->rq_repmsg, REPLY_REC_OFF,
sizeof(*repbody));
RETURN(rc);
}
+static int filter_export_check_flavor(struct filter_obd *filter,
+ struct obd_export *exp,
+ struct ptlrpc_request *req)
+{
+ int rc = 0;
+
+ /* FIXME
+ * this should be done in filter_connect()/filter_reconnect(), but
+ * we can't obtain information like NID, which stored in incoming
+ * request, thus can't decide what flavor to use. so we do it here.
+ *
+ * This hack should be removed after the OST stack be rewritten, just
+ * like what we are doing in mdt_obd_connect()/mdt_obd_reconnect().
+ */
+ if (exp->exp_flvr.sf_rpc != SPTLRPC_FLVR_INVALID)
+ return 0;
+
+ CDEBUG(D_SEC, "from %s\n", sptlrpc_part2name(req->rq_sp_from));
+ spin_lock(&exp->exp_lock);
+ exp->exp_sp_peer = req->rq_sp_from;
+
+ read_lock(&filter->fo_sptlrpc_lock);
+ sptlrpc_rule_set_choose(&filter->fo_sptlrpc_rset, exp->exp_sp_peer,
+ req->rq_peer.nid, &exp->exp_flvr);
+ read_unlock(&filter->fo_sptlrpc_lock);
+
+ if (exp->exp_flvr.sf_rpc != req->rq_flvr.sf_rpc) {
+ CERROR("invalid rpc flavor %x, expect %x, from %s\n",
+ req->rq_flvr.sf_rpc, exp->exp_flvr.sf_rpc,
+ libcfs_nid2str(req->rq_peer.nid));
+ exp->exp_flvr.sf_rpc = SPTLRPC_FLVR_INVALID;
+ rc = -EACCES;
+ }
+
+ spin_unlock(&exp->exp_lock);
+
+ return rc;
+}
static int ost_filter_recovery_request(struct ptlrpc_request *req,
struct obd_device *obd, int *process)
if (OBD_FAIL_CHECK(OBD_FAIL_OST_CONNECT_NET))
RETURN(0);
rc = target_handle_connect(req);
- if (!rc)
- obd = req->rq_export->exp_obd;
+ if (!rc) {
+ struct obd_export *exp = req->rq_export;
+
+ obd = exp->exp_obd;
+
+ rc = filter_export_check_flavor(&obd->u.filter,
+ exp, req);
+ }
break;
}
case OST_DISCONNECT:
ptlrpc_objs += events.o ptlrpc_module.o service.o pinger.o recov_thread.o
ptlrpc_objs += llog_net.o llog_client.o llog_server.o import.o ptlrpcd.o
ptlrpc_objs += pers.o lproc_ptlrpc.o wiretest.o layout.o
-ptlrpc_objs += sec.o sec_bulk.o sec_gc.o sec_null.o sec_plain.o sec_lproc.o
+ptlrpc_objs += sec.o sec_bulk.o sec_gc.o sec_config.o sec_lproc.o
+ptlrpc_objs += sec_null.o sec_plain.o
ptlrpc-objs := $(ldlm_objs) $(ptlrpc_objs)
COMMON_SOURCES = client.c recover.c connection.c niobuf.c pack_generic.c \
events.c ptlrpc_module.c service.c pinger.c recov_thread.c llog_net.c \
llog_client.c llog_server.c import.c ptlrpcd.c pers.c wiretest.c \
- ptlrpc_internal.h layout.c sec.c sec_bulk.c sec_gc.c sec_null.c \
- sec_plain.c sec_lproc.c lproc_ptlrpc.c $(LDLM_COMM_SOURCES)
+ ptlrpc_internal.h layout.c sec.c sec_bulk.c sec_gc.c sec_config.c \
+ sec_lproc.c sec_null.c sec_plain.c lproc_ptlrpc.c $(LDLM_COMM_SOURCES)
if LIBLUSTRE
service.c \
wiretest.c \
sec.c \
+ sec_bulk.c \
+ sec_gc.c \
+ sec_config.c \
+ sec_lproc.c \
sec_null.c \
sec_plain.c \
$(LDLM_COMM_SOURCES)
modulefs_DATA = ptlrpc_gss$(KMODEXT)
endif # MODULES
-DIST_SOURCES = $(ptlrpc_gss-objs:.o=.c) gss_api.h gss_asn1.h gss_err.h \
- gss_internal.h gss_krb5.h
+DIST_SOURCES = *.c *.h
MOSTLYCLEANFILES := @MOSTLYCLEANFILES@
rawobj_t *out_msg);
__u32 lgss_plain_encrypt(
struct gss_ctx *ctx,
+ int decrypt,
int length,
void *in_buf,
void *out_buf);
rawobj_t *out_msg);
__u32 (*gss_plain_encrypt)(
struct gss_ctx *ctx,
+ int decrypt,
int length,
void *in_buf,
void *out_buf);
{
struct crypto_tfm *tfm;
struct scatterlist sg, sg2, *sgd;
+ unsigned int blksize;
int i, rc;
__u8 local_iv[sizeof(bsd->bsd_iv)];
if (alg == BULK_PRIV_ALG_NULL)
return 0;
- if (encrypt)
- get_random_bytes(bsd->bsd_iv, sizeof(bsd->bsd_iv));
-
- /* compute the secret iv */
- lgss_plain_encrypt(gctx, sizeof(local_iv), bsd->bsd_iv, local_iv);
-
tfm = crypto_alloc_tfm(sptlrpc_bulk_priv_alg2name(alg),
sptlrpc_bulk_priv_alg2flags(alg));
if (tfm == NULL) {
return -ENOMEM;
}
+ blksize = crypto_tfm_alg_blocksize(tfm);
+ LASSERT(blksize <= sizeof(local_iv));
+
+ if (encrypt)
+ get_random_bytes(bsd->bsd_iv, sizeof(bsd->bsd_iv));
+
+ /* compute the secret iv */
+ rc = lgss_plain_encrypt(gctx, 0,
+ sizeof(local_iv), bsd->bsd_iv, local_iv);
+ if (rc) {
+ CERROR("failed to compute secret iv: %d\n", rc);
+ goto out;
+ }
+
rc = crypto_cipher_setkey(tfm, local_iv, sizeof(local_iv));
if (rc) {
CERROR("Failed to set key for TFM %s: %d\n",
sptlrpc_bulk_priv_alg2name(alg), rc);
- crypto_free_tfm(tfm);
- return rc;
+ goto out;
}
for (i = 0; i < desc->bd_iov_count; i++) {
*/
}
- crypto_free_tfm(tfm);
-
if (encrypt)
bsd->bsd_priv_alg = alg;
- return 0;
+out:
+ crypto_free_tfm(tfm);
+ return rc;
}
int gss_cli_ctx_wrap_bulk(struct ptlrpc_cli_ctx *ctx,
struct gss_cli_ctx *gctx;
struct lustre_msg *msg;
struct ptlrpc_bulk_sec_desc *bsdr;
- struct sec_flavor_config *conf;
int offset, rc;
ENTRY;
- LASSERT(SEC_FLAVOR_HAS_BULK(req->rq_sec_flavor));
+ LASSERT(req->rq_pack_bulk);
LASSERT(req->rq_bulk_read || req->rq_bulk_write);
- switch (SEC_FLAVOR_SVC(req->rq_sec_flavor)) {
+ switch (RPC_FLVR_SVC(req->rq_flvr.sf_rpc)) {
case SPTLRPC_SVC_NULL:
LASSERT(req->rq_reqbuf->lm_bufcount >= 3);
msg = req->rq_reqbuf;
}
/* make checksum */
- conf = &req->rq_import->imp_obd->u.cli.cl_sec_conf;
- rc = bulk_csum_cli_request(desc, req->rq_bulk_read, conf->sfc_bulk_csum,
- msg, offset);
+ rc = bulk_csum_cli_request(desc, req->rq_bulk_read,
+ req->rq_flvr.sf_bulk_csum, msg, offset);
if (rc) {
CERROR("client bulk %s: failed to generate checksum: %d\n",
req->rq_bulk_read ? "read" : "write", rc);
RETURN(rc);
}
- if (conf->sfc_bulk_priv == BULK_PRIV_ALG_NULL)
+ if (req->rq_flvr.sf_bulk_priv == BULK_PRIV_ALG_NULL)
RETURN(0);
/* previous bulk_csum_cli_request() has verified bsdr is good */
bsdr = lustre_msg_buf(msg, offset, 0);
if (req->rq_bulk_read) {
- bsdr->bsd_priv_alg = conf->sfc_bulk_priv;
+ bsdr->bsd_priv_alg = req->rq_flvr.sf_bulk_priv;
RETURN(0);
}
LASSERT(gctx->gc_mechctx);
rc = do_bulk_privacy(gctx->gc_mechctx, desc, 1,
- conf->sfc_bulk_priv, bsdr);
+ req->rq_flvr.sf_bulk_priv, bsdr);
if (rc)
CERROR("bulk write: client failed to encrypt pages\n");
int roff, voff, rc;
ENTRY;
- LASSERT(SEC_FLAVOR_HAS_BULK(req->rq_sec_flavor));
+ LASSERT(req->rq_pack_bulk);
LASSERT(req->rq_bulk_read || req->rq_bulk_write);
- switch (SEC_FLAVOR_SVC(req->rq_sec_flavor)) {
+ switch (RPC_FLVR_SVC(req->rq_flvr.sf_rpc)) {
case SPTLRPC_SVC_NULL:
vmsg = req->rq_repbuf;
voff = vmsg->lm_bufcount - 1;
ENTRY;
LASSERT(req->rq_svc_ctx);
+ LASSERT(req->rq_pack_bulk);
LASSERT(req->rq_bulk_write);
grctx = gss_svc_ctx2reqctx(req->rq_svc_ctx);
ENTRY;
LASSERT(req->rq_svc_ctx);
+ LASSERT(req->rq_pack_bulk);
LASSERT(req->rq_bulk_read);
grctx = gss_svc_ctx2reqctx(req->rq_svc_ctx);
rawobj_t obj;
LASSERT(msg->lm_bufcount <= 4);
+ LASSERT(req->rq_cli_ctx);
+ LASSERT(req->rq_cli_ctx->cc_sec);
/* gss hdr */
ghdr = lustre_msg_buf(msg, 0, sizeof(*ghdr));
ghdr->gh_handle.len = 0;
/* fix the user desc */
- if (SEC_FLAVOR_HAS_USER(req->rq_sec_flavor)) {
+ if (req->rq_pack_udesc) {
+ ghdr->gh_flags |= LUSTRE_GSS_PACK_USER;
+
pud = lustre_msg_buf(msg, offset, sizeof(*pud));
LASSERT(pud);
pud->pud_uid = pud->pud_fsuid = uid;
/* security payload */
p = lustre_msg_buf(msg, offset, 0);
size = msg->lm_buflens[offset];
+ LASSERT(p);
/* 1. lustre svc type */
LASSERT(size > 4);
/* 3. reverse context handle. actually only needed by root user,
* but we send it anyway. */
- gsec = container_of(imp->imp_sec, struct gss_sec, gs_base);
+ gsec = sec2gsec(req->rq_cli_ctx->cc_sec);
obj.len = sizeof(gsec->gs_rvs_hdl);
obj.data = (__u8 *) &gsec->gs_rvs_hdl;
if (rawobj_serialize(&obj, &p, &size))
/* XXX move to where lgssd could see */
struct lgssd_ioctl_param {
int version; /* in */
+ int secid; /* in */
char *uuid; /* in */
int lustre_svc; /* in */
uid_t uid; /* in */
goto out_copy;
}
+ if (req->rq_cli_ctx->cc_sec->ps_id != param.secid) {
+ CWARN("original secid %d, now has changed to %d, "
+ "cancel this negotiation\n", param.secid,
+ req->rq_cli_ctx->cc_sec->ps_id);
+ param.status = -EINVAL;
+ goto out_copy;
+ }
+
/* get token */
rc = ctx_init_pack_request(imp, req,
param.lustre_svc,
might_sleep();
- CDEBUG(D_SEC, "%s ctx %p(%u->%s)\n",
- sec_is_reverse(ctx->cc_sec) ?
- "server finishing reverse" : "client finishing forward",
- ctx, ctx->cc_vcred.vc_uid, sec2target_str(ctx->cc_sec));
+ CWARN("%s ctx %p idx "LPX64" (%u->%s)\n",
+ sec_is_reverse(ctx->cc_sec) ?
+ "server finishing reverse" : "client finishing forward",
+ ctx, gss_handle_to_u64(&gctx->gc_handle),
+ ctx->cc_vcred.vc_uid, sec2target_str(ctx->cc_sec));
gctx->gc_proc = PTLRPC_GSS_PROC_DESTROY;
}
/* fix the user desc */
- if (SEC_FLAVOR_HAS_USER(req->rq_sec_flavor)) {
+ if (req->rq_pack_udesc) {
/* we rely the fact that this request is in AUTH mode,
* and user_desc at offset 2. */
pud = lustre_msg_buf(req->rq_reqbuf, 2, sizeof(*pud));
__u8 *buf;
} rawobj_buf_t;
+int rawobj_empty(rawobj_t *obj);
int rawobj_alloc(rawobj_t *obj, char *buf, int len);
void rawobj_free(rawobj_t *obj);
int rawobj_equal(rawobj_t *a, rawobj_t *b);
LUSTRE_GSS_TGT_MGS = 2,
};
+enum ptlrpc_gss_header_flags {
+ LUSTRE_GSS_PACK_BULK = 1,
+ LUSTRE_GSS_PACK_USER = 2,
+};
+
static inline
__u32 import_to_gss_svc(struct obd_import *imp)
{
* following 3 header must have the same size and offset
*/
struct gss_header {
- __u32 gh_version; /* gss version */
+ __u8 gh_version; /* gss version */
+ __u8 gh_sp; /* sec part */
+ __u16 gh_pad0;
__u32 gh_flags; /* wrap flags */
__u32 gh_proc; /* proc */
__u32 gh_seq; /* sequence */
};
struct gss_rep_header {
- __u32 gh_version;
+ __u8 gh_version;
+ __u8 gh_sp;
+ __u16 gh_pad0;
__u32 gh_flags;
__u32 gh_proc;
__u32 gh_major;
};
struct gss_err_header {
- __u32 gh_version;
+ __u8 gh_version;
+ __u8 gh_sp;
+ __u16 gh_pad0;
__u32 gh_flags;
__u32 gh_proc;
__u32 gh_major;
* used later by server.
*/
struct gss_wire_ctx {
+ __u32 gw_flags;
__u32 gw_proc;
__u32 gw_seq;
__u32 gw_svc;
PTLRPC_GSS_MAX_HANDLE_SIZE)
+static inline __u64 gss_handle_to_u64(rawobj_t *handle)
+{
+ if (handle->len != PTLRPC_GSS_MAX_HANDLE_SIZE)
+ return -1;
+ return *((__u64 *) handle->data);
+}
+
#define GSS_SEQ_WIN (2048)
#define GSS_SEQ_WIN_MAIN GSS_SEQ_WIN
#define GSS_SEQ_WIN_BACK (128)
};
struct gss_svc_ctx {
- unsigned int gsc_usr_root:1,
- gsc_usr_mds:1,
- gsc_remote:1;
+ struct gss_ctx *gsc_mechctx;
+ struct gss_svc_seq_data gsc_seqdata;
+ rawobj_t gsc_rvs_hdl;
+ __u32 gsc_rvs_seq;
uid_t gsc_uid;
gid_t gsc_gid;
uid_t gsc_mapped_uid;
- rawobj_t gsc_rvs_hdl;
- struct gss_svc_seq_data gsc_seqdata;
- struct gss_ctx *gsc_mechctx;
+ unsigned int gsc_usr_root:1,
+ gsc_usr_mds:1,
+ gsc_remote:1,
+ gsc_reverse:1;
};
struct gss_svc_reqctx {
atomic_t gc_seq;
rawobj_t gc_handle;
struct gss_ctx *gc_mechctx;
+ /* handle for the buddy svc ctx */
+ rawobj_t gc_svc_handle;
};
struct gss_cli_ctx_keyring {
struct gss_sec_keyring {
struct gss_sec gsk_base;
/*
- * unique sec_id.
- */
- int gsk_id;
- /*
* all contexts listed here. access is protected by sec spinlock.
*/
struct hlist_head gsk_clist;
return container_of(ctx, struct gss_svc_reqctx, src_base);
}
+static inline
+struct gss_svc_ctx *gss_svc_ctx2gssctx(struct ptlrpc_svc_ctx *ctx)
+{
+ LASSERT(ctx);
+ return gss_svc_ctx2reqctx(ctx)->src_ctx;
+}
+
/* sec_gss.c */
int gss_cli_ctx_match(struct ptlrpc_cli_ctx *ctx, struct vfs_cred *vcred);
int gss_cli_ctx_display(struct ptlrpc_cli_ctx *ctx, char *buf, int bufsize);
struct ptlrpc_sec_policy *policy,
struct obd_import *imp,
struct ptlrpc_svc_ctx *ctx,
- __u32 flavor,
- unsigned long flags);
+ struct sptlrpc_flavor *sf);
void gss_sec_destroy_common(struct gss_sec *gsec);
+void gss_sec_kill(struct ptlrpc_sec *sec);
int gss_cli_ctx_init_common(struct ptlrpc_sec *sec,
struct ptlrpc_cli_ctx *ctx,
void gss_cli_ctx_flags2str(unsigned long flags, char *buf, int bufsize);
/* gss_keyring.c */
-extern struct ptlrpc_sec_policy gss_policy_keyring;
int __init gss_init_keyring(void);
void __exit gss_exit_keyring(void);
int gss_svc_upcall_install_rvs_ctx(struct obd_import *imp,
struct gss_sec *gsec,
struct gss_cli_ctx *gctx);
+int gss_svc_upcall_expire_rvs_ctx(rawobj_t *handle);
+int gss_svc_upcall_dup_handle(rawobj_t *handle, struct gss_svc_ctx *ctx);
+int gss_svc_upcall_update_sequence(rawobj_t *handle, __u32 seq);
int gss_svc_upcall_handle_init(struct ptlrpc_request *req,
struct gss_svc_reqctx *grctx,
struct gss_wire_ctx *gw,
static int sec_install_rctx_kr(struct ptlrpc_sec *sec,
struct ptlrpc_svc_ctx *svc_ctx);
+#ifndef task_aux
+#define task_aux(tsk) (tsk)
+#endif
+
/*
* the timeout is only for the case that upcall child process die abnormally.
* in any other cases it should finally update kernel key. so we set this
{
struct ptlrpc_sec *sec = ctx->cc_sec;
struct gss_cli_ctx_keyring *gctx_kr = ctx2gctx_keyring(ctx);
- int rc;
CDEBUG(D_SEC, "destroying ctx %p\n", ctx);
/* at this time the association with key has been broken. */
LASSERT(sec);
+ LASSERT(atomic_read(&sec->ps_refcount) > 0);
+ LASSERT(atomic_read(&sec->ps_nctx) > 0);
LASSERT(test_bit(PTLRPC_CTX_CACHED_BIT, &ctx->cc_flags) == 0);
LASSERT(gctx_kr->gck_key == NULL);
ctx_clear_timer_kr(ctx);
LASSERT(gctx_kr->gck_timer == NULL);
- rc = gss_cli_ctx_fini_common(sec, ctx);
- if (rc < 0)
+ if (gss_cli_ctx_fini_common(sec, ctx))
return;
OBD_FREE_PTR(gctx_kr);
- if (rc > 0) {
- CWARN("released the last ctx, proceed to destroy sec %s@%p\n",
- sec->ps_policy->sp_name, sec);
- sptlrpc_sec_destroy(sec);
+ atomic_dec(&sec->ps_nctx);
+ sptlrpc_sec_put(sec);
+}
+
+static void ctx_release_kr(struct ptlrpc_cli_ctx *ctx, int sync)
+{
+ if (sync) {
+ ctx_destroy_kr(ctx);
+ } else {
+ atomic_inc(&ctx->cc_refcount);
+ sptlrpc_gc_add_ctx(ctx);
}
}
-static void ctx_put_kr(struct ptlrpc_cli_ctx *ctx)
+static void ctx_put_kr(struct ptlrpc_cli_ctx *ctx, int sync)
{
LASSERT(atomic_read(&ctx->cc_refcount) > 0);
if (atomic_dec_and_test(&ctx->cc_refcount))
- ctx_destroy_kr(ctx);
+ ctx_release_kr(ctx, sync);
}
/*
spin_unlock(lock);
}
-static
-void ctx_enlist_kr(struct ptlrpc_cli_ctx *ctx, int is_root, int locked)
+static void ctx_enlist_kr(struct ptlrpc_cli_ctx *ctx, int is_root, int locked)
{
struct ptlrpc_sec *sec = ctx->cc_sec;
struct gss_sec_keyring *gsec_kr = sec2gsec_keyring(sec);
*
* return non-zero if we indeed unlist this ctx.
*/
-static
-int ctx_unlist_kr(struct ptlrpc_cli_ctx *ctx, int locked)
+static int ctx_unlist_kr(struct ptlrpc_cli_ctx *ctx, int locked)
{
struct ptlrpc_sec *sec = ctx->cc_sec;
struct gss_sec_keyring *gsec_kr = sec2gsec_keyring(sec);
* bind a key with a ctx together.
* caller must hold write lock of the key, as well as ref on key & ctx.
*/
-static
-void bind_key_ctx(struct key *key, struct ptlrpc_cli_ctx *ctx)
+static void bind_key_ctx(struct key *key, struct ptlrpc_cli_ctx *ctx)
{
LASSERT(atomic_read(&ctx->cc_refcount) > 0);
LASSERT(atomic_read(&key->usage) > 0);
* unbind a key and a ctx.
* caller must hold write lock, as well as a ref of the key.
*/
-static
-void unbind_key_ctx(struct key *key, struct ptlrpc_cli_ctx *ctx)
+static void unbind_key_ctx(struct key *key, struct ptlrpc_cli_ctx *ctx)
{
LASSERT(key->payload.data == ctx);
LASSERT(test_bit(PTLRPC_CTX_CACHED_BIT, &ctx->cc_flags) == 0);
/* once ctx get split from key, the timer is meaningless */
ctx_clear_timer_kr(ctx);
- ctx_put_kr(ctx);
+ ctx_put_kr(ctx, 1);
key_put(key);
}
sptlrpc_cli_ctx_wakeup(ctx);
unbind_ctx_kr(ctx);
- ctx_put_kr(ctx);
+ ctx_put_kr(ctx, 0);
}
}
static void construct_key_desc(void *buf, int bufsize,
struct ptlrpc_sec *sec, uid_t uid)
{
- snprintf(buf, bufsize, "%d@%x", uid, sec2gsec_keyring(sec)->gsk_id);
+ snprintf(buf, bufsize, "%d@%x", uid, sec->ps_id);
((char *)buf)[bufsize - 1] = '\0';
}
* sec apis *
****************************************/
-static atomic_t gss_sec_id_kr = ATOMIC_INIT(0);
-
static
struct ptlrpc_sec * gss_sec_create_kr(struct obd_import *imp,
- struct ptlrpc_svc_ctx *ctx,
- __u32 flavor,
- unsigned long flags)
+ struct ptlrpc_svc_ctx *svcctx,
+ struct sptlrpc_flavor *sf)
{
struct gss_sec_keyring *gsec_kr;
ENTRY;
if (gsec_kr == NULL)
RETURN(NULL);
- gsec_kr->gsk_id = atomic_inc_return(&gss_sec_id_kr);
CFS_INIT_HLIST_HEAD(&gsec_kr->gsk_clist);
gsec_kr->gsk_root_ctx = NULL;
mutex_init(&gsec_kr->gsk_root_uc_lock);
#endif
if (gss_sec_create_common(&gsec_kr->gsk_base, &gss_policy_keyring,
- imp, ctx, flavor, flags))
+ imp, svcctx, sf))
goto err_free;
- if (ctx != NULL) {
- if (sec_install_rctx_kr(&gsec_kr->gsk_base.gs_base, ctx)) {
- gss_sec_destroy_common(&gsec_kr->gsk_base);
- goto err_free;
- }
+ if (svcctx != NULL &&
+ sec_install_rctx_kr(&gsec_kr->gsk_base.gs_base, svcctx)) {
+ gss_sec_destroy_common(&gsec_kr->gsk_base);
+ goto err_free;
}
RETURN(&gsec_kr->gsk_base.gs_base);
OBD_FREE(gsec_kr, sizeof(*gsec_kr));
}
-static
-int user_is_root(struct ptlrpc_sec *sec, struct vfs_cred *vcred)
+static inline int user_is_root(struct ptlrpc_sec *sec, struct vfs_cred *vcred)
{
- if (sec->ps_flags & PTLRPC_SEC_FL_ROOTONLY)
+ /* except the ROOTONLY flag, treat it as root user only if real uid
+ * is 0, euid/fsuid being 0 are handled as setuid scenarios */
+ if (sec_is_rootonly(sec) || (vcred->vc_uid == 0))
return 1;
-
- /* FIXME
- * more precisely deal with setuid. maybe add more infomation
- * into vfs_cred ?? */
- return (vcred->vc_uid == 0);
+ else
+ return 0;
}
/*
struct key *key;
char desc[24];
char *coinfo;
- const int coinfo_size = sizeof(struct obd_uuid) + 64;
+ int coinfo_size;
char *co_flags = "";
ENTRY;
co_flags = "r";
}
+ /* in case of setuid, key will be constructed as owner of fsuid/fsgid,
+ * but we do authentication based on real uid/gid. the key permission
+ * bits will be exactly as POS_ALL, so only processes who subscribed
+ * this key could have the access, although the quota might be counted
+ * on others (fsuid/fsgid).
+ *
+ * keyring will use fsuid/fsgid as upcall parameters, so we have to
+ * encode real uid/gid into callout info.
+ */
+
construct_key_desc(desc, sizeof(desc), sec, vcred->vc_uid);
- /* callout info: mech:flags:svc_type:peer_nid:target_uuid */
+ /* callout info format:
+ * secid:mech:uid:gid:flags:svc_type:peer_nid:target_uuid
+ */
+ coinfo_size = sizeof(struct obd_uuid) + MAX_OBD_NAME + 64;
OBD_ALLOC(coinfo, coinfo_size);
if (coinfo == NULL)
goto out;
- snprintf(coinfo, coinfo_size, "%s:%s:%d:"LPX64":%s",
- sec2gsec(sec)->gs_mech->gm_name,
+ snprintf(coinfo, coinfo_size, "%d:%s:%u:%u:%s:%d:"LPX64":%s",
+ sec->ps_id, sec2gsec(sec)->gs_mech->gm_name,
+ vcred->vc_uid, vcred->vc_gid,
co_flags, import_to_gss_svc(imp),
imp->imp_connection->c_peer.nid, imp->imp_obd->obd_name);
struct ptlrpc_cli_ctx *ctx,
int sync)
{
+ LASSERT(atomic_read(&sec->ps_refcount) > 0);
LASSERT(atomic_read(&ctx->cc_refcount) == 0);
-
- if (sync) {
- ctx_destroy_kr(ctx);
- } else {
- atomic_inc(&ctx->cc_refcount);
- sptlrpc_gc_add_ctx(ctx);
- }
+ ctx_release_kr(ctx, sync);
}
/*
atomic_inc(&ctx->cc_refcount);
- if (ctx_unlist_kr(ctx, 1))
+ if (ctx_unlist_kr(ctx, 1)) {
hlist_add_head(&ctx->cc_cache, &freelist);
- else {
+ } else {
LASSERT(atomic_read(&ctx->cc_refcount) >= 2);
atomic_dec(&ctx->cc_refcount);
}
-
}
spin_unlock(&sec->ps_lock);
{
ENTRY;
- CDEBUG(D_SEC, "sec %p(%d, busy %d), uid %d, grace %d, force %d\n",
- sec, atomic_read(&sec->ps_refcount), atomic_read(&sec->ps_busy),
+ CDEBUG(D_SEC, "sec %p(%d, nctx %d), uid %d, grace %d, force %d\n",
+ sec, atomic_read(&sec->ps_refcount), atomic_read(&sec->ps_nctx),
uid, grace, force);
if (uid != -1 && uid != 0)
}
static
-int gss_sec_display_kr(struct ptlrpc_sec *sec, char *buf, int bufsize)
+int gss_sec_display_kr(struct ptlrpc_sec *sec, struct seq_file *seq)
{
struct gss_sec_keyring *gsec_kr = sec2gsec_keyring(sec);
struct hlist_node *pos, *next;
struct ptlrpc_cli_ctx *ctx;
- int written = 0;
+ struct gss_cli_ctx *gctx;
+ time_t now = cfs_time_current_sec();
ENTRY;
- written = snprintf(buf, bufsize, "context list ===>\n");
- bufsize -= written;
- buf += written;
-
spin_lock(&sec->ps_lock);
hlist_for_each_entry_safe(ctx, pos, next,
&gsec_kr->gsk_clist, cc_cache) {
- struct gss_cli_ctx *gctx;
struct key *key;
char flags_str[40];
- int len;
+ char mech[40];
gctx = ctx2gctx(ctx);
key = ctx2gctx_keyring(ctx)->gck_key;
gss_cli_ctx_flags2str(ctx->cc_flags,
flags_str, sizeof(flags_str));
- len = snprintf(buf, bufsize, "%p(%d): uid %u, exp %ld(%ld)s, "
- "fl %s, seq %d, win %u, key %08x(%d), ",
- ctx, atomic_read(&ctx->cc_refcount),
- ctx->cc_vcred.vc_uid,
- ctx->cc_expire,
- ctx->cc_expire - cfs_time_current_sec(),
- flags_str,
- atomic_read(&gctx->gc_seq),
- gctx->gc_win,
- key ? key->serial : 0,
- key ? atomic_read(&key->usage) : 0);
-
- written += len;
- buf += len;
- bufsize -= len;
-
- if (bufsize <= 0)
- break;
-
if (gctx->gc_mechctx)
- len = lgss_display(gctx->gc_mechctx, buf, bufsize);
+ lgss_display(gctx->gc_mechctx, mech, sizeof(mech));
else
- len = snprintf(buf, bufsize, "mech N/A\n");
-
- written += len;
- buf += len;
- bufsize -= len;
-
- if (bufsize <= 0)
- break;
+ snprintf(mech, sizeof(mech), "N/A");
+ mech[sizeof(mech) - 1] = '\0';
+
+ seq_printf(seq, "%p: uid %u, ref %d, expire %ld(%+ld), fl %s, "
+ "seq %d, win %u, key %08x(ref %d), "
+ "hdl "LPX64":"LPX64", mech: %s\n",
+ ctx, ctx->cc_vcred.vc_uid,
+ atomic_read(&ctx->cc_refcount),
+ ctx->cc_expire,
+ ctx->cc_expire ? ctx->cc_expire - now : 0,
+ flags_str,
+ atomic_read(&gctx->gc_seq),
+ gctx->gc_win,
+ key ? key->serial : 0,
+ key ? atomic_read(&key->usage) : 0,
+ gss_handle_to_u64(&gctx->gc_handle),
+ gss_handle_to_u64(&gctx->gc_svc_handle),
+ mech);
}
spin_unlock(&sec->ps_lock);
- RETURN(written);
+ RETURN(0);
}
/****************************************
if (rc) {
CERROR("failed copy reverse cli ctx: %d\n", rc);
- ctx_put_kr(cli_ctx);
+ ctx_put_kr(cli_ctx, 1);
return rc;
}
rvs_sec_install_root_ctx_kr(sec, cli_ctx, NULL);
- ctx_put_kr(cli_ctx);
+ ctx_put_kr(cli_ctx, 1);
return 0;
}
rvs_sec_install_root_ctx_kr(sec, cli_ctx, key);
- ctx_put_kr(cli_ctx);
+ ctx_put_kr(cli_ctx, 1);
up_write(&key->sem);
rc = 0;
return rc;
err_put:
- ctx_put_kr(cli_ctx);
+ ctx_put_kr(cli_ctx, 1);
err_up:
up_write(&key->sem);
err_revoke:
int gss_svc_install_rctx_kr(struct obd_import *imp,
struct ptlrpc_svc_ctx *svc_ctx)
{
- LASSERT(imp->imp_sec);
+ struct ptlrpc_sec *sec;
+ int rc;
- return sec_install_rctx_kr(imp->imp_sec, svc_ctx);
+ sec = sptlrpc_import_sec_ref(imp);
+ LASSERT(sec);
+
+ rc = sec_install_rctx_kr(sec, svc_ctx);
+ sptlrpc_sec_put(sec);
+
+ return rc;
}
/****************************************
static
int gss_kt_instantiate(struct key *key, const void *data, size_t datalen)
{
+ int rc;
ENTRY;
if (data != NULL || datalen != 0) {
RETURN(-EINVAL);
}
- /* XXX */
- key->perm |= KEY_POS_ALL | KEY_USR_ALL;
+ /* link the key to session keyring, so following context negotiation
+ * rpc fired from user space could find this key. This will be unlinked
+ * automatically when upcall processes die.
+ *
+ * we can't do this through keyctl from userspace, because the upcall
+ * might be neither possessor nor owner of the key (setuid).
+ *
+ * the session keyring is created upon upcall, and don't change all
+ * the way until upcall finished, so rcu lock is not needed here.
+ */
+ LASSERT(cfs_current()->signal->session_keyring);
+
+ rc = key_link(cfs_current()->signal->session_keyring, key);
+ if (unlikely(rc)) {
+ CERROR("failed to link key %08x to keyring %08x: %d\n",
+ key->serial,
+ cfs_current()->signal->session_keyring->serial, rc);
+ RETURN(rc);
+ }
+
CDEBUG(D_SEC, "key %p instantiated, ctx %p\n", key, key->payload.data);
RETURN(0);
}
static struct ptlrpc_sec_cops gss_sec_keyring_cops = {
.create_sec = gss_sec_create_kr,
.destroy_sec = gss_sec_destroy_kr,
+ .kill_sec = gss_sec_kill,
.lookup_ctx = gss_sec_lookup_ctx_kr,
.release_ctx = gss_sec_release_ctx_kr,
.flush_ctx_cache = gss_sec_flush_ctx_cache_kr,
static
__u32 gss_plain_encrypt_kerberos(struct gss_ctx *ctx,
+ int decrypt,
int length,
void *in_buf,
void *out_buf)
struct krb5_ctx *kctx = ctx->internal_ctx_id;
__u32 rc;
- rc = krb5_encrypt(kctx->kc_keye.kb_tfm, 0,
+ rc = krb5_encrypt(kctx->kc_keye.kb_tfm, decrypt,
NULL, in_buf, out_buf, length);
if (rc)
CERROR("plain encrypt error: %d\n", rc);
struct krb5_ctx *kctx = ctx->internal_ctx_id;
int written;
- written = snprintf(buf, bufsize, "mech: krb5 (%s)\n",
+ written = snprintf(buf, bufsize, "krb5 (%s)",
enctype2str(kctx->kc_enctype));
return written;
}
__u32 lgss_plain_encrypt(struct gss_ctx *ctx,
+ int decrypt,
int length,
void *in_buf,
void *out_buf)
LASSERT(ctx->mech_type->gm_ops->gss_plain_encrypt);
return ctx->mech_type->gm_ops
- ->gss_plain_encrypt(ctx, length, in_buf, out_buf);
+ ->gss_plain_encrypt(ctx, decrypt, length, in_buf, out_buf);
}
/* gss_delete_sec_context: free all resources associated with context_handle.
void ctx_destroy_pf(struct ptlrpc_sec *sec, struct ptlrpc_cli_ctx *ctx)
{
struct gss_cli_ctx *gctx = ctx2gctx(ctx);
- int rc;
- rc = gss_cli_ctx_fini_common(sec, ctx);
- if (rc < 0)
+ if (gss_cli_ctx_fini_common(sec, ctx))
return;
OBD_FREE_PTR(gctx);
- if (rc > 0) {
- CWARN("released the last ctx, proceed to destroy sec %s@%p\n",
- sec->ps_policy->sp_name, sec);
- sptlrpc_sec_destroy(sec);
- }
+ atomic_dec(&sec->ps_nctx);
+ sptlrpc_sec_put(sec);
}
static
}
ctx_enhash_pf(new, &gsec_pf->gsp_chash[hash]);
- atomic_inc(&gsec->gs_base.ps_busy);
spin_unlock(&gsec->gs_base.ps_lock);
static
struct ptlrpc_sec* gss_sec_create_pf(struct obd_import *imp,
struct ptlrpc_svc_ctx *ctx,
- __u32 flavor,
- unsigned long flags)
+ struct sptlrpc_flavor *sf)
{
struct gss_sec_pipefs *gsec_pf;
int alloc_size, hash_size, i;
#define GSS_SEC_PIPEFS_CTX_HASH_SIZE (32)
- if (ctx || flags & (PTLRPC_SEC_FL_ROOTONLY | PTLRPC_SEC_FL_REVERSE))
+ if (ctx ||
+ sf->sf_flags & (PTLRPC_SEC_FL_ROOTONLY | PTLRPC_SEC_FL_REVERSE))
hash_size = 1;
else
hash_size = GSS_SEC_PIPEFS_CTX_HASH_SIZE;
CFS_INIT_HLIST_HEAD(&gsec_pf->gsp_chash[i]);
if (gss_sec_create_common(&gsec_pf->gsp_base, &gss_policy_pipefs,
- imp, ctx, flavor, flags))
+ imp, ctx, sf))
goto err_free;
if (ctx == NULL) {
int gss_svc_install_rctx_pf(struct obd_import *imp,
struct ptlrpc_svc_ctx *ctx)
{
- struct gss_sec *gsec;
+ struct ptlrpc_sec *sec;
+ int rc;
- LASSERT(imp->imp_sec);
- LASSERT(ctx);
+ sec = sptlrpc_import_sec_ref(imp);
+ LASSERT(sec);
+ rc = gss_install_rvs_cli_ctx_pf(sec2gsec(sec), ctx);
- gsec = container_of(imp->imp_sec, struct gss_sec, gs_base);
- return gss_install_rvs_cli_ctx_pf(gsec, ctx);
+ sptlrpc_sec_put(sec);
+ return rc;
}
/****************************************
static struct ptlrpc_sec_cops gss_sec_pipefs_cops = {
.create_sec = gss_sec_create_pf,
.destroy_sec = gss_sec_destroy_pf,
+ .kill_sec = gss_sec_kill,
.lookup_ctx = gss_sec_lookup_ctx_pf,
.release_ctx = gss_sec_release_ctx_pf,
.flush_ctx_cache = gss_sec_flush_ctx_cache_pf,
#include "gss_internal.h"
+int rawobj_empty(rawobj_t *obj)
+{
+ LASSERT(equi(obj->len, obj->data));
+ return (obj->len == 0);
+}
+
int rawobj_alloc(rawobj_t *obj, char *buf, int len)
{
LASSERT(obj);
#include <linux/slab.h>
#include <linux/hash.h>
#include <linux/mutex.h>
+#include <linux/sunrpc/cache.h>
#else
#include <liblustre.h>
#endif
-#include <linux/sunrpc/cache.h>
-
#include <obd.h>
#include <obd_class.h>
#include <obd_support.h>
return idx;
}
-static inline
-unsigned long hash_mem(char *buf, int length, int bits)
+static inline unsigned long hash_mem(char *buf, int length, int bits)
{
unsigned long hash = 0;
unsigned long l = 0;
static struct cache_detail rsi_cache;
static struct rsi *rsi_lookup(struct rsi *item, int set);
-static
-void rsi_free(struct rsi *rsi)
+static void rsi_free(struct rsi *rsi)
{
rawobj_free(&rsi->in_handle);
rawobj_free(&rsi->in_token);
rawobj_free(&rsi->out_token);
}
-static
-void rsi_put(struct cache_head *item, struct cache_detail *cd)
+static void rsi_put(struct cache_head *item, struct cache_detail *cd)
{
struct rsi *rsi = container_of(item, struct rsi, h);
}
}
-static inline
-int rsi_hash(struct rsi *item)
+static inline int rsi_hash(struct rsi *item)
{
return hash_mem((char *)item->in_handle.data, item->in_handle.len,
RSI_HASHBITS) ^
RSI_HASHBITS);
}
-static inline
-int rsi_match(struct rsi *item, struct rsi *tmp)
+static inline int rsi_match(struct rsi *item, struct rsi *tmp)
{
return (rawobj_equal(&item->in_handle, &tmp->in_handle) &&
rawobj_equal(&item->in_token, &tmp->in_token));
}
-static
-void rsi_request(struct cache_detail *cd,
+static void rsi_request(struct cache_detail *cd,
struct cache_head *h,
char **bpp, int *blen)
{
(*bpp)[-1] = '\n';
}
-static inline
-void rsi_init(struct rsi *new, struct rsi *item)
+static inline void rsi_init(struct rsi *new, struct rsi *item)
{
new->out_handle = RAWOBJ_EMPTY;
new->out_token = RAWOBJ_EMPTY;
init_waitqueue_head(&new->waitq);
}
-static inline
-void rsi_update(struct rsi *new, struct rsi *item)
+static inline void rsi_update(struct rsi *new, struct rsi *item)
{
LASSERT(new->out_handle.len == 0);
LASSERT(new->out_token.len == 0);
new->minor_status = item->minor_status;
}
-static
-int rsi_parse(struct cache_detail *cd, char *mesg, int mlen)
+static int rsi_parse(struct cache_detail *cd, char *mesg, int mlen)
{
char *buf = mesg;
char *ep;
static struct cache_detail rsc_cache;
static struct rsc *rsc_lookup(struct rsc *item, int set);
-static
-void rsc_free(struct rsc *rsci)
+static void rsc_free(struct rsc *rsci)
{
rawobj_free(&rsci->handle);
rawobj_free(&rsci->ctx.gsc_rvs_hdl);
lgss_delete_sec_context(&rsci->ctx.gsc_mechctx);
}
-static
-void rsc_put(struct cache_head *item, struct cache_detail *cd)
+static void rsc_put(struct cache_head *item, struct cache_detail *cd)
{
struct rsc *rsci = container_of(item, struct rsc, h);
}
}
-static inline
-int rsc_hash(struct rsc *rsci)
+static inline int rsc_hash(struct rsc *rsci)
{
return hash_mem((char *)rsci->handle.data,
rsci->handle.len, RSC_HASHBITS);
}
-static inline
-int rsc_match(struct rsc *new, struct rsc *tmp)
+static inline int rsc_match(struct rsc *new, struct rsc *tmp)
{
return rawobj_equal(&new->handle, &tmp->handle);
}
-static inline
-void rsc_init(struct rsc *new, struct rsc *tmp)
+static inline void rsc_init(struct rsc *new, struct rsc *tmp)
{
new->handle = tmp->handle;
tmp->handle = RAWOBJ_EMPTY;
new->ctx.gsc_rvs_hdl = RAWOBJ_EMPTY;
}
-static inline
-void rsc_update(struct rsc *new, struct rsc *tmp)
+static inline void rsc_update(struct rsc *new, struct rsc *tmp)
{
new->ctx = tmp->ctx;
tmp->ctx.gsc_rvs_hdl = RAWOBJ_EMPTY;
spin_lock_init(&new->ctx.gsc_seqdata.ssd_lock);
}
-static
-int rsc_parse(struct cache_detail *cd, char *mesg, int mlen)
+static int rsc_parse(struct cache_detail *cd, char *mesg, int mlen)
{
char *buf = mesg;
int len, rv, tmp_int;
typedef int rsc_entry_match(struct rsc *rscp, long data);
-static
-void rsc_flush(rsc_entry_match *match, long data)
+static void rsc_flush(rsc_entry_match *match, long data)
{
struct cache_head **ch;
struct rsc *rscp;
EXIT;
}
-static
-int match_uid(struct rsc *rscp, long uid)
+static int match_uid(struct rsc *rscp, long uid)
{
if ((int) uid == -1)
return 1;
return ((int) rscp->ctx.gsc_uid == (int) uid);
}
-static
-int match_target(struct rsc *rscp, long target)
+static int match_target(struct rsc *rscp, long target)
{
return (rscp->target == (struct obd_device *) target);
}
-static inline
-void rsc_flush_uid(int uid)
+static inline void rsc_flush_uid(int uid)
{
if (uid == -1)
CWARN("flush all gss contexts...\n");
rsc_flush(match_uid, (long) uid);
}
-static inline
-void rsc_flush_target(struct obd_device *target)
+static inline void rsc_flush_target(struct obd_device *target)
{
rsc_flush(match_target, (long) target);
}
static DefineSimpleCacheLookup(rsc, 0);
-static
-struct rsc *gss_svc_searchbyctx(rawobj_t *handle)
+static struct rsc *gss_svc_searchbyctx(rawobj_t *handle)
{
struct rsc rsci;
struct rsc *found;
rscp = rsc_lookup(&rsci, 1);
rsc_free(&rsci);
- if (rscp)
- rsc_put(&rscp->h, &rsc_cache);
+ if (rscp) {
+ /* FIXME */
+ rscp->ctx.gsc_usr_root = 1;
+ rscp->ctx.gsc_usr_mds= 1;
+ rscp->ctx.gsc_reverse = 1;
+
+ rawobj_dup(&gctx->gc_svc_handle, &rscp->handle);
- CDEBUG(D_SEC, "client installed reverse svc ctx to %s: idx "LPX64"\n",
- imp->imp_obd->u.cli.cl_target_uuid.uuid, gsec->gs_rvs_hdl);
+ CWARN("create reverse svc ctx %p to %s: idx "LPX64"\n",
+ &rscp->ctx, obd2cli_tgt(imp->imp_obd),
+ gsec->gs_rvs_hdl);
+
+ rsc_put(&rscp->h, &rsc_cache);
+ }
RETURN(0);
}
-static
-struct cache_deferred_req* cache_upcall_defer(struct cache_req *req)
+int gss_svc_upcall_expire_rvs_ctx(rawobj_t *handle)
+{
+ const cfs_time_t expire = 20;
+ struct rsc *rscp;
+
+ rscp = gss_svc_searchbyctx(handle);
+ if (rscp) {
+ CDEBUG(D_SEC, "reverse svcctx %p (rsc %p) expire soon\n",
+ &rscp->ctx, rscp);
+
+ rscp->h.expiry_time = cfs_time_current_sec() + expire;
+ rsc_put(&rscp->h, &rsc_cache);
+ }
+ return 0;
+}
+
+int gss_svc_upcall_dup_handle(rawobj_t *handle, struct gss_svc_ctx *ctx)
+{
+ struct rsc *rscp = container_of(ctx, struct rsc, ctx);
+
+ return rawobj_dup(handle, &rscp->handle);
+}
+
+int gss_svc_upcall_update_sequence(rawobj_t *handle, __u32 seq)
+{
+ struct rsc *rscp;
+
+ rscp = gss_svc_searchbyctx(handle);
+ if (rscp) {
+ CDEBUG(D_SEC, "reverse svcctx %p (rsc %p) update seq to %u\n",
+ &rscp->ctx, rscp, seq + 1);
+
+ rscp->ctx.gsc_rvs_seq = seq + 1;
+ rsc_put(&rscp->h, &rsc_cache);
+ }
+ return 0;
+}
+
+static struct cache_deferred_req* cache_upcall_defer(struct cache_req *req)
{
return NULL;
}
/* if anything went wrong, we don't keep the context too */
if (rc != SECSVC_OK)
set_bit(CACHE_NEGATIVE, &rsci->h.flags);
+ else
+ CDEBUG(D_SEC, "create rsc with idx "LPX64"\n",
+ gss_handle_to_u64(&rsci->handle));
rsc_put(&rsci->h, &rsc_cache);
}
rsc = gss_svc_searchbyctx(&gw->gw_handle);
if (!rsc) {
- CWARN("Invalid gss context handle from %s\n",
+ CWARN("Invalid gss ctx idx "LPX64" from %s\n",
+ gss_handle_to_u64(&gw->gw_handle),
libcfs_nid2str(req->rq_peer.nid));
return NULL;
}
{
struct rsc *rsc = container_of(ctx, struct rsc, ctx);
+ /* can't be found */
set_bit(CACHE_NEGATIVE, &rsc->h.flags);
+ /* to be removed at next scan */
+ rsc->h.expiry_time = 1;
}
int __init gss_init_svc_upcall(void)
static
void gss_header_swabber(struct gss_header *ghdr)
{
- __swab32s(&ghdr->gh_version);
__swab32s(&ghdr->gh_flags);
__swab32s(&ghdr->gh_proc);
__swab32s(&ghdr->gh_seq);
__swab32s(&ghdr->gh_svc);
__swab32s(&ghdr->gh_pad1);
- __swab32s(&ghdr->gh_pad2);
- __swab32s(&ghdr->gh_pad3);
__swab32s(&ghdr->gh_handle.len);
}
/*
* return signature size, otherwise < 0 to indicate error
*/
-static
-int gss_sign_msg(struct lustre_msg *msg,
- struct gss_ctx *mechctx,
- __u32 proc, __u32 seq, __u32 svc,
- rawobj_t *handle)
+static int gss_sign_msg(struct lustre_msg *msg,
+ struct gss_ctx *mechctx,
+ enum lustre_sec_part sp,
+ __u32 flags, __u32 proc, __u32 seq, __u32 svc,
+ rawobj_t *handle)
{
struct gss_header *ghdr;
rawobj_t text[3], mic;
ghdr = lustre_msg_buf(msg, 0, 0);
ghdr->gh_version = PTLRPC_GSS_VERSION;
- ghdr->gh_flags = 0;
+ ghdr->gh_sp = (__u8) sp;
+ ghdr->gh_flags = flags;
ghdr->gh_proc = proc;
ghdr->gh_seq = seq;
ghdr->gh_svc = svc;
LASSERT(atomic_read(&ctx->cc_refcount));
if (!test_and_set_bit(PTLRPC_CTX_DEAD_BIT, &ctx->cc_flags)) {
- cfs_time_t now;
-
if (!ctx->cc_early_expire)
clear_bit(PTLRPC_CTX_UPTODATE_BIT, &ctx->cc_flags);
- now = cfs_time_current_sec();
- if (ctx->cc_expire && cfs_time_aftereq(now, ctx->cc_expire))
- CWARN("ctx %p(%u->%s): get expired (%lds exceeds)\n",
- ctx, ctx->cc_vcred.vc_uid,
- sec2target_str(ctx->cc_sec),
- cfs_time_sub(now, ctx->cc_expire));
- else
- CWARN("ctx %p(%u->%s): force to die (%lds remains)\n",
- ctx, ctx->cc_vcred.vc_uid,
- sec2target_str(ctx->cc_sec),
- ctx->cc_expire == 0 ? 0 :
- cfs_time_sub(ctx->cc_expire, now));
+ CWARN("ctx %p(%u->%s) get expired: %lu(%+lds)\n",
+ ctx, ctx->cc_vcred.vc_uid, sec2target_str(ctx->cc_sec),
+ ctx->cc_expire,
+ ctx->cc_expire == 0 ? 0 :
+ cfs_time_sub(ctx->cc_expire, cfs_time_current_sec()));
return 1;
}
+
return 0;
}
}
ctx->cc_expire = gss_round_ctx_expiry(ctx_expiry,
- ctx->cc_sec->ps_flags);
+ ctx->cc_sec->ps_flvr.sf_flags);
/* At this point this ctx might have been marked as dead by
* someone else, in which case nobody will make further use
* destroying server side context when it be destroied. */
set_bit(PTLRPC_CTX_UPTODATE_BIT, &ctx->cc_flags);
- if (sec_is_reverse(ctx->cc_sec))
- CDEBUG(D_SEC, "server installed reverse ctx %p, "
- "will expire at %lu(%lds lifetime)\n",
- ctx, ctx->cc_expire,
- ctx->cc_expire - cfs_time_current_sec());
- else
- CWARN("client refreshed ctx %p(%u->%s), will expire at "
- "%lu(%lds lifetime)\n", ctx, ctx->cc_vcred.vc_uid,
- sec2target_str(ctx->cc_sec), ctx->cc_expire,
- ctx->cc_expire - cfs_time_current_sec());
+ if (sec_is_reverse(ctx->cc_sec)) {
+ CWARN("server installed reverse ctx %p idx "LPX64", "
+ "expiry %lu(%+lds)\n", ctx,
+ gss_handle_to_u64(&gctx->gc_handle),
+ ctx->cc_expire, ctx->cc_expire - cfs_time_current_sec());
+ } else {
+ CWARN("client refreshed ctx %p idx "LPX64" (%u->%s), "
+ "expiry %lu(%+lds)\n", ctx,
+ gss_handle_to_u64(&gctx->gc_handle),
+ ctx->cc_vcred.vc_uid, sec2target_str(ctx->cc_sec),
+ ctx->cc_expire, ctx->cc_expire - cfs_time_current_sec());
- /* install reverse svc ctx, but only for forward connection
- * and root context */
- if (!sec_is_reverse(ctx->cc_sec) && ctx->cc_vcred.vc_uid == 0) {
- gss_sec_install_rctx(ctx->cc_sec->ps_import,
- ctx->cc_sec, ctx);
+ /* install reverse svc ctx for root context */
+ if (ctx->cc_vcred.vc_uid == 0)
+ gss_sec_install_rctx(ctx->cc_sec->ps_import,
+ ctx->cc_sec, ctx);
}
}
-static
-void gss_cli_ctx_finalize(struct gss_cli_ctx *gctx)
+static void gss_cli_ctx_finalize(struct gss_cli_ctx *gctx)
{
+ LASSERT(gctx->gc_base.cc_sec);
+
if (gctx->gc_mechctx) {
lgss_delete_sec_context(&gctx->gc_mechctx);
gctx->gc_mechctx = NULL;
}
+ if (!rawobj_empty(&gctx->gc_svc_handle)) {
+ /* forward ctx: mark buddy reverse svcctx soon-expire.
+ * reverse ctx: update current seq to buddy svcctx. */
+ if (!sec_is_reverse(gctx->gc_base.cc_sec))
+ gss_svc_upcall_expire_rvs_ctx(&gctx->gc_svc_handle);
+ else
+ gss_svc_upcall_update_sequence(&gctx->gc_svc_handle,
+ (__u32) atomic_read(&gctx->gc_seq));
+
+ rawobj_free(&gctx->gc_svc_handle);
+ }
+
rawobj_free(&gctx->gc_handle);
}
int gss_cli_ctx_sign(struct ptlrpc_cli_ctx *ctx,
struct ptlrpc_request *req)
{
- struct gss_cli_ctx *gctx;
- __u32 seq, svc;
+ struct gss_cli_ctx *gctx = ctx2gctx(ctx);
+ __u32 flags = 0, seq, svc;
int rc;
ENTRY;
if (req->rq_ctx_init)
RETURN(0);
- gctx = container_of(ctx, struct gss_cli_ctx, gc_base);
- svc = SEC_FLAVOR_SVC(req->rq_sec_flavor);
+ svc = RPC_FLVR_SVC(req->rq_flvr.sf_rpc);
+ if (req->rq_pack_bulk)
+ flags |= LUSTRE_GSS_PACK_BULK;
+ if (req->rq_pack_udesc)
+ flags |= LUSTRE_GSS_PACK_USER;
+
redo:
seq = atomic_inc_return(&gctx->gc_seq);
rc = gss_sign_msg(req->rq_reqbuf, gctx->gc_mechctx,
- gctx->gc_proc, seq, svc,
+ ctx->cc_sec->ps_part,
+ flags, gctx->gc_proc, seq, svc,
&gctx->gc_handle);
if (rc < 0)
RETURN(rc);
} else if (sec_is_reverse(ctx->cc_sec)) {
CWARN("reverse server respond error (%08x/%08x)\n",
errhdr->gh_major, errhdr->gh_minor);
+ sptlrpc_cli_ctx_expire(ctx);
rc = -EINVAL;
} else if (errhdr->gh_major == GSS_S_NO_CONTEXT ||
errhdr->gh_major == GSS_S_BAD_SIG) {
switch (ghdr->gh_proc) {
case PTLRPC_GSS_PROC_DATA:
+ if (!equi(req->rq_pack_bulk == 1,
+ ghdr->gh_flags & LUSTRE_GSS_PACK_BULK)) {
+ CERROR("%s bulk flag in reply\n",
+ req->rq_pack_bulk ? "missing" : "unexpected");
+ RETURN(-EPROTO);
+ }
+
if (ghdr->gh_seq != reqhdr->gh_seq) {
CERROR("seqnum %u mismatch, expect %u\n",
ghdr->gh_seq, reqhdr->gh_seq);
req->rq_repmsg = lustre_msg_buf(msg, 1, 0);
req->rq_replen = msg->lm_buflens[1];
- if (SEC_FLAVOR_HAS_BULK(req->rq_sec_flavor)) {
+ if (req->rq_pack_bulk) {
if (msg->lm_bufcount < 4) {
CERROR("Invalid reply bufcount %u\n",
msg->lm_bufcount);
}
lustre_init_msg_v2(req->rq_reqbuf, 3, buflens, NULL);
- req->rq_reqbuf->lm_secflvr = req->rq_sec_flavor;
+ req->rq_reqbuf->lm_secflvr = req->rq_flvr.sf_rpc;
/* gss header */
ghdr = lustre_msg_buf(req->rq_reqbuf, 0, 0);
ghdr->gh_version = PTLRPC_GSS_VERSION;
+ ghdr->gh_sp = (__u8) ctx->cc_sec->ps_part;
ghdr->gh_flags = 0;
ghdr->gh_proc = gctx->gc_proc;
ghdr->gh_seq = atomic_inc_return(&gctx->gc_seq);
ghdr->gh_svc = SPTLRPC_SVC_PRIV;
ghdr->gh_handle.len = gctx->gc_handle.len;
memcpy(ghdr->gh_handle.data, gctx->gc_handle.data, gctx->gc_handle.len);
+ if (req->rq_pack_bulk)
+ ghdr->gh_flags |= LUSTRE_GSS_PACK_BULK;
+ if (req->rq_pack_udesc)
+ ghdr->gh_flags |= LUSTRE_GSS_PACK_USER;
redo:
/* header signature */
switch (ghdr->gh_proc) {
case PTLRPC_GSS_PROC_DATA:
+ if (!equi(req->rq_pack_bulk == 1,
+ ghdr->gh_flags & LUSTRE_GSS_PACK_BULK)) {
+ CERROR("%s bulk flag in reply\n",
+ req->rq_pack_bulk ? "missing" : "unexpected");
+ RETURN(-EPROTO);
+ }
+
if (lustre_msg_swabbed(req->rq_repbuf))
gss_header_swabber(ghdr);
RETURN(-EPROTO);
}
- if (SEC_FLAVOR_HAS_BULK(req->rq_sec_flavor)) {
+ if (req->rq_pack_bulk) {
if (req->rq_repbuf->lm_bufcount < 2) {
CERROR("Too few request buffer segments %d\n",
req->rq_repbuf->lm_bufcount);
int gss_sec_create_common(struct gss_sec *gsec,
struct ptlrpc_sec_policy *policy,
struct obd_import *imp,
- struct ptlrpc_svc_ctx *ctx,
- __u32 flavor,
- unsigned long flags)
+ struct ptlrpc_svc_ctx *svcctx,
+ struct sptlrpc_flavor *sf)
{
struct ptlrpc_sec *sec;
LASSERT(imp);
- LASSERT(SEC_FLAVOR_POLICY(flavor) == SPTLRPC_POLICY_GSS);
+ LASSERT(RPC_FLVR_POLICY(sf->sf_rpc) == SPTLRPC_POLICY_GSS);
- gsec->gs_mech = lgss_subflavor_to_mech(SEC_FLAVOR_SUB(flavor));
+ gsec->gs_mech = lgss_subflavor_to_mech(RPC_FLVR_SUB(sf->sf_rpc));
if (!gsec->gs_mech) {
- CERROR("gss backend 0x%x not found\n", SEC_FLAVOR_SUB(flavor));
+ CERROR("gss backend 0x%x not found\n",
+ RPC_FLVR_SUB(sf->sf_rpc));
return -EOPNOTSUPP;
}
/* initialize upper ptlrpc_sec */
sec = &gsec->gs_base;
sec->ps_policy = policy;
- sec->ps_flavor = flavor;
- sec->ps_flags = flags;
+ atomic_set(&sec->ps_refcount, 0);
+ atomic_set(&sec->ps_nctx, 0);
+ sec->ps_id = sptlrpc_get_next_secid();
+ sec->ps_flvr = *sf;
sec->ps_import = class_import_get(imp);
sec->ps_lock = SPIN_LOCK_UNLOCKED;
- atomic_set(&sec->ps_busy, 0);
CFS_INIT_LIST_HEAD(&sec->ps_gc_list);
- if (!ctx) {
+ if (!svcctx) {
sec->ps_gc_interval = GSS_GC_INTERVAL;
- sec->ps_gc_next = cfs_time_current_sec() + sec->ps_gc_interval;
} else {
LASSERT(sec_is_reverse(sec));
/* never do gc on reverse sec */
sec->ps_gc_interval = 0;
- sec->ps_gc_next = 0;
}
- if (SEC_FLAVOR_SVC(flavor) == SPTLRPC_SVC_PRIV &&
- flags & PTLRPC_SEC_FL_BULK)
+ if (sec->ps_flvr.sf_bulk_priv != BULK_PRIV_ALG_NULL &&
+ sec->ps_flvr.sf_flags & PTLRPC_SEC_FL_BULK)
sptlrpc_enc_pool_add_user();
- CDEBUG(D_SEC, "create %s%s@%p\n", (ctx ? "reverse " : ""),
+ CDEBUG(D_SEC, "create %s%s@%p\n", (svcctx ? "reverse " : ""),
policy->sp_name, gsec);
return 0;
}
LASSERT(sec->ps_import);
LASSERT(atomic_read(&sec->ps_refcount) == 0);
- LASSERT(atomic_read(&sec->ps_busy) == 0);
+ LASSERT(atomic_read(&sec->ps_nctx) == 0);
if (gsec->gs_mech) {
lgss_mech_put(gsec->gs_mech);
class_import_put(sec->ps_import);
- if (SEC_FLAVOR_SVC(sec->ps_flavor) == SPTLRPC_SVC_PRIV &&
- sec->ps_flags & PTLRPC_SEC_FL_BULK)
+ if (sec->ps_flvr.sf_bulk_priv != BULK_PRIV_ALG_NULL &&
+ sec->ps_flvr.sf_flags & PTLRPC_SEC_FL_BULK)
sptlrpc_enc_pool_del_user();
EXIT;
}
+void gss_sec_kill(struct ptlrpc_sec *sec)
+{
+ sec->ps_dying = 1;
+}
+
int gss_cli_ctx_init_common(struct ptlrpc_sec *sec,
struct ptlrpc_cli_ctx *ctx,
struct ptlrpc_ctx_ops *ctxops,
CFS_INIT_LIST_HEAD(&ctx->cc_req_list);
CFS_INIT_LIST_HEAD(&ctx->cc_gc_chain);
- /* take a ref on belonging sec */
- atomic_inc(&sec->ps_busy);
+ /* take a ref on belonging sec, balanced in ctx destroying */
+ atomic_inc(&sec->ps_refcount);
+ /* statistic only */
+ atomic_inc(&sec->ps_nctx);
CDEBUG(D_SEC, "%s@%p: create ctx %p(%u->%s)\n",
sec->ps_policy->sp_name, ctx->cc_sec,
}
/*
- * return:
- * -1: the destroy has been taken care of by someone else
- * 0: proceed to destroy the ctx
- * 1: busy count dropped to 0, proceed to destroy ctx and sec
+ * return value:
+ * 1: the context has been taken care of by someone else
+ * 0: proceed to really destroy the context locally
*/
int gss_cli_ctx_fini_common(struct ptlrpc_sec *sec,
struct ptlrpc_cli_ctx *ctx)
{
struct gss_cli_ctx *gctx = ctx2gctx(ctx);
- LASSERT(ctx->cc_sec == sec);
+ LASSERT(atomic_read(&sec->ps_nctx) > 0);
LASSERT(atomic_read(&ctx->cc_refcount) == 0);
- LASSERT(atomic_read(&sec->ps_busy) > 0);
+ LASSERT(ctx->cc_sec == sec);
if (gctx->gc_mechctx) {
/* the final context fini rpc will use this ctx too, and it's
gss_cli_ctx_finalize(gctx);
if (!atomic_dec_and_test(&ctx->cc_refcount))
- return -1;
+ return 1;
}
if (sec_is_reverse(sec))
- CDEBUG(D_SEC, "reverse sec %p: destroy ctx %p\n",
- ctx->cc_sec, ctx);
+ CWARN("reverse sec %p: destroy ctx %p\n",
+ ctx->cc_sec, ctx);
else
CWARN("%s@%p: destroy ctx %p(%u->%s)\n",
sec->ps_policy->sp_name, ctx->cc_sec,
ctx, ctx->cc_vcred.vc_uid, sec2target_str(ctx->cc_sec));
- if (atomic_dec_and_test(&sec->ps_busy)) {
- LASSERT(atomic_read(&sec->ps_refcount) == 0);
- return 1;
- }
-
return 0;
}
struct ptlrpc_request *req,
int svc, int msgsize)
{
- struct sec_flavor_config *conf;
int bufsize, txtsize;
int buflens[5], bufcnt = 2;
ENTRY;
if (svc == SPTLRPC_SVC_INTG)
txtsize += buflens[1];
- if (SEC_FLAVOR_HAS_USER(req->rq_sec_flavor)) {
+ if (req->rq_pack_udesc) {
buflens[bufcnt] = sptlrpc_current_user_desc_size();
if (svc == SPTLRPC_SVC_INTG)
txtsize += buflens[bufcnt];
bufcnt++;
}
- if (SEC_FLAVOR_HAS_BULK(req->rq_sec_flavor)) {
- conf = &req->rq_import->imp_obd->u.cli.cl_sec_conf;
- buflens[bufcnt] = bulk_sec_desc_size(conf->sfc_bulk_csum, 1,
- req->rq_bulk_read);
+ if (req->rq_pack_bulk) {
+ buflens[bufcnt] = bulk_sec_desc_size(
+ req->rq_flvr.sf_bulk_csum, 1,
+ req->rq_bulk_read);
if (svc == SPTLRPC_SVC_INTG)
txtsize += buflens[bufcnt];
bufcnt++;
}
lustre_init_msg_v2(req->rq_reqbuf, bufcnt, buflens, NULL);
- req->rq_reqbuf->lm_secflvr = req->rq_sec_flavor;
+ req->rq_reqbuf->lm_secflvr = req->rq_flvr.sf_rpc;
req->rq_reqmsg = lustre_msg_buf(req->rq_reqbuf, 1, msgsize);
LASSERT(req->rq_reqmsg);
/* pack user desc here, later we might leave current user's process */
- if (SEC_FLAVOR_HAS_USER(req->rq_sec_flavor))
+ if (req->rq_pack_udesc)
sptlrpc_pack_user_desc(req->rq_reqbuf, 2);
RETURN(0);
struct ptlrpc_request *req,
int msgsize)
{
- struct sec_flavor_config *conf;
int ibuflens[3], ibufcnt;
int buflens[3];
int clearsize, wiresize;
ibufcnt = 1;
ibuflens[0] = msgsize;
- if (SEC_FLAVOR_HAS_USER(req->rq_sec_flavor))
+ if (req->rq_pack_udesc)
ibuflens[ibufcnt++] = sptlrpc_current_user_desc_size();
- if (SEC_FLAVOR_HAS_BULK(req->rq_sec_flavor)) {
- conf = &req->rq_import->imp_obd->u.cli.cl_sec_conf;
- ibuflens[ibufcnt++] = bulk_sec_desc_size(conf->sfc_bulk_csum, 1,
- req->rq_bulk_read);
- }
+ if (req->rq_pack_bulk)
+ ibuflens[ibufcnt++] = bulk_sec_desc_size(
+ req->rq_flvr.sf_bulk_csum, 1,
+ req->rq_bulk_read);
+
clearsize = lustre_msg_size_v2(ibufcnt, ibuflens);
/* to allow append padding during encryption */
clearsize += GSS_MAX_CIPHER_BLOCK;
lustre_init_msg_v2(req->rq_clrbuf, ibufcnt, ibuflens, NULL);
req->rq_reqmsg = lustre_msg_buf(req->rq_clrbuf, 0, msgsize);
- if (SEC_FLAVOR_HAS_USER(req->rq_sec_flavor))
+ if (req->rq_pack_udesc)
sptlrpc_pack_user_desc(req->rq_clrbuf, 1);
RETURN(0);
struct ptlrpc_request *req,
int msgsize)
{
- int svc = SEC_FLAVOR_SVC(req->rq_sec_flavor);
+ int svc = RPC_FLVR_SVC(req->rq_flvr.sf_rpc);
- LASSERT(!SEC_FLAVOR_HAS_BULK(req->rq_sec_flavor) ||
+ LASSERT(!req->rq_pack_bulk ||
(req->rq_bulk_read || req->rq_bulk_write));
switch (svc) {
case SPTLRPC_SVC_PRIV:
return gss_alloc_reqbuf_priv(sec, req, msgsize);
default:
- LASSERTF(0, "bad flavor %x\n", req->rq_sec_flavor);
+ LASSERTF(0, "bad rpc flavor %x\n", req->rq_flvr.sf_rpc);
return 0;
}
}
ENTRY;
LASSERT(!req->rq_pool || req->rq_reqbuf);
- privacy = SEC_FLAVOR_SVC(req->rq_sec_flavor) == SPTLRPC_SVC_PRIV;
+ privacy = RPC_FLVR_SVC(req->rq_flvr.sf_rpc) == SPTLRPC_SVC_PRIV;
if (!req->rq_clrbuf)
goto release_reqbuf;
release_reqbuf:
if (!req->rq_pool && req->rq_reqbuf) {
+ LASSERT(req->rq_reqbuf_len);
+
OBD_FREE(req->rq_reqbuf, req->rq_reqbuf_len);
req->rq_reqbuf = NULL;
req->rq_reqbuf_len = 0;
}
+ req->rq_reqmsg = NULL;
+
EXIT;
}
struct ptlrpc_request *req,
int svc, int msgsize)
{
- struct sec_flavor_config *conf;
int txtsize;
int buflens[4], bufcnt = 2;
if (svc == SPTLRPC_SVC_INTG)
txtsize += buflens[1];
- if (SEC_FLAVOR_HAS_BULK(req->rq_sec_flavor)) {
- conf = &req->rq_import->imp_obd->u.cli.cl_sec_conf;
- buflens[bufcnt] = bulk_sec_desc_size(conf->sfc_bulk_csum, 0,
- req->rq_bulk_read);
+ if (req->rq_pack_bulk) {
+ buflens[bufcnt] = bulk_sec_desc_size(
+ req->rq_flvr.sf_bulk_csum, 0,
+ req->rq_bulk_read);
if (svc == SPTLRPC_SVC_INTG)
txtsize += buflens[bufcnt];
bufcnt++;
struct ptlrpc_request *req,
int msgsize)
{
- struct sec_flavor_config *conf;
int txtsize;
int buflens[3], bufcnt;
bufcnt = 1;
buflens[0] = msgsize;
- if (SEC_FLAVOR_HAS_BULK(req->rq_sec_flavor)) {
- conf = &req->rq_import->imp_obd->u.cli.cl_sec_conf;
+ if (req->rq_pack_bulk) {
buflens[bufcnt++] = bulk_sec_desc_size(
- conf->sfc_bulk_csum, 0,
+ req->rq_flvr.sf_bulk_csum, 0,
req->rq_bulk_read);
}
txtsize = lustre_msg_size_v2(bufcnt, buflens);
struct ptlrpc_request *req,
int msgsize)
{
- int svc = SEC_FLAVOR_SVC(req->rq_sec_flavor);
+ int svc = RPC_FLVR_SVC(req->rq_flvr.sf_rpc);
ENTRY;
- LASSERT(!SEC_FLAVOR_HAS_BULK(req->rq_sec_flavor) ||
+ LASSERT(!req->rq_pack_bulk ||
(req->rq_bulk_read || req->rq_bulk_write));
switch (svc) {
case SPTLRPC_SVC_PRIV:
return gss_alloc_repbuf_priv(sec, req, msgsize);
default:
- LASSERTF(0, "bad flavor %x\n", req->rq_sec_flavor);
+ LASSERTF(0, "bad rpc flavor %x\n", req->rq_flvr.sf_rpc);
return 0;
}
}
OBD_FREE(req->rq_repbuf, req->rq_repbuf_len);
req->rq_repbuf = NULL;
req->rq_repbuf_len = 0;
+
+ req->rq_repmsg = NULL;
}
static int get_enlarged_msgsize(struct lustre_msg *msg,
struct ptlrpc_request *req,
int segment, int newsize)
{
- int svc = SEC_FLAVOR_SVC(req->rq_sec_flavor);
+ int svc = RPC_FLVR_SVC(req->rq_flvr.sf_rpc);
LASSERT(!req->rq_ctx_init && !req->rq_ctx_fini);
case SPTLRPC_SVC_PRIV:
return gss_enlarge_reqbuf_priv(sec, req, segment, newsize);
default:
- LASSERTF(0, "bad flavor %x\n", req->rq_sec_flavor);
+ LASSERTF(0, "bad rpc flavor %x\n", req->rq_flvr.sf_rpc);
return 0;
}
}
int gss_svc_sign(struct ptlrpc_request *req,
struct ptlrpc_reply_state *rs,
struct gss_svc_reqctx *grctx,
- int svc)
+ __u32 svc)
{
+ __u32 flags = 0;
int rc;
ENTRY;
if (req->rq_replen != rs->rs_repbuf->lm_buflens[1])
lustre_shrink_msg(rs->rs_repbuf, 1, req->rq_replen, 1);
+ if (req->rq_pack_bulk)
+ flags |= LUSTRE_GSS_PACK_BULK;
+
rc = gss_sign_msg(rs->rs_repbuf, grctx->src_ctx->gsc_mechctx,
- PTLRPC_GSS_PROC_DATA, grctx->src_wirectx.gw_seq,
- svc, NULL);
+ LUSTRE_SP_ANY, flags, PTLRPC_GSS_PROC_DATA,
+ grctx->src_wirectx.gw_seq, svc, NULL);
if (rc < 0)
RETURN(rc);
req->rq_ctx_init = 1;
+ if (gw->gw_flags & LUSTRE_GSS_PACK_BULK) {
+ CERROR("unexpected bulk flag\n");
+ RETURN(SECSVC_DROP);
+ }
+
if (gw->gw_proc == PTLRPC_GSS_PROC_INIT && gw->gw_handle.len != 0) {
CERROR("proc %u: invalid handle length %u\n",
gw->gw_proc, gw->gw_handle.len);
uuid = (struct obd_uuid *) uuid_obj.data;
target = class_uuid2obd(uuid);
if (!target || target->obd_stopping || !target->obd_set_up) {
- CERROR("target '%s' is not available for context init (%s)",
+ CERROR("target '%s' is not available for context init (%s)\n",
uuid->uuid, target == NULL ? "no target" :
(target->obd_stopping ? "stopping" : "not set up"));
RETURN(SECSVC_DROP);
RETURN(rc);
if (grctx->src_ctx->gsc_usr_mds || grctx->src_ctx->gsc_usr_root)
- CWARN("user from %s authenticated as %s\n",
- libcfs_nid2str(req->rq_peer.nid),
+ CWARN("create svc ctx %p: user from %s authenticated as %s\n",
+ grctx->src_ctx, libcfs_nid2str(req->rq_peer.nid),
grctx->src_ctx->gsc_usr_mds ? "mds" : "root");
else
- CWARN("accept user %u from %s\n", grctx->src_ctx->gsc_uid,
+ CWARN("create svc ctx %p: accept user %u from %s\n",
+ grctx->src_ctx, grctx->src_ctx->gsc_uid,
libcfs_nid2str(req->rq_peer.nid));
- if (SEC_FLAVOR_HAS_USER(req->rq_sec_flavor)) {
+ if (gw->gw_flags & LUSTRE_GSS_PACK_USER) {
if (reqbuf->lm_bufcount < 4) {
CERROR("missing user descriptor\n");
RETURN(SECSVC_DROP);
CERROR("Mal-formed user descriptor\n");
RETURN(SECSVC_DROP);
}
+
+ req->rq_pack_udesc = 1;
req->rq_user_desc = lustre_msg_buf(reqbuf, 2, 0);
}
if (*major != GSS_S_COMPLETE)
RETURN(-EACCES);
- if (gss_check_seq_num(&gctx->gsc_seqdata, gw->gw_seq, 1)) {
+ if (gctx->gsc_reverse == 0 &&
+ gss_check_seq_num(&gctx->gsc_seqdata, gw->gw_seq, 1)) {
CERROR("phase 1+: discard replayed req: seq %u\n", gw->gw_seq);
*major = GSS_S_DUPLICATE_TOKEN;
RETURN(-EACCES);
verified:
/* user descriptor */
- if (SEC_FLAVOR_HAS_USER(req->rq_sec_flavor)) {
+ if (gw->gw_flags & LUSTRE_GSS_PACK_USER) {
if (msg->lm_bufcount < (offset + 1)) {
CERROR("no user desc included\n");
RETURN(-EINVAL);
RETURN(-EINVAL);
}
+ req->rq_pack_udesc = 1;
req->rq_user_desc = lustre_msg_buf(msg, offset, 0);
offset++;
}
/* check bulk cksum data */
- if (SEC_FLAVOR_HAS_BULK(req->rq_sec_flavor)) {
+ if (gw->gw_flags & LUSTRE_GSS_PACK_BULK) {
if (msg->lm_bufcount < (offset + 1)) {
CERROR("no bulk checksum included\n");
RETURN(-EINVAL);
if (bulk_sec_desc_unpack(msg, offset))
RETURN(-EINVAL);
+ req->rq_pack_bulk = 1;
grctx->src_reqbsd = lustre_msg_buf(msg, offset, 0);
grctx->src_reqbsd_size = lustre_msg_buflen(msg, offset);
}
RETURN(-EINVAL);
}
- if (SEC_FLAVOR_HAS_USER(req->rq_sec_flavor)) {
+ if (gw->gw_flags & LUSTRE_GSS_PACK_USER) {
if (msg->lm_bufcount < offset + 1) {
CERROR("no user descriptor included\n");
RETURN(-EINVAL);
RETURN(-EINVAL);
}
+ req->rq_pack_udesc = 1;
req->rq_user_desc = lustre_msg_buf(msg, offset, 0);
offset++;
}
- if (SEC_FLAVOR_HAS_BULK(req->rq_sec_flavor)) {
+ if (gw->gw_flags & LUSTRE_GSS_PACK_BULK) {
if (msg->lm_bufcount < offset + 1) {
CERROR("no bulk checksum included\n");
RETURN(-EINVAL);
if (bulk_sec_desc_unpack(msg, offset))
RETURN(-EINVAL);
+ req->rq_pack_bulk = 1;
grctx->src_reqbsd = lustre_msg_buf(msg, offset, 0);
grctx->src_reqbsd_size = lustre_msg_buflen(msg, offset);
}
grctx->src_ctx = gss_svc_upcall_get_ctx(req, gw);
if (!grctx->src_ctx) {
- CWARN("invalid gss context handle for destroy.\n");
+ CDEBUG(D_SEC, "invalid gss context handle for destroy.\n");
RETURN(SECSVC_DROP);
}
if (gss_svc_verify_request(req, grctx, gw, &major))
RETURN(SECSVC_DROP);
- CWARN("destroy svc ctx %p(%u->%s)\n", grctx->src_ctx,
- grctx->src_ctx->gsc_uid, libcfs_nid2str(req->rq_peer.nid));
+ CWARN("destroy svc ctx %p idx "LPX64" (%u->%s)\n",
+ grctx->src_ctx, gss_handle_to_u64(&gw->gw_handle),
+ grctx->src_ctx->gsc_uid, libcfs_nid2str(req->rq_peer.nid));
gss_svc_upcall_destroy_ctx(grctx->src_ctx);
- if (SEC_FLAVOR_HAS_USER(req->rq_sec_flavor)) {
+ if (gw->gw_flags & LUSTRE_GSS_PACK_USER) {
if (req->rq_reqbuf->lm_bufcount < 4) {
CERROR("missing user descriptor, ignore it\n");
RETURN(SECSVC_OK);
CERROR("Mal-formed user descriptor, ignore it\n");
RETURN(SECSVC_OK);
}
+
+ req->rq_pack_udesc = 1;
req->rq_user_desc = lustre_msg_buf(req->rq_reqbuf, 2, 0);
}
RETURN(SECSVC_DROP);
}
+ req->rq_sp_from = ghdr->gh_sp;
+
/* alloc grctx data */
OBD_ALLOC_PTR(grctx);
if (!grctx) {
gw = &grctx->src_wirectx;
/* save wire context */
+ gw->gw_flags = ghdr->gh_flags;
gw->gw_proc = ghdr->gh_proc;
gw->gw_seq = ghdr->gh_seq;
gw->gw_svc = ghdr->gh_svc;
LASSERT(msglen % 8 == 0);
- if (SEC_FLAVOR_HAS_BULK(req->rq_sec_flavor) &&
- !req->rq_bulk_read && !req->rq_bulk_write) {
+ if (req->rq_pack_bulk && !req->rq_bulk_read && !req->rq_bulk_write) {
CERROR("client request bulk sec on non-bulk rpc\n");
RETURN(-EPROTO);
}
- svc = SEC_FLAVOR_SVC(req->rq_sec_flavor);
+ svc = RPC_FLVR_SVC(req->rq_flvr.sf_rpc);
grctx = gss_svc_ctx2reqctx(req->rq_svc_ctx);
if (gss_svc_reqctx_is_special(grctx))
ibufcnt = 1;
ibuflens[0] = msglen;
- if (SEC_FLAVOR_HAS_BULK(req->rq_sec_flavor)) {
+ if (req->rq_pack_bulk) {
LASSERT(grctx->src_reqbsd);
bsd_off = ibufcnt;
if (svc == SPTLRPC_SVC_INTG)
txtsize += buflens[1];
- if (SEC_FLAVOR_HAS_BULK(req->rq_sec_flavor)) {
+ if (req->rq_pack_bulk) {
LASSERT(grctx->src_reqbsd);
bsd_off = bufcnt;
rs->rs_msg = lustre_msg_buf(rs->rs_repbuf, 0, msglen);
} else {
lustre_init_msg_v2(rs->rs_repbuf, bufcnt, buflens, NULL);
- rs->rs_repbuf->lm_secflvr = req->rq_sec_flavor;
+ rs->rs_repbuf->lm_secflvr = req->rq_flvr.sf_rpc;
rs->rs_msg = lustre_msg_buf(rs->rs_repbuf, 1, 0);
}
LASSERT(lustre_msg_size_v2(3, buflens) <= rs->rs_repbuf_len);
lustre_init_msg_v2(rs->rs_repbuf, 3, buflens, NULL);
- rs->rs_repbuf->lm_secflvr = req->rq_sec_flavor;
+ rs->rs_repbuf->lm_secflvr = req->rq_flvr.sf_rpc;
/* gss header */
ghdr = lustre_msg_buf(rs->rs_repbuf, 0, 0);
ghdr->gh_seq = grctx->src_wirectx.gw_seq;
ghdr->gh_svc = SPTLRPC_SVC_PRIV;
ghdr->gh_handle.len = 0;
+ if (req->rq_pack_bulk)
+ ghdr->gh_flags |= LUSTRE_GSS_PACK_BULK;
/* header signature */
msgobj.len = rs->rs_repbuf->lm_buflens[0];
struct ptlrpc_svc_ctx *svc_ctx)
{
struct gss_cli_ctx *cli_gctx = ctx2gctx(cli_ctx);
- struct gss_svc_reqctx *grctx;
+ struct gss_svc_ctx *svc_gctx = gss_svc_ctx2gssctx(svc_ctx);
struct gss_ctx *mechctx = NULL;
+ LASSERT(cli_gctx);
+ LASSERT(svc_gctx && svc_gctx->gsc_mechctx);
+
cli_gctx->gc_proc = PTLRPC_GSS_PROC_DATA;
cli_gctx->gc_win = GSS_SEQ_WIN;
- atomic_set(&cli_gctx->gc_seq, 0);
- grctx = container_of(svc_ctx, struct gss_svc_reqctx, src_base);
- LASSERT(grctx->src_ctx);
- LASSERT(grctx->src_ctx->gsc_mechctx);
+ /* The problem is the reverse ctx might get lost in some recovery
+ * situations, and the same svc_ctx will be used to re-create it.
+ * if there's callback be sentout before that, new reverse ctx start
+ * with sequence 0 will lead to future callback rpc be treated as
+ * replay.
+ *
+ * each reverse root ctx will record its latest sequence number on its
+ * buddy svcctx before be destroied, so here we continue use it.
+ */
+ atomic_set(&cli_gctx->gc_seq, svc_gctx->gsc_rvs_seq);
+
+ if (gss_svc_upcall_dup_handle(&cli_gctx->gc_svc_handle, svc_gctx)) {
+ CERROR("failed to dup svc handle\n");
+ goto err_out;
+ }
- if (lgss_copy_reverse_context(grctx->src_ctx->gsc_mechctx, &mechctx) !=
+ if (lgss_copy_reverse_context(svc_gctx->gsc_mechctx, &mechctx) !=
GSS_S_COMPLETE) {
CERROR("failed to copy mech context\n");
- return -ENOMEM;
+ goto err_svc_handle;
}
- if (rawobj_dup(&cli_gctx->gc_handle, &grctx->src_ctx->gsc_rvs_hdl)) {
+ if (rawobj_dup(&cli_gctx->gc_handle, &svc_gctx->gsc_rvs_hdl)) {
CERROR("failed to dup reverse handle\n");
- lgss_delete_sec_context(&mechctx);
- return -ENOMEM;
+ goto err_ctx;
}
cli_gctx->gc_mechctx = mechctx;
gss_cli_ctx_uptodate(cli_gctx);
return 0;
+
+err_ctx:
+ lgss_delete_sec_context(&mechctx);
+err_svc_handle:
+ rawobj_free(&cli_gctx->gc_svc_handle);
+err_out:
+ return -ENOMEM;
}
int __init sptlrpc_gss_init(void)
}
}
+ rc = sptlrpc_import_sec_adapt(imp, NULL, 0);
+ if (rc)
+ GOTO(out, rc);
+
/* Reset connect flags to the originally requested flags, in case
* the server is updated on-the-fly we will get the new features. */
imp->imp_connect_data.ocd_connect_flags = imp->imp_connect_flags_orig;
- rc = obd_reconnect(imp->imp_obd->obd_self_export, obd,
+ rc = obd_reconnect(NULL, imp->imp_obd->obd_self_export, obd,
&obd->obd_uuid, &imp->imp_connect_data);
if (rc)
GOTO(out, rc);
struct obd_connect_data *ocd;
/* reply message might not be ready */
- if (request->rq_repmsg != NULL)
+ if (request->rq_repmsg == NULL)
RETURN(-EPROTO);
ocd = lustre_swab_repbuf(request, REPLY_REC_OFF,
};
static const struct req_msg_field *mds_setxattr_server[] = {
- &RMF_PTLRPC_BODY,
- &RMF_EADATA
+ &RMF_PTLRPC_BODY
};
static const struct req_msg_field *mds_getattr_server[] = {
int rc;
/* We must already have a reply buffer (only ptlrpc_error() may be
- * called without one). The reply generated by security layer (e.g.
+ * called without one). The reply generated by sptlrpc layer (e.g.
* error notify, etc.) might have NULL rq->reqmsg; Otherwise we must
* have a request buffer which is either the actual (swabbed) incoming
* request, or a saved copy if this is a req saved in
* target_queue_final_reply().
*/
+ LASSERT (req->rq_no_reply == 0);
LASSERT (req->rq_reqbuf != NULL);
LASSERT (rs != NULL);
LASSERT (may_be_difficult || !rs->rs_difficult);
int ptlrpc_reply (struct ptlrpc_request *req)
{
- return (ptlrpc_send_reply (req, 0));
+ if (req->rq_no_reply)
+ return 0;
+ else
+ return (ptlrpc_send_reply(req, 0));
}
int ptlrpc_error(struct ptlrpc_request *req)
int rc;
ENTRY;
+ if (req->rq_no_reply)
+ RETURN(0);
+
if (!req->rq_repmsg) {
rc = lustre_pack_reply(req, 1, NULL, NULL);
if (rc)
LASSERT(count > 0);
LASSERT(lens[MSG_PTLRPC_BODY_OFF] == sizeof(struct ptlrpc_body));
- /* if we choose policy other than null, we have also choosed
- * to use new message format.
- */
- if (magic == LUSTRE_MSG_MAGIC_V1 &&
- req->rq_sec_flavor != SPTLRPC_FLVR_NULL)
- magic = LUSTRE_MSG_MAGIC_V2;
+ /* only use new format, we don't need to be compatible with 1.4 */
+ magic = LUSTRE_MSG_MAGIC_V2;
switch (magic) {
case LUSTRE_MSG_MAGIC_V1:
void sptlrpc_enc_pool_fini(void);
int sptlrpc_proc_read_enc_pool(char *page, char **start, off_t off, int count,
int *eof, void *data);
-const char * sptlrpc_bulk_csum_alg2name(__u32 csum_alg);
/* sec_lproc.c */
int sptlrpc_lproc_init(void);
/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
* vim:expandtab:shiftwidth=8:tabstop=8:
*
- * Copyright (C) 2004-2006 Cluster File Systems, Inc.
+ * Copyright (C) 2004-2007 Cluster File Systems, Inc.
+ * Author: Eric Mei <ericm@clusterfs.com>
*
* This file is part of Lustre, http://www.lustre.org.
*
int sptlrpc_register_policy(struct ptlrpc_sec_policy *policy)
{
- __u32 number = policy->sp_policy;
+ __u16 number = policy->sp_policy;
LASSERT(policy->sp_name);
LASSERT(policy->sp_cops);
int sptlrpc_unregister_policy(struct ptlrpc_sec_policy *policy)
{
- __u32 number = policy->sp_policy;
+ __u16 number = policy->sp_policy;
LASSERT(number < SPTLRPC_POLICY_MAX);
EXPORT_SYMBOL(sptlrpc_unregister_policy);
static
-struct ptlrpc_sec_policy * sptlrpc_flavor2policy(ptlrpc_sec_flavor_t flavor)
+struct ptlrpc_sec_policy * sptlrpc_rpcflavor2policy(__u16 flavor)
{
-#ifdef CONFIG_KMOD
static DECLARE_MUTEX(load_mutex);
-#endif
- static atomic_t loaded = ATOMIC_INIT(0);
- struct ptlrpc_sec_policy *policy;
- __u32 number = SEC_FLAVOR_POLICY(flavor), flag = 0;
+ static atomic_t loaded = ATOMIC_INIT(0);
+ struct ptlrpc_sec_policy *policy;
+ __u16 number = RPC_FLVR_POLICY(flavor), flag = 0;
if (number >= SPTLRPC_POLICY_MAX)
return NULL;
-#ifdef CONFIG_KMOD
again:
-#endif
read_lock(&policy_lock);
policy = policies[number];
if (policy && !try_module_get(policy->sp_owner))
flag = atomic_read(&loaded);
read_unlock(&policy_lock);
-#ifdef CONFIG_KMOD
/* if failure, try to load gss module, once */
- if (unlikely(policy == NULL) &&
- flag == 0 &&
- (number == SPTLRPC_POLICY_GSS ||
- number == SPTLRPC_POLICY_GSS_PIPEFS)) {
+ if (unlikely(policy == NULL) && flag == 0 &&
+ number == SPTLRPC_POLICY_GSS) {
mutex_down(&load_mutex);
if (atomic_read(&loaded) == 0) {
if (request_module("ptlrpc_gss") != 0)
CERROR("Unable to load module ptlrpc_gss\n");
else
- CWARN("module ptlrpc_gss loaded\n");
+ CWARN("module ptlrpc_gss loaded on demand\n");
atomic_set(&loaded, 1);
}
goto again;
}
-#endif
return policy;
}
-ptlrpc_sec_flavor_t sptlrpc_name2flavor(const char *name)
+__u16 sptlrpc_name2rpcflavor(const char *name)
{
if (!strcmp(name, "null"))
return SPTLRPC_FLVR_NULL;
return SPTLRPC_FLVR_INVALID;
}
-EXPORT_SYMBOL(sptlrpc_name2flavor);
+EXPORT_SYMBOL(sptlrpc_name2rpcflavor);
-char *sptlrpc_flavor2name(ptlrpc_sec_flavor_t flavor)
+const char *sptlrpc_rpcflavor2name(__u16 flavor)
{
switch (flavor) {
case SPTLRPC_FLVR_NULL:
case SPTLRPC_FLVR_KRB5P:
return "krb5p";
default:
- CERROR("invalid flavor 0x%x(p%u,s%u,v%u)\n", flavor,
- SEC_FLAVOR_POLICY(flavor), SEC_FLAVOR_MECH(flavor),
- SEC_FLAVOR_SVC(flavor));
+ CERROR("invalid rpc flavor 0x%x(p%u,s%u,v%u)\n", flavor,
+ RPC_FLVR_POLICY(flavor), RPC_FLVR_MECH(flavor),
+ RPC_FLVR_SVC(flavor));
}
- return "UNKNOWN";
+ return "unknown";
+}
+EXPORT_SYMBOL(sptlrpc_rpcflavor2name);
+
+int sptlrpc_flavor2name(struct sptlrpc_flavor *sf, char *buf, int bufsize)
+{
+ char *bulk;
+
+ if (sf->sf_bulk_priv != BULK_PRIV_ALG_NULL)
+ bulk = "bulkp";
+ else if (sf->sf_bulk_csum != BULK_CSUM_ALG_NULL)
+ bulk = "bulki";
+ else
+ bulk = "bulkn";
+
+ snprintf(buf, bufsize, "%s-%s:%s/%s",
+ sptlrpc_rpcflavor2name(sf->sf_rpc), bulk,
+ sptlrpc_bulk_csum_alg2name(sf->sf_bulk_csum),
+ sptlrpc_bulk_priv_alg2name(sf->sf_bulk_priv));
+ return 0;
}
EXPORT_SYMBOL(sptlrpc_flavor2name);
LASSERT(sec);
LASSERT(sec->ps_policy->sp_cops->lookup_ctx);
- if (sec->ps_flags & (PTLRPC_SEC_FL_REVERSE | PTLRPC_SEC_FL_ROOTONLY)) {
+ if (sec->ps_flvr.sf_flags & (PTLRPC_SEC_FL_REVERSE |
+ PTLRPC_SEC_FL_ROOTONLY)) {
vcred.vc_uid = 0;
vcred.vc_gid = 0;
- if (sec->ps_flags & PTLRPC_SEC_FL_REVERSE) {
+ if (sec->ps_flvr.sf_flags & PTLRPC_SEC_FL_REVERSE) {
create = 0;
remove_dead = 0;
}
return ctx->cc_ops->display(ctx, buf, bufsize);
}
+static int sptlrpc_import_sec_check_expire(struct obd_import *imp)
+{
+ int adapt = 0;
+
+ spin_lock(&imp->imp_lock);
+ if (imp->imp_sec_expire &&
+ imp->imp_sec_expire < cfs_time_current_sec()) {
+ adapt = 1;
+ imp->imp_sec_expire = 0;
+ }
+ spin_unlock(&imp->imp_lock);
+
+ if (!adapt)
+ return 0;
+
+ CDEBUG(D_SEC, "found delayed sec adapt expired, do it now\n");
+ return sptlrpc_import_sec_adapt(imp, NULL, 0);
+}
+
int sptlrpc_req_get_ctx(struct ptlrpc_request *req)
{
struct obd_import *imp = req->rq_import;
+ struct ptlrpc_sec *sec;
+ int rc;
ENTRY;
LASSERT(!req->rq_cli_ctx);
LASSERT(imp);
- if (imp->imp_sec == NULL) {
- CERROR("import %p (%s) with no sec pointer\n",
+ if (unlikely(imp->imp_sec_expire)) {
+ rc = sptlrpc_import_sec_check_expire(imp);
+ if (rc)
+ RETURN(rc);
+ }
+
+ sec = sptlrpc_import_sec_ref(imp);
+ if (sec == NULL) {
+ CERROR("import %p (%s) with no ptlrpc_sec\n",
imp, ptlrpc_import_state_name(imp->imp_state));
RETURN(-EACCES);
}
- req->rq_cli_ctx = get_my_ctx(imp->imp_sec);
+ if (unlikely(sec->ps_dying)) {
+ CERROR("attempt to use dying sec %p\n", sec);
+ return -EACCES;
+ }
+
+ req->rq_cli_ctx = get_my_ctx(sec);
+
+ sptlrpc_sec_put(sec);
if (!req->rq_cli_ctx) {
CERROR("req %p: fail to get context\n", req);
EXIT;
}
+static
+int sptlrpc_req_ctx_switch(struct ptlrpc_request *req,
+ struct ptlrpc_cli_ctx *oldctx,
+ struct ptlrpc_cli_ctx *newctx)
+{
+ struct sptlrpc_flavor old_flvr;
+ char *reqmsg;
+ int reqmsg_size;
+ int rc;
+
+ if (likely(oldctx->cc_sec == newctx->cc_sec))
+ return 0;
+
+ LASSERT(req->rq_reqmsg);
+ LASSERT(req->rq_reqlen);
+ LASSERT(req->rq_replen);
+
+ CWARN("req %p: switch ctx %p -> %p, switch sec %p(%s) -> %p(%s)\n",
+ req, oldctx, newctx,
+ oldctx->cc_sec, oldctx->cc_sec->ps_policy->sp_name,
+ newctx->cc_sec, newctx->cc_sec->ps_policy->sp_name);
+
+ /* save flavor */
+ old_flvr = req->rq_flvr;
+
+ /* save request message */
+ reqmsg_size = req->rq_reqlen;
+ OBD_ALLOC(reqmsg, reqmsg_size);
+ if (reqmsg == NULL)
+ return -ENOMEM;
+ memcpy(reqmsg, req->rq_reqmsg, reqmsg_size);
+
+ /* release old req/rep buf */
+ req->rq_cli_ctx = oldctx;
+ sptlrpc_cli_free_reqbuf(req);
+ sptlrpc_cli_free_repbuf(req);
+ req->rq_cli_ctx = newctx;
+
+ /* recalculate the flavor */
+ sptlrpc_req_set_flavor(req, 0);
+
+ /* alloc new request buffer
+ * we don't need to alloc reply buffer here, leave it to the
+ * rest procedure of ptlrpc
+ */
+ rc = sptlrpc_cli_alloc_reqbuf(req, reqmsg_size);
+ if (!rc) {
+ LASSERT(req->rq_reqmsg);
+ memcpy(req->rq_reqmsg, reqmsg, reqmsg_size);
+ } else {
+ CWARN("failed to alloc reqbuf: %d\n", rc);
+ req->rq_flvr = old_flvr;
+ }
+
+ OBD_FREE(reqmsg, reqmsg_size);
+ return rc;
+}
+
/*
- * request must have a context. if failed to get new context,
- * just restore the old one
+ * request must have a context. in any case of failure, restore the
+ * restore the old one. a request must have a ctx.
*/
int sptlrpc_req_replace_dead_ctx(struct ptlrpc_request *req)
{
- struct ptlrpc_cli_ctx *ctx = req->rq_cli_ctx;
- int rc;
+ struct ptlrpc_cli_ctx *oldctx = req->rq_cli_ctx;
+ struct ptlrpc_cli_ctx *newctx;
+ int rc;
ENTRY;
- LASSERT(ctx);
- LASSERT(test_bit(PTLRPC_CTX_DEAD_BIT, &ctx->cc_flags));
-
- /* make sure not on context waiting list */
- spin_lock(&ctx->cc_lock);
- list_del_init(&req->rq_ctx_chain);
- spin_unlock(&ctx->cc_lock);
+ LASSERT(oldctx);
+ LASSERT(test_bit(PTLRPC_CTX_DEAD_BIT, &oldctx->cc_flags));
- sptlrpc_cli_ctx_get(ctx);
+ sptlrpc_cli_ctx_get(oldctx);
sptlrpc_req_put_ctx(req, 0);
+
rc = sptlrpc_req_get_ctx(req);
- if (!rc) {
- LASSERT(req->rq_cli_ctx);
- sptlrpc_cli_ctx_put(ctx, 1);
- } else {
+ if (unlikely(rc)) {
LASSERT(!req->rq_cli_ctx);
- req->rq_cli_ctx = ctx;
+
+ /* restore old ctx */
+ req->rq_cli_ctx = oldctx;
+ RETURN(rc);
}
- RETURN(rc);
+
+ newctx = req->rq_cli_ctx;
+ LASSERT(newctx);
+
+ if (unlikely(newctx == oldctx)) {
+ /*
+ * still get the old ctx, usually means system busy
+ */
+ CWARN("ctx (%p, fl %lx) doesn't switch, relax a little bit\n",
+ newctx, newctx->cc_flags);
+
+ schedule_timeout(HZ);
+ } else {
+ rc = sptlrpc_req_ctx_switch(req, oldctx, newctx);
+ if (rc) {
+ /* restore old ctx */
+ sptlrpc_req_put_ctx(req, 0);
+ req->rq_cli_ctx = oldctx;
+ RETURN(rc);
+ }
+
+ LASSERT(req->rq_cli_ctx == newctx);
+ }
+
+ sptlrpc_cli_ctx_put(oldctx, 1);
+ RETURN(0);
}
EXPORT_SYMBOL(sptlrpc_req_replace_dead_ctx);
LASSERT(ctx);
+ /*
+ * during the process a request's context might change type even
+ * (e.g. from gss ctx to plain ctx), so each loop we need to re-check
+ * everything
+ */
+again:
/* skip special ctxs */
if (cli_ctx_is_eternal(ctx) || req->rq_ctx_init || req->rq_ctx_fini)
RETURN(0);
}
LASSERT(test_bit(PTLRPC_CTX_NEW_BIT, &ctx->cc_flags) == 0);
-again:
LASSERT(ctx->cc_ops->validate);
if (ctx->cc_ops->validate(ctx) == 0) {
req_off_ctx_list(req, ctx);
}
if (unlikely(test_bit(PTLRPC_CTX_DEAD_BIT, &ctx->cc_flags))) {
- /* don't have to, but we don't want to release it too soon */
- sptlrpc_cli_ctx_get(ctx);
-
rc = sptlrpc_req_replace_dead_ctx(req);
if (rc) {
LASSERT(ctx == req->rq_cli_ctx);
- CERROR("req %p: failed to replace dead ctx %p\n",
- req, ctx);
+ CERROR("req %p: failed to replace dead ctx %p: %d\n",
+ req, ctx, rc);
req->rq_err = 1;
LASSERT(list_empty(&req->rq_ctx_chain));
- sptlrpc_cli_ctx_put(ctx, 1);
- RETURN(-ENOMEM);
+ RETURN(rc);
}
- /* FIXME
- * if ctx didn't really switch, might be cpu tight or sth,
- * we just relax a little bit.
- */
- if (ctx == req->rq_cli_ctx)
- schedule();
-
- CWARN("req %p: replace dead ctx %p(%u->%s) => %p\n",
- req, ctx, ctx->cc_vcred.vc_uid,
- sec2target_str(ctx->cc_sec), req->rq_cli_ctx);
+ CWARN("req %p: replace dead ctx %p => ctx %p (%u->%s)\n",
+ req, ctx, req->rq_cli_ctx,
+ req->rq_cli_ctx->cc_vcred.vc_uid,
+ sec2target_str(req->rq_cli_ctx->cc_sec));
- sptlrpc_cli_ctx_put(ctx, 1);
ctx = req->rq_cli_ctx;
LASSERT(list_empty(&req->rq_ctx_chain));
ctx_refresh_interrupt, req);
rc = l_wait_event(req->rq_reply_waitq, ctx_check_refresh(ctx), &lwi);
- /* five cases we are here:
- * 1. successfully refreshed;
- * 2. someone else mark this ctx dead by force;
- * 3. interruptted;
- * 4. timedout, and we don't want recover from the failure;
- * 5. timedout, and waked up upon recovery finished;
+ /* following cases we could be here:
+ * - successfully refreshed;
+ * - interruptted;
+ * - timedout, and we don't want recover from the failure;
+ * - timedout, and waked up upon recovery finished;
+ * - someone else mark this ctx dead by force;
+ * - someone invalidate the req and call wake_client_req(),
+ * e.g. ptlrpc_abort_inflight();
*/
if (!cli_ctx_is_refreshed(ctx)) {
/* timed out or interruptted */
goto again;
}
+/*
+ * Note this could be called in two situations:
+ * - new request from ptlrpc_pre_req(), with proper @opcode
+ * - old request which changed ctx in the middle, with @opcode == 0
+ */
void sptlrpc_req_set_flavor(struct ptlrpc_request *req, int opcode)
{
- struct sec_flavor_config *conf;
+ struct ptlrpc_sec *sec;
LASSERT(req->rq_import);
- LASSERT(req->rq_import->imp_sec);
LASSERT(req->rq_cli_ctx);
LASSERT(req->rq_cli_ctx->cc_sec);
LASSERT(req->rq_bulk_read == 0 || req->rq_bulk_write == 0);
case SEC_CTX_FINI:
req->rq_ctx_fini = 1;
break;
+ case 0:
+ /* init/fini rpc won't be resend, so can't be here */
+ LASSERT(req->rq_ctx_init == 0);
+ LASSERT(req->rq_ctx_fini == 0);
+
+ /* cleanup flags, which should be recalculated */
+ req->rq_pack_udesc = 0;
+ req->rq_pack_bulk = 0;
+ break;
}
- req->rq_sec_flavor = req->rq_cli_ctx->cc_sec->ps_flavor;
+ sec = req->rq_cli_ctx->cc_sec;
+
+ spin_lock(&sec->ps_lock);
+ req->rq_flvr = sec->ps_flvr;
+ spin_unlock(&sec->ps_lock);
/* force SVC_NULL for context initiation rpc, SVC_INTG for context
- * destruction rpc
- */
- if (unlikely(req->rq_ctx_init)) {
- req->rq_sec_flavor = SEC_MAKE_RPC_FLAVOR(
- SEC_FLAVOR_POLICY(req->rq_sec_flavor),
- SEC_FLAVOR_MECH(req->rq_sec_flavor),
- SPTLRPC_SVC_NULL);
- } else if (unlikely(req->rq_ctx_fini)) {
- req->rq_sec_flavor = SEC_MAKE_RPC_FLAVOR(
- SEC_FLAVOR_POLICY(req->rq_sec_flavor),
- SEC_FLAVOR_MECH(req->rq_sec_flavor),
- SPTLRPC_SVC_INTG);
- }
-
- conf = &req->rq_import->imp_obd->u.cli.cl_sec_conf;
-
- /* user descriptor flag, except ROOTONLY which don't need, and
- * null security which can't
- */
- if ((conf->sfc_flags & PTLRPC_SEC_FL_ROOTONLY) == 0 &&
- req->rq_sec_flavor != SPTLRPC_FLVR_NULL)
- req->rq_sec_flavor |= SEC_FLAVOR_FL_USER;
+ * destruction rpc */
+ if (unlikely(req->rq_ctx_init))
+ rpc_flvr_set_svc(&req->rq_flvr.sf_rpc, SPTLRPC_SVC_NULL);
+ else if (unlikely(req->rq_ctx_fini))
+ rpc_flvr_set_svc(&req->rq_flvr.sf_rpc, SPTLRPC_SVC_INTG);
+
+ /* user descriptor flag, null security can't do it anyway */
+ if ((sec->ps_flvr.sf_flags & PTLRPC_SEC_FL_UDESC) &&
+ (req->rq_flvr.sf_rpc != SPTLRPC_FLVR_NULL))
+ req->rq_pack_udesc = 1;
/* bulk security flag */
if ((req->rq_bulk_read || req->rq_bulk_write) &&
- (conf->sfc_bulk_priv != BULK_PRIV_ALG_NULL ||
- conf->sfc_bulk_csum != BULK_CSUM_ALG_NULL))
- req->rq_sec_flavor |= SEC_FLAVOR_FL_BULK;
+ (req->rq_flvr.sf_bulk_priv != BULK_PRIV_ALG_NULL ||
+ req->rq_flvr.sf_bulk_csum != BULK_CSUM_ALG_NULL))
+ req->rq_pack_bulk = 1;
}
void sptlrpc_request_out_callback(struct ptlrpc_request *req)
{
- if (SEC_FLAVOR_SVC(req->rq_sec_flavor) != SPTLRPC_SVC_PRIV)
+ if (RPC_FLVR_SVC(req->rq_flvr.sf_rpc) != SPTLRPC_SVC_PRIV)
return;
LASSERT(req->rq_clrbuf);
*/
int sptlrpc_import_check_ctx(struct obd_import *imp)
{
+ struct ptlrpc_sec *sec;
struct ptlrpc_cli_ctx *ctx;
struct ptlrpc_request *req = NULL;
int rc;
might_sleep();
- ctx = get_my_ctx(imp->imp_sec);
+ sec = sptlrpc_import_sec_ref(imp);
+ ctx = get_my_ctx(sec);
+ sptlrpc_sec_put(sec);
+
if (!ctx)
RETURN(1);
RETURN(rc);
}
- switch (SEC_FLAVOR_SVC(req->rq_sec_flavor)) {
+ switch (RPC_FLVR_SVC(req->rq_flvr.sf_rpc)) {
case SPTLRPC_SVC_NULL:
case SPTLRPC_SVC_AUTH:
case SPTLRPC_SVC_INTG:
int sptlrpc_cli_unwrap_reply(struct ptlrpc_request *req)
{
struct ptlrpc_cli_ctx *ctx = req->rq_cli_ctx;
- int rc;
+ int rc;
ENTRY;
LASSERT(ctx);
RETURN(-EPROTO);
}
+
if (req->rq_repbuf->lm_magic == LUSTRE_MSG_MAGIC_V1 ||
req->rq_repbuf->lm_magic == LUSTRE_MSG_MAGIC_V1_SWABBED) {
- /* it's must be null flavor, so our requets also should be
- * in null flavor */
- if (SEC_FLAVOR_POLICY(req->rq_sec_flavor) !=
+ /*
+ * v1 message, it's must be null flavor, so our requets also
+ * should be in null flavor
+ */
+ if (RPC_FLVR_POLICY(req->rq_flvr.sf_rpc) !=
SPTLRPC_POLICY_NULL) {
- CERROR("request flavor is %x but reply with null\n",
- req->rq_sec_flavor);
+ CERROR("request was %s but reply with null\n",
+ sptlrpc_rpcflavor2name(req->rq_flvr.sf_rpc));
RETURN(-EPROTO);
}
} else {
- /* v2 message... */
- ptlrpc_sec_flavor_t tmpf = req->rq_repbuf->lm_secflvr;
+ /*
+ * v2 message, check request/reply policy match
+ */
+ __u16 rpc_flvr = WIRE_FLVR_RPC(req->rq_repbuf->lm_secflvr);
if (req->rq_repbuf->lm_magic == LUSTRE_MSG_MAGIC_V2_SWABBED)
- __swab32s(&tmpf);
+ __swab16s(&rpc_flvr);
- if (SEC_FLAVOR_POLICY(tmpf) !=
- SEC_FLAVOR_POLICY(req->rq_sec_flavor)) {
- CERROR("request policy %u while reply with %d\n",
- SEC_FLAVOR_POLICY(req->rq_sec_flavor),
- SEC_FLAVOR_POLICY(tmpf));
+ if (RPC_FLVR_POLICY(rpc_flvr) !=
+ RPC_FLVR_POLICY(req->rq_flvr.sf_rpc)) {
+ CERROR("request policy was %u while reply with %u\n",
+ RPC_FLVR_POLICY(req->rq_flvr.sf_rpc),
+ RPC_FLVR_POLICY(rpc_flvr));
RETURN(-EPROTO);
}
- if ((SEC_FLAVOR_POLICY(req->rq_sec_flavor) !=
- SPTLRPC_POLICY_NULL) &&
+ /* do nothing if it's null policy; otherwise unpack the
+ * wrapper message
+ */
+ if (RPC_FLVR_POLICY(rpc_flvr) != SPTLRPC_POLICY_NULL &&
lustre_unpack_msg(req->rq_repbuf, req->rq_nob_received))
RETURN(-EPROTO);
}
- switch (SEC_FLAVOR_SVC(req->rq_sec_flavor)) {
+ switch (RPC_FLVR_SVC(req->rq_flvr.sf_rpc)) {
case SPTLRPC_SVC_NULL:
case SPTLRPC_SVC_AUTH:
case SPTLRPC_SVC_INTG:
}
/**************************************************
+ * sec ID *
+ **************************************************/
+
+/*
+ * "fixed" sec (e.g. null) use sec_id < 0
+ */
+static atomic_t sptlrpc_sec_id = ATOMIC_INIT(1);
+
+int sptlrpc_get_next_secid(void)
+{
+ return atomic_inc_return(&sptlrpc_sec_id);
+}
+EXPORT_SYMBOL(sptlrpc_get_next_secid);
+
+/**************************************************
* client side high-level security APIs *
**************************************************/
-static
-void sec_cop_destroy_sec(struct ptlrpc_sec *sec)
+static int sec_cop_flush_ctx_cache(struct ptlrpc_sec *sec, uid_t uid,
+ int grace, int force)
+{
+ struct ptlrpc_sec_policy *policy = sec->ps_policy;
+
+ LASSERT(policy->sp_cops);
+ LASSERT(policy->sp_cops->flush_ctx_cache);
+
+ return policy->sp_cops->flush_ctx_cache(sec, uid, grace, force);
+}
+
+static void sec_cop_destroy_sec(struct ptlrpc_sec *sec)
{
struct ptlrpc_sec_policy *policy = sec->ps_policy;
LASSERT(atomic_read(&sec->ps_refcount) == 0);
- LASSERT(atomic_read(&sec->ps_busy) == 0);
+ LASSERT(atomic_read(&sec->ps_nctx) == 0);
LASSERT(policy->sp_cops->destroy_sec);
CDEBUG(D_SEC, "%s@%p: being destroied\n", sec->ps_policy->sp_name, sec);
sptlrpc_policy_put(policy);
}
-static
-int sec_cop_flush_ctx_cache(struct ptlrpc_sec *sec, uid_t uid,
- int grace, int force)
+void sptlrpc_sec_destroy(struct ptlrpc_sec *sec)
{
- struct ptlrpc_sec_policy *policy = sec->ps_policy;
+ sec_cop_destroy_sec(sec);
+}
+EXPORT_SYMBOL(sptlrpc_sec_destroy);
- LASSERT(policy->sp_cops);
- LASSERT(policy->sp_cops->flush_ctx_cache);
+static void sptlrpc_sec_kill(struct ptlrpc_sec *sec)
+{
+ LASSERT(atomic_read(&sec->ps_refcount) > 0);
- return policy->sp_cops->flush_ctx_cache(sec, uid, grace, force);
+ if (sec->ps_policy->sp_cops->kill_sec) {
+ sec->ps_policy->sp_cops->kill_sec(sec);
+
+ sec_cop_flush_ctx_cache(sec, -1, 1, 1);
+ }
}
-void sptlrpc_sec_destroy(struct ptlrpc_sec *sec)
+struct ptlrpc_sec *sptlrpc_sec_get(struct ptlrpc_sec *sec)
{
- sec_cop_destroy_sec(sec);
+ if (sec) {
+ LASSERT(atomic_read(&sec->ps_refcount) > 0);
+ atomic_inc(&sec->ps_refcount);
+ }
+
+ return sec;
}
-EXPORT_SYMBOL(sptlrpc_sec_destroy);
+EXPORT_SYMBOL(sptlrpc_sec_get);
+
+void sptlrpc_sec_put(struct ptlrpc_sec *sec)
+{
+ if (sec) {
+ LASSERT(atomic_read(&sec->ps_refcount) > 0);
+
+ if (atomic_dec_and_test(&sec->ps_refcount)) {
+ LASSERT(atomic_read(&sec->ps_nctx) == 0);
+
+ sptlrpc_gc_del_sec(sec);
+ sec_cop_destroy_sec(sec);
+ }
+ }
+}
+EXPORT_SYMBOL(sptlrpc_sec_put);
/*
- * let policy module to determine whether take refrence of
- * import or not.
+ * it's policy module responsible for taking refrence of import
*/
static
-struct ptlrpc_sec * import_create_sec(struct obd_import *imp,
- struct ptlrpc_svc_ctx *ctx,
- __u32 flavor,
- unsigned long flags)
+struct ptlrpc_sec * sptlrpc_sec_create(struct obd_import *imp,
+ struct ptlrpc_svc_ctx *svc_ctx,
+ struct sptlrpc_flavor *sf,
+ enum lustre_sec_part sp)
{
struct ptlrpc_sec_policy *policy;
- struct ptlrpc_sec *sec;
+ struct ptlrpc_sec *sec;
ENTRY;
- flavor = SEC_FLAVOR_RPC(flavor);
-
- if (ctx) {
+ if (svc_ctx) {
LASSERT(imp->imp_dlm_fake == 1);
CDEBUG(D_SEC, "%s %s: reverse sec using flavor %s\n",
imp->imp_obd->obd_type->typ_name,
imp->imp_obd->obd_name,
- sptlrpc_flavor2name(flavor));
+ sptlrpc_rpcflavor2name(sf->sf_rpc));
- policy = sptlrpc_policy_get(ctx->sc_policy);
- flags |= PTLRPC_SEC_FL_REVERSE | PTLRPC_SEC_FL_ROOTONLY;
+ policy = sptlrpc_policy_get(svc_ctx->sc_policy);
+ sf->sf_flags |= PTLRPC_SEC_FL_REVERSE | PTLRPC_SEC_FL_ROOTONLY;
} else {
LASSERT(imp->imp_dlm_fake == 0);
CDEBUG(D_SEC, "%s %s: select security flavor %s\n",
imp->imp_obd->obd_type->typ_name,
imp->imp_obd->obd_name,
- sptlrpc_flavor2name(flavor));
+ sptlrpc_rpcflavor2name(sf->sf_rpc));
- policy = sptlrpc_flavor2policy(flavor);
+ policy = sptlrpc_rpcflavor2policy(sf->sf_rpc);
if (!policy) {
- CERROR("invalid flavor 0x%x\n", flavor);
+ CERROR("invalid flavor 0x%x\n", sf->sf_rpc);
RETURN(NULL);
}
}
- sec = policy->sp_cops->create_sec(imp, ctx, flavor, flags);
+ sec = policy->sp_cops->create_sec(imp, svc_ctx, sf);
if (sec) {
atomic_inc(&sec->ps_refcount);
- /* take 1 busy count on behalf of sec itself,
- * balanced in sptlrpc_set_put()
- */
- atomic_inc(&sec->ps_busy);
+ sec->ps_part = sp;
if (sec->ps_gc_interval && policy->sp_cops->gc_ctx)
sptlrpc_gc_add_sec(sec);
- } else
+ } else {
sptlrpc_policy_put(policy);
+ }
RETURN(sec);
}
-int sptlrpc_import_get_sec(struct obd_import *imp,
- struct ptlrpc_svc_ctx *ctx,
- __u32 flavor,
- unsigned long flags)
+struct ptlrpc_sec *sptlrpc_import_sec_ref(struct obd_import *imp)
{
- might_sleep();
+ struct ptlrpc_sec *sec;
- /* old sec might be still there in reconnecting */
- if (imp->imp_sec)
- return 0;
+ spin_lock(&imp->imp_lock);
+ sec = sptlrpc_sec_get(imp->imp_sec);
+ spin_unlock(&imp->imp_lock);
- imp->imp_sec = import_create_sec(imp, ctx, flavor, flags);
- if (!imp->imp_sec)
- return -EINVAL;
+ return sec;
+}
+EXPORT_SYMBOL(sptlrpc_import_sec_ref);
- return 0;
+static void sptlrpc_import_sec_install(struct obd_import *imp,
+ struct ptlrpc_sec *sec)
+{
+ struct ptlrpc_sec *old_sec;
+
+ LASSERT(atomic_read(&sec->ps_refcount) > 0);
+
+ spin_lock(&imp->imp_lock);
+ old_sec = imp->imp_sec;
+ imp->imp_sec = sec;
+ spin_unlock(&imp->imp_lock);
+
+ if (old_sec) {
+ sptlrpc_sec_kill(old_sec);
+
+ /* balance the ref taken by this import */
+ sptlrpc_sec_put(old_sec);
+ }
+}
+
+static void sptlrpc_import_sec_adapt_inplace(struct obd_import *imp,
+ struct ptlrpc_sec *sec,
+ struct sptlrpc_flavor *sf)
+{
+ if (sf->sf_bulk_priv != sec->ps_flvr.sf_bulk_priv ||
+ sf->sf_bulk_csum != sec->ps_flvr.sf_bulk_csum) {
+ CWARN("imp %p (%s->%s): changing bulk flavor %s/%s -> %s/%s\n",
+ imp, imp->imp_obd->obd_name,
+ obd_uuid2str(&imp->imp_connection->c_remote_uuid),
+ sptlrpc_bulk_priv_alg2name(sec->ps_flvr.sf_bulk_priv),
+ sptlrpc_bulk_csum_alg2name(sec->ps_flvr.sf_bulk_csum),
+ sptlrpc_bulk_priv_alg2name(sf->sf_bulk_priv),
+ sptlrpc_bulk_csum_alg2name(sf->sf_bulk_csum));
+
+ spin_lock(&sec->ps_lock);
+ sec->ps_flvr.sf_bulk_priv = sf->sf_bulk_priv;
+ sec->ps_flvr.sf_bulk_csum = sf->sf_bulk_csum;
+ spin_unlock(&sec->ps_lock);
+ }
+
+ if (!equi(sf->sf_flags & PTLRPC_SEC_FL_UDESC,
+ sec->ps_flvr.sf_flags & PTLRPC_SEC_FL_UDESC)) {
+ CWARN("imp %p (%s->%s): %s shipping user descriptor\n",
+ imp, imp->imp_obd->obd_name,
+ obd_uuid2str(&imp->imp_connection->c_remote_uuid),
+ (sf->sf_flags & PTLRPC_SEC_FL_UDESC) ? "start" : "stop");
+
+ spin_lock(&sec->ps_lock);
+ sec->ps_flvr.sf_flags &= ~PTLRPC_SEC_FL_UDESC;
+ sec->ps_flvr.sf_flags |= sf->sf_flags & PTLRPC_SEC_FL_UDESC;
+ spin_unlock(&sec->ps_lock);
+ }
}
-void sptlrpc_import_put_sec(struct obd_import *imp)
+/*
+ * for normal import, @svc_ctx should be NULL and @rpc_flavor is ignored;
+ * for reverse import, @svc_ctx and @rpc_flavor is from incoming request.
+ */
+int sptlrpc_import_sec_adapt(struct obd_import *imp,
+ struct ptlrpc_svc_ctx *svc_ctx,
+ __u16 rpc_flavor)
{
- struct ptlrpc_sec *sec;
- struct ptlrpc_sec_policy *policy;
+ struct ptlrpc_connection *conn;
+ struct sptlrpc_flavor sf;
+ struct ptlrpc_sec *sec, *newsec;
+ enum lustre_sec_part sp;
+ int rc;
- might_sleep();
+ if (imp == NULL)
+ return 0;
- if (imp->imp_sec == NULL)
- return;
+ conn = imp->imp_connection;
- sec = imp->imp_sec;
- policy = sec->ps_policy;
+ if (svc_ctx == NULL) {
+ /* normal import, determine flavor from rule set */
+ sptlrpc_rule_set_choose(&imp->imp_obd->u.cli.cl_sptlrpc_rset,
+ LUSTRE_SP_ANY, conn->c_self, &sf);
- if (atomic_dec_and_test(&sec->ps_refcount)) {
- sec_cop_flush_ctx_cache(sec, -1, 1, 1);
- sptlrpc_gc_del_sec(sec);
+ sp = imp->imp_obd->u.cli.cl_sec_part;
+ } else {
+ /* reverse import, determine flavor from incoming reqeust */
+ sf.sf_rpc = rpc_flavor;
+ sf.sf_bulk_priv = BULK_PRIV_ALG_NULL;
+ sf.sf_bulk_csum = BULK_CSUM_ALG_NULL;
+ sf.sf_flags = PTLRPC_SEC_FL_REVERSE | PTLRPC_SEC_FL_ROOTONLY;
- if (atomic_dec_and_test(&sec->ps_busy))
- sec_cop_destroy_sec(sec);
- else {
- CWARN("delay destroying busy sec %s %p\n",
- policy->sp_name, sec);
+ sp = sptlrpc_target_sec_part(imp->imp_obd);
+ }
+
+ sec = sptlrpc_import_sec_ref(imp);
+ if (sec) {
+ if (svc_ctx == NULL) {
+ /* normal import, only check rpc flavor, if just bulk
+ * flavor or flags changed, we can handle it on the fly
+ * without switching sec. */
+ if (sf.sf_rpc == sec->ps_flvr.sf_rpc) {
+ sptlrpc_import_sec_adapt_inplace(imp, sec, &sf);
+
+ rc = 0;
+ goto out;
+ }
+ } else {
+ /* reverse import, do not compare bulk flavor */
+ if (sf.sf_rpc == sec->ps_flvr.sf_rpc) {
+ rc = 0;
+ goto out;
+ }
}
+
+ CWARN("%simport %p (%s%s%s): changing flavor "
+ "(%s, %s/%s) -> (%s, %s/%s)\n",
+ svc_ctx ? "reverse " : "",
+ imp, imp->imp_obd->obd_name,
+ svc_ctx == NULL ? "->" : "<-",
+ obd_uuid2str(&conn->c_remote_uuid),
+ sptlrpc_rpcflavor2name(sec->ps_flvr.sf_rpc),
+ sptlrpc_bulk_csum_alg2name(sec->ps_flvr.sf_bulk_csum),
+ sptlrpc_bulk_priv_alg2name(sec->ps_flvr.sf_bulk_priv),
+ sptlrpc_rpcflavor2name(sf.sf_rpc),
+ sptlrpc_bulk_csum_alg2name(sf.sf_bulk_csum),
+ sptlrpc_bulk_priv_alg2name(sf.sf_bulk_priv));
} else {
- sptlrpc_policy_put(policy);
+ CWARN("%simport %p (%s%s%s) netid %x: "
+ "select initial flavor (%s, %s/%s)\n",
+ svc_ctx == NULL ? "" : "reverse ",
+ imp, imp->imp_obd->obd_name,
+ svc_ctx == NULL ? "->" : "<-",
+ obd_uuid2str(&conn->c_remote_uuid),
+ LNET_NIDNET(conn->c_self),
+ sptlrpc_rpcflavor2name(sf.sf_rpc),
+ sptlrpc_bulk_csum_alg2name(sf.sf_bulk_csum),
+ sptlrpc_bulk_priv_alg2name(sf.sf_bulk_priv));
+ }
+
+ mutex_down(&imp->imp_sec_mutex);
+
+ newsec = sptlrpc_sec_create(imp, svc_ctx, &sf, sp);
+ if (newsec) {
+ sptlrpc_import_sec_install(imp, newsec);
+ rc = 0;
+ } else {
+ CERROR("%simport %p (%s): failed to create new sec\n",
+ svc_ctx == NULL ? "" : "reverse ",
+ imp, obd_uuid2str(&conn->c_remote_uuid));
+ rc = -EPERM;
}
- imp->imp_sec = NULL;
+ mutex_up(&imp->imp_sec_mutex);
+
+out:
+ sptlrpc_sec_put(sec);
+ return 0;
}
-void sptlrpc_import_flush_root_ctx(struct obd_import *imp)
+void sptlrpc_import_sec_put(struct obd_import *imp)
{
- if (imp == NULL || imp->imp_sec == NULL)
+ if (imp->imp_sec) {
+ sptlrpc_sec_kill(imp->imp_sec);
+
+ sptlrpc_sec_put(imp->imp_sec);
+ imp->imp_sec = NULL;
+ }
+}
+
+static void import_flush_ctx_common(struct obd_import *imp,
+ uid_t uid, int grace, int force)
+{
+ struct ptlrpc_sec *sec;
+
+ if (imp == NULL)
+ return;
+
+ sec = sptlrpc_import_sec_ref(imp);
+ if (sec == NULL)
return;
+ sec_cop_flush_ctx_cache(sec, uid, grace, force);
+ sptlrpc_sec_put(sec);
+}
+
+void sptlrpc_import_inval_all_ctx(struct obd_import *imp)
+{
+ /* use grace == 0 */
+ import_flush_ctx_common(imp, -1, 0, 1);
+}
+
+void sptlrpc_import_flush_root_ctx(struct obd_import *imp)
+{
/* it's important to use grace mode, see explain in
- * sptlrpc_req_refresh_ctx()
- */
- sec_cop_flush_ctx_cache(imp->imp_sec, 0, 1, 1);
+ * sptlrpc_req_refresh_ctx() */
+ import_flush_ctx_common(imp, 0, 1, 1);
}
void sptlrpc_import_flush_my_ctx(struct obd_import *imp)
{
- if (imp == NULL || imp->imp_sec == NULL)
- return;
-
- sec_cop_flush_ctx_cache(imp->imp_sec, cfs_current()->uid, 1, 1);
+ import_flush_ctx_common(imp, cfs_current()->uid, 1, 1);
}
EXPORT_SYMBOL(sptlrpc_import_flush_my_ctx);
void sptlrpc_import_flush_all_ctx(struct obd_import *imp)
{
- if (imp == NULL || imp->imp_sec == NULL)
- return;
-
- sec_cop_flush_ctx_cache(imp->imp_sec, -1, 1, 1);
+ import_flush_ctx_common(imp, -1, 1, 1);
}
EXPORT_SYMBOL(sptlrpc_import_flush_all_ctx);
LASSERT(atomic_read(&ctx->cc_refcount));
LASSERT(ctx->cc_sec);
LASSERT(ctx->cc_sec->ps_policy);
- LASSERT(req->rq_reqbuf || req->rq_clrbuf);
+
+ if (req->rq_reqbuf == NULL && req->rq_clrbuf == NULL)
+ return;
policy = ctx->cc_sec->ps_policy;
policy->sp_cops->free_reqbuf(ctx->cc_sec, req);
LASSERT(atomic_read(&ctx->cc_refcount));
LASSERT(ctx->cc_sec);
LASSERT(ctx->cc_sec->ps_policy);
- LASSERT(req->rq_repbuf);
+
+ if (req->rq_repbuf == NULL)
+ return;
+ LASSERT(req->rq_repbuf_len);
policy = ctx->cc_sec->ps_policy;
policy->sp_cops->free_repbuf(ctx->cc_sec, req);
* server side security *
****************************************/
+static int flavor_allowed(struct sptlrpc_flavor *exp,
+ struct ptlrpc_request *req)
+{
+ struct sptlrpc_flavor *flvr = &req->rq_flvr;
+
+ if (exp->sf_rpc == flvr->sf_rpc)
+ return 1;
+
+ if ((req->rq_ctx_init || req->rq_ctx_fini) &&
+ RPC_FLVR_POLICY(exp->sf_rpc) == RPC_FLVR_POLICY(flvr->sf_rpc) &&
+ RPC_FLVR_MECH(exp->sf_rpc) == RPC_FLVR_MECH(flvr->sf_rpc))
+ return 1;
+
+ return 0;
+}
+
+#define EXP_FLVR_UPDATE_EXPIRE (OBD_TIMEOUT_DEFAULT + 10)
+
int sptlrpc_target_export_check(struct obd_export *exp,
struct ptlrpc_request *req)
{
- if (!req->rq_auth_gss ||
- (!req->rq_auth_usr_root && !req->rq_auth_usr_mdt))
+ struct sptlrpc_flavor flavor;
+
+ if (exp == NULL)
return 0;
- if (!req->rq_ctx_init)
+ /* client side export has no imp_reverse, skip
+ * FIXME maybe we should check flavor this as well??? */
+ if (exp->exp_imp_reverse == NULL)
return 0;
- LASSERT(exp->exp_imp_reverse);
- sptlrpc_svc_install_rvs_ctx(exp->exp_imp_reverse, req->rq_svc_ctx);
- return 0;
+ /* don't care about ctx fini rpc */
+ if (req->rq_ctx_fini)
+ return 0;
+
+ spin_lock(&exp->exp_lock);
+
+ /* if flavor just changed (exp->exp_flvr_changed != 0), we wait for
+ * the first req with the new flavor, then treat it as current flavor,
+ * adapt reverse sec according to it.
+ * note the first rpc with new flavor might not be with root ctx, in
+ * which case delay the sec_adapt by leaving exp_flvr_adapt == 1. */
+ if (unlikely(exp->exp_flvr_changed) &&
+ flavor_allowed(&exp->exp_flvr_old[1], req)) {
+ /* make the new flavor as "current", and old ones as
+ * about-to-expire */
+ CDEBUG(D_SEC, "exp %p: just changed: %x->%x\n", exp,
+ exp->exp_flvr.sf_rpc, exp->exp_flvr_old[1].sf_rpc);
+ flavor = exp->exp_flvr_old[1];
+ exp->exp_flvr_old[1] = exp->exp_flvr_old[0];
+ exp->exp_flvr_expire[1] = exp->exp_flvr_expire[0];
+ exp->exp_flvr_old[0] = exp->exp_flvr;
+ exp->exp_flvr_expire[0] = cfs_time_current_sec() +
+ EXP_FLVR_UPDATE_EXPIRE;
+ exp->exp_flvr = flavor;
+
+ /* flavor change finished */
+ exp->exp_flvr_changed = 0;
+ LASSERT(exp->exp_flvr_adapt == 1);
+
+ /* if it's gss, we only interested in root ctx init */
+ if (req->rq_auth_gss &&
+ !(req->rq_ctx_init && (req->rq_auth_usr_root ||
+ req->rq_auth_usr_mdt))) {
+ spin_unlock(&exp->exp_lock);
+ CDEBUG(D_SEC, "is good but not root(%d:%d:%d:%d)\n",
+ req->rq_auth_gss, req->rq_ctx_init,
+ req->rq_auth_usr_root, req->rq_auth_usr_mdt);
+ return 0;
+ }
+
+ exp->exp_flvr_adapt = 0;
+ spin_unlock(&exp->exp_lock);
+
+ return sptlrpc_import_sec_adapt(exp->exp_imp_reverse,
+ req->rq_svc_ctx, flavor.sf_rpc);
+ }
+
+ /* if it equals to the current flavor, we accept it, but need to
+ * dealing with reverse sec/ctx */
+ if (likely(flavor_allowed(&exp->exp_flvr, req))) {
+ /* most cases should return here, we only interested in
+ * gss root ctx init */
+ if (!req->rq_auth_gss || !req->rq_ctx_init ||
+ (!req->rq_auth_usr_root && !req->rq_auth_usr_mdt)) {
+ spin_unlock(&exp->exp_lock);
+ return 0;
+ }
+
+ if (exp->exp_flvr_adapt) {
+ exp->exp_flvr_adapt = 0;
+ CDEBUG(D_SEC, "exp %p (%x|%x|%x): do delayed adapt\n",
+ exp, exp->exp_flvr.sf_rpc,
+ exp->exp_flvr_old[0].sf_rpc,
+ exp->exp_flvr_old[1].sf_rpc);
+ flavor = exp->exp_flvr;
+ spin_unlock(&exp->exp_lock);
+
+ return sptlrpc_import_sec_adapt(exp->exp_imp_reverse,
+ req->rq_svc_ctx,
+ flavor.sf_rpc);
+ } else {
+ CDEBUG(D_SEC, "exp %p (%x|%x|%x): is current flavor, "
+ "install rvs ctx\n", exp, exp->exp_flvr.sf_rpc,
+ exp->exp_flvr_old[0].sf_rpc,
+ exp->exp_flvr_old[1].sf_rpc);
+ spin_unlock(&exp->exp_lock);
+
+ return sptlrpc_svc_install_rvs_ctx(exp->exp_imp_reverse,
+ req->rq_svc_ctx);
+ }
+ }
+
+ if (exp->exp_flvr_expire[0]) {
+ if (exp->exp_flvr_expire[0] >= cfs_time_current_sec()) {
+ if (flavor_allowed(&exp->exp_flvr_old[0], req)) {
+ CDEBUG(D_SEC, "exp %p (%x|%x|%x): match the "
+ "middle one (%lu)\n", exp,
+ exp->exp_flvr.sf_rpc,
+ exp->exp_flvr_old[0].sf_rpc,
+ exp->exp_flvr_old[1].sf_rpc,
+ exp->exp_flvr_expire[0] -
+ cfs_time_current_sec());
+ spin_unlock(&exp->exp_lock);
+ return 0;
+ }
+ } else {
+ CDEBUG(D_SEC, "mark middle expired\n");
+ exp->exp_flvr_expire[0] = 0;
+ }
+ CDEBUG(D_SEC, "exp %p (%x|%x|%x): %x not match middle\n", exp,
+ exp->exp_flvr.sf_rpc,
+ exp->exp_flvr_old[0].sf_rpc, exp->exp_flvr_old[1].sf_rpc,
+ req->rq_flvr.sf_rpc);
+ }
+
+ /* now it doesn't match the current flavor, the only chance we can
+ * accept it is match the old flavors which is not expired. */
+ if (exp->exp_flvr_changed == 0 && exp->exp_flvr_expire[1]) {
+ if (exp->exp_flvr_expire[1] >= cfs_time_current_sec()) {
+ if (flavor_allowed(&exp->exp_flvr_old[1], req)) {
+ CDEBUG(D_SEC, "exp %p (%x|%x|%x): match the "
+ "oldest one (%lu)\n", exp,
+ exp->exp_flvr.sf_rpc,
+ exp->exp_flvr_old[0].sf_rpc,
+ exp->exp_flvr_old[1].sf_rpc,
+ exp->exp_flvr_expire[1] -
+ cfs_time_current_sec());
+ spin_unlock(&exp->exp_lock);
+ return 0;
+ }
+ } else {
+ CDEBUG(D_SEC, "mark oldest expired\n");
+ exp->exp_flvr_expire[1] = 0;
+ }
+ CDEBUG(D_SEC, "exp %p (%x|%x|%x): %x not match found\n",
+ exp, exp->exp_flvr.sf_rpc,
+ exp->exp_flvr_old[0].sf_rpc, exp->exp_flvr_old[1].sf_rpc,
+ req->rq_flvr.sf_rpc);
+ } else {
+ CDEBUG(D_SEC, "exp %p (%x|%x|%x): skip the last one\n",
+ exp, exp->exp_flvr.sf_rpc, exp->exp_flvr_old[0].sf_rpc,
+ exp->exp_flvr_old[1].sf_rpc);
+ }
+
+ spin_unlock(&exp->exp_lock);
+
+ CWARN("req %p: (%u|%u|%u|%u|%u) with unauthorized flavor %x\n",
+ req, req->rq_auth_gss, req->rq_ctx_init, req->rq_ctx_fini,
+ req->rq_auth_usr_root, req->rq_auth_usr_mdt, req->rq_flvr.sf_rpc);
+ return -EACCES;
+}
+
+void sptlrpc_target_update_exp_flavor(struct obd_device *obd,
+ struct sptlrpc_rule_set *rset)
+{
+ struct obd_export *exp;
+ struct sptlrpc_flavor new_flvr;
+
+ LASSERT(obd);
+
+ spin_lock(&obd->obd_dev_lock);
+
+ list_for_each_entry(exp, &obd->obd_exports, exp_obd_chain) {
+ if (exp->exp_connection == NULL)
+ continue;
+
+ /* note if this export had just been updated flavor
+ * (exp_flvr_changed == 1), this will override the
+ * previous one. */
+ spin_lock(&exp->exp_lock);
+ sptlrpc_rule_set_choose(rset, exp->exp_sp_peer,
+ exp->exp_connection->c_peer.nid,
+ &new_flvr);
+ if (exp->exp_flvr_changed ||
+ memcmp(&new_flvr, &exp->exp_flvr, sizeof(new_flvr))) {
+ exp->exp_flvr_old[1] = new_flvr;
+ exp->exp_flvr_expire[1] = 0;
+ exp->exp_flvr_changed = 1;
+ exp->exp_flvr_adapt = 1;
+ CDEBUG(D_SEC, "exp %p (%s): updated flavor %x->%x\n",
+ exp, sptlrpc_part2name(exp->exp_sp_peer),
+ exp->exp_flvr.sf_rpc,
+ exp->exp_flvr_old[1].sf_rpc);
+ }
+ spin_unlock(&exp->exp_lock);
+ }
+
+ spin_unlock(&obd->obd_dev_lock);
+}
+EXPORT_SYMBOL(sptlrpc_target_update_exp_flavor);
+
+static int sptlrpc_svc_check_from(struct ptlrpc_request *req, int svc_rc)
+{
+ if (svc_rc == SECSVC_DROP)
+ return SECSVC_DROP;
+
+ switch (req->rq_sp_from) {
+ case LUSTRE_SP_CLI:
+ case LUSTRE_SP_MDT:
+ case LUSTRE_SP_OST:
+ case LUSTRE_SP_MGS:
+ case LUSTRE_SP_ANY:
+ break;
+ default:
+ DEBUG_REQ(D_ERROR, req, "invalid source %u", req->rq_sp_from);
+ return SECSVC_DROP;
+ }
+
+ if (!req->rq_auth_gss)
+ return svc_rc;
+
+ if (unlikely(req->rq_sp_from == LUSTRE_SP_ANY)) {
+ CERROR("not specific part\n");
+ return SECSVC_DROP;
+ }
+
+ /* from MDT, must be authenticated as MDT */
+ if (unlikely(req->rq_sp_from == LUSTRE_SP_MDT &&
+ !req->rq_auth_usr_mdt)) {
+ DEBUG_REQ(D_ERROR, req, "fake source MDT");
+ return SECSVC_DROP;
+ }
+
+ /* from OST, must be callback to MDT and CLI, the reverse sec
+ * was from mdt/root keytab, so it should be MDT or root FIXME */
+ if (unlikely(req->rq_sp_from == LUSTRE_SP_OST &&
+ !req->rq_auth_usr_mdt && !req->rq_auth_usr_root)) {
+ DEBUG_REQ(D_ERROR, req, "fake source OST");
+ return SECSVC_DROP;
+ }
+
+ return svc_rc;
}
int sptlrpc_svc_unwrap_request(struct ptlrpc_request *req)
LASSERT(req->rq_reqmsg == NULL);
LASSERT(req->rq_repmsg == NULL);
- /*
- * in any case we avoid to call unpack_msg() for request of null flavor
- * which will later be done by ptlrpc_server_handle_request().
- */
+ req->rq_sp_from = LUSTRE_SP_ANY;
+ req->rq_auth_uid = INVALID_UID;
+ req->rq_auth_mapped_uid = INVALID_UID;
+
if (req->rq_reqdata_len < sizeof(struct lustre_msg)) {
CERROR("request size %d too small\n", req->rq_reqdata_len);
RETURN(SECSVC_DROP);
if (msg->lm_magic == LUSTRE_MSG_MAGIC_V1 ||
msg->lm_magic == LUSTRE_MSG_MAGIC_V1_SWABBED) {
- req->rq_sec_flavor = SPTLRPC_FLVR_NULL;
+ /*
+ * v1 message, treat as to be null
+ */
+ req->rq_flvr.sf_rpc = SPTLRPC_FLVR_NULL;
} else {
- req->rq_sec_flavor = msg->lm_secflvr;
-
- if (msg->lm_magic == LUSTRE_MSG_MAGIC_V2_SWABBED)
- __swab32s(&req->rq_sec_flavor);
-
- if ((SEC_FLAVOR_POLICY(req->rq_sec_flavor) !=
+ /*
+ * v2 message.
+ */
+ if (msg->lm_magic == LUSTRE_MSG_MAGIC_V2)
+ req->rq_flvr.sf_rpc = WIRE_FLVR_RPC(msg->lm_secflvr);
+ else
+ req->rq_flvr.sf_rpc = WIRE_FLVR_RPC(
+ __swab32(msg->lm_secflvr));
+
+ /* unpack the wrapper message if the policy is not null */
+ if ((RPC_FLVR_POLICY(req->rq_flvr.sf_rpc) !=
SPTLRPC_POLICY_NULL) &&
lustre_unpack_msg(msg, req->rq_reqdata_len))
RETURN(SECSVC_DROP);
}
- policy = sptlrpc_flavor2policy(req->rq_sec_flavor);
+ policy = sptlrpc_rpcflavor2policy(req->rq_flvr.sf_rpc);
if (!policy) {
- CERROR("unsupported security flavor %x\n", req->rq_sec_flavor);
+ CERROR("unsupported rpc flavor %x\n", req->rq_flvr.sf_rpc);
RETURN(SECSVC_DROP);
}
LASSERT(req->rq_reqmsg || rc != SECSVC_OK);
sptlrpc_policy_put(policy);
+ /* sanity check for the request source */
+ rc = sptlrpc_svc_check_from(req, rc);
+
/* FIXME move to proper place */
if (rc == SECSVC_OK) {
__u32 opc = lustre_msg_get_opc(req->rq_reqmsg);
{
struct ptlrpc_cli_ctx *ctx;
- if (!SEC_FLAVOR_HAS_BULK(req->rq_sec_flavor))
+ if (!req->rq_pack_bulk)
return 0;
LASSERT(req->rq_bulk_read || req->rq_bulk_write);
struct ptlrpc_cli_ctx *ctx;
int rc = 0;
- if (!SEC_FLAVOR_HAS_BULK(req->rq_sec_flavor))
+ if (!req->rq_pack_bulk)
return 0;
LASSERT(req->rq_bulk_read && !req->rq_bulk_write);
{
struct ptlrpc_cli_ctx *ctx;
- if (!SEC_FLAVOR_HAS_BULK(req->rq_sec_flavor))
+ if (!req->rq_pack_bulk)
return 0;
LASSERT(!req->rq_bulk_read && req->rq_bulk_write);
{
struct ptlrpc_svc_ctx *ctx;
- if (!SEC_FLAVOR_HAS_BULK(req->rq_sec_flavor))
+ if (!req->rq_pack_bulk)
return 0;
LASSERT(req->rq_bulk_read || req->rq_bulk_write);
{
struct ptlrpc_svc_ctx *ctx;
- if (!SEC_FLAVOR_HAS_BULK(req->rq_sec_flavor))
+ if (!req->rq_pack_bulk)
return 0;
LASSERT(req->rq_bulk_read || req->rq_bulk_write);
EXPORT_SYMBOL(sptlrpc_unpack_user_desc);
/****************************************
- * user supplied flavor string parsing *
- ****************************************/
-
-static
-int get_default_flavor(enum lustre_part to_part, struct sec_flavor_config *conf)
-{
- conf->sfc_bulk_priv = BULK_PRIV_ALG_NULL;
- conf->sfc_bulk_csum = BULK_CSUM_ALG_NULL;
- conf->sfc_flags = 0;
-
- switch (to_part) {
- case LUSTRE_MDT:
- conf->sfc_rpc_flavor = SPTLRPC_FLVR_PLAIN;
- return 0;
- case LUSTRE_OST:
- conf->sfc_rpc_flavor = SPTLRPC_FLVR_NULL;
- return 0;
- default:
- CERROR("Unknown to lustre part %d, apply defaults\n", to_part);
- conf->sfc_rpc_flavor = SPTLRPC_FLVR_NULL;
- return -EINVAL;
- }
-}
-
-static
-void get_flavor_by_rpc(__u32 rpc_flavor, struct sec_flavor_config *conf)
-{
- conf->sfc_rpc_flavor = rpc_flavor;
- conf->sfc_bulk_priv = BULK_PRIV_ALG_NULL;
- conf->sfc_bulk_csum = BULK_CSUM_ALG_NULL;
- conf->sfc_flags = 0;
-
- switch (rpc_flavor) {
- case SPTLRPC_FLVR_NULL:
- case SPTLRPC_FLVR_PLAIN:
- case SPTLRPC_FLVR_KRB5N:
- case SPTLRPC_FLVR_KRB5A:
- break;
- case SPTLRPC_FLVR_KRB5P:
- conf->sfc_bulk_priv = BULK_PRIV_ALG_ARC4;
- /* fall through */
- case SPTLRPC_FLVR_KRB5I:
- conf->sfc_bulk_csum = BULK_CSUM_ALG_SHA1;
- break;
- default:
- LBUG();
- }
-}
-
-static
-void get_flavor_by_rpc_bulk(__u32 rpc_flavor, int bulk_priv,
- struct sec_flavor_config *conf)
-{
- if (bulk_priv)
- conf->sfc_bulk_priv = BULK_PRIV_ALG_ARC4;
- else
- conf->sfc_bulk_priv = BULK_PRIV_ALG_NULL;
-
- switch (rpc_flavor) {
- case SPTLRPC_FLVR_PLAIN:
- conf->sfc_bulk_csum = BULK_CSUM_ALG_MD5;
- break;
- case SPTLRPC_FLVR_KRB5N:
- case SPTLRPC_FLVR_KRB5A:
- case SPTLRPC_FLVR_KRB5I:
- case SPTLRPC_FLVR_KRB5P:
- conf->sfc_bulk_csum = BULK_CSUM_ALG_SHA1;
- break;
- default:
- LBUG();
- }
-}
-
-static __u32 __flavors[] = {
- SPTLRPC_FLVR_NULL,
- SPTLRPC_FLVR_PLAIN,
- SPTLRPC_FLVR_KRB5N,
- SPTLRPC_FLVR_KRB5A,
- SPTLRPC_FLVR_KRB5I,
- SPTLRPC_FLVR_KRB5P,
-};
-
-#define __nflavors (sizeof(__flavors)/sizeof(__u32))
-
-/*
- * flavor string format: rpc[-bulk{n|i|p}[:cksum/enc]]
- * for examples:
- * null
- * plain-bulki
- * krb5p-bulkn
- * krb5i-bulkp
- * krb5i-bulkp:sha512/arc4
- */
-int sptlrpc_parse_flavor(enum lustre_part from_part, enum lustre_part to_part,
- char *str, struct sec_flavor_config *conf)
-{
- char *f, *bulk, *alg, *enc;
- char buf[64];
- int i, bulk_priv;
- ENTRY;
-
- if (str == NULL) {
- if (get_default_flavor(to_part, conf))
- return -EINVAL;
- goto set_flags;
- }
-
- for (i = 0; i < __nflavors; i++) {
- f = sptlrpc_flavor2name(__flavors[i]);
- if (strncmp(str, f, strlen(f)) == 0)
- break;
- }
-
- if (i >= __nflavors)
- GOTO(invalid, -EINVAL);
-
- /* prepare local buffer thus we can modify it as we want */
- strncpy(buf, str, 64);
- buf[64 - 1] = '\0';
-
- /* find bulk string */
- bulk = strchr(buf, '-');
- if (bulk)
- *bulk++ = '\0';
-
- /* now the first part must equal to rpc flavor name */
- if (strcmp(buf, f) != 0)
- GOTO(invalid, -EINVAL);
-
- get_flavor_by_rpc(__flavors[i], conf);
-
- if (bulk == NULL)
- goto set_flags;
-
- /* null flavor should not have any suffix */
- if (__flavors[i] == SPTLRPC_FLVR_NULL)
- GOTO(invalid, -EINVAL);
-
- /* find bulk algorithm string */
- alg = strchr(bulk, ':');
- if (alg)
- *alg++ = '\0';
-
- /* verify bulk section */
- if (strcmp(bulk, "bulkn") == 0) {
- conf->sfc_bulk_csum = BULK_CSUM_ALG_NULL;
- conf->sfc_bulk_priv = BULK_PRIV_ALG_NULL;
- goto set_flags;
- }
-
- if (strcmp(bulk, "bulki") == 0)
- bulk_priv = 0;
- else if (strcmp(bulk, "bulkp") == 0)
- bulk_priv = 1;
- else
- GOTO(invalid, -EINVAL);
-
- /* plain policy dosen't support bulk encryption */
- if (bulk_priv && __flavors[i] == SPTLRPC_FLVR_PLAIN)
- GOTO(invalid, -EINVAL);
-
- get_flavor_by_rpc_bulk(__flavors[i], bulk_priv, conf);
-
- if (alg == NULL)
- goto set_flags;
-
- /* find encryption algorithm string */
- enc = strchr(alg, '/');
- if (enc)
- *enc++ = '\0';
-
- /* bulk combination sanity check */
- if ((bulk_priv && enc == NULL) || (bulk_priv == 0 && enc))
- GOTO(invalid, -EINVAL);
-
- /* checksum algorithm */
- for (i = 0; i < BULK_CSUM_ALG_MAX; i++) {
- if (strcmp(alg, sptlrpc_bulk_csum_alg2name(i)) == 0) {
- conf->sfc_bulk_csum = i;
- break;
- }
- }
- if (i >= BULK_CSUM_ALG_MAX)
- GOTO(invalid, -EINVAL);
-
- /* privacy algorithm */
- if (enc) {
- if (strcmp(enc, "arc4") != 0)
- GOTO(invalid, -EINVAL);
- conf->sfc_bulk_priv = BULK_PRIV_ALG_ARC4;
- }
-
-set_flags:
- /* * set ROOTONLY flag:
- * - to OST
- * - from MDT to MDT
- * * set BULK flag for:
- * - from CLI to OST
- */
- if (to_part == LUSTRE_OST ||
- (from_part == LUSTRE_MDT && to_part == LUSTRE_MDT))
- conf->sfc_flags |= PTLRPC_SEC_FL_ROOTONLY;
- if (from_part == LUSTRE_CLI && to_part == LUSTRE_OST)
- conf->sfc_flags |= PTLRPC_SEC_FL_BULK;
-
-#ifdef __BIG_ENDIAN
- __swab32s(&conf->sfc_rpc_flavor);
- __swab32s(&conf->sfc_bulk_csum);
- __swab32s(&conf->sfc_bulk_priv);
- __swab32s(&conf->sfc_flags);
-#endif
- return 0;
-invalid:
- CERROR("invalid flavor string: %s\n", str);
- return -EINVAL;
-}
-EXPORT_SYMBOL(sptlrpc_parse_flavor);
-
-/****************************************
* misc helpers *
****************************************/
/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
* vim:expandtab:shiftwidth=8:tabstop=8:
*
- * Copyright (C) 2006 Cluster File Systems, Inc.
+ * Copyright (C) 2006-2007 Cluster File Systems, Inc.
* Author: Eric Mei <ericm@clusterfs.com>
*
* This file is part of Lustre, http://www.lustre.org.
#define PTRS_PER_PAGE (CFS_PAGE_SIZE / sizeof(void *))
#define PAGES_PER_POOL (PTRS_PER_PAGE)
+#define IDLE_IDX_MAX (100)
+#define IDLE_IDX_WEIGHT (3)
+
+#define CACHE_QUIESCENCE_PERIOD (20)
+
static struct ptlrpc_enc_page_pool {
/*
* constants
*/
unsigned long epp_max_pages; /* maximum pages can hold, const */
unsigned int epp_max_pools; /* number of pools, const */
- /*
- * users of the pools. the capacity grow as more user added,
- * but doesn't shrink when users gone -- just current policy.
- * during failover there might be user add/remove activities.
- */
- atomic_t epp_users; /* shared by how many users (osc) */
- atomic_t epp_users_gone; /* users removed */
+
/*
* wait queue in case of not enough free pages.
*/
cfs_waitq_t epp_waitq; /* waiting threads */
unsigned int epp_waitqlen; /* wait queue length */
unsigned long epp_pages_short; /* # of pages wanted of in-q users */
- unsigned long epp_adding:1, /* during adding pages */
- epp_full:1; /* pools are all full */
+ unsigned int epp_growing:1; /* during adding pages */
+
+ /*
+ * indicating how idle the pools are, from 0 to MAX_IDLE_IDX
+ * this is counted based on each time when getting pages from
+ * the pools, not based on time. which means in case that system
+ * is idled for a while but the idle_idx might still be low if no
+ * activities happened in the pools.
+ */
+ unsigned long epp_idle_idx;
+
+ /* last shrink time due to mem tight */
+ long epp_last_shrink;
+ long epp_last_access;
+
/*
* in-pool pages bookkeeping
*/
spinlock_t epp_lock; /* protect following fields */
unsigned long epp_total_pages; /* total pages in pools */
unsigned long epp_free_pages; /* current pages available */
+
/*
* statistics
*/
- unsigned int epp_st_adds;
- unsigned int epp_st_failadds; /* # of add pages failures */
- unsigned long epp_st_reqs; /* # of get_pages requests */
- unsigned long epp_st_missings; /* # of cache missing */
- unsigned long epp_st_lowfree; /* lowest free pages ever reached */
- unsigned long epp_st_max_wqlen;/* highest waitqueue length ever */
- cfs_time_t epp_st_max_wait; /* in jeffies */
+ unsigned int epp_st_grows; /* # of grows */
+ unsigned int epp_st_grow_fails; /* # of add pages failures */
+ unsigned int epp_st_shrinks; /* # of shrinks */
+ unsigned long epp_st_access; /* # of access */
+ unsigned long epp_st_missings; /* # of cache missing */
+ unsigned long epp_st_lowfree; /* lowest free pages reached */
+ unsigned long epp_st_max_wqlen; /* highest waitqueue length */
+ cfs_time_t epp_st_max_wait; /* in jeffies */
/*
* pointers to pools
*/
cfs_page_t ***epp_pools;
} page_pools;
+/*
+ * memory shrinker
+ */
+const int pools_shrinker_seeks = DEFAULT_SEEKS;
+static struct shrinker *pools_shrinker = NULL;
+
+
+/*
+ * /proc/fs/lustre/sptlrpc/encrypt_page_pools
+ */
int sptlrpc_proc_read_enc_pool(char *page, char **start, off_t off, int count,
int *eof, void *data)
{
"pages per pool: %lu\n"
"max pages: %lu\n"
"max pools: %u\n"
- "users: %d - %d\n"
- "current waitqueue len: %u\n"
- "current pages in short: %lu\n"
"total pages: %lu\n"
"total free: %lu\n"
- "add page times: %u\n"
- "add page failed times: %u\n"
- "total requests: %lu\n"
+ "idle index: %lu/100\n"
+ "last shrink: %lds\n"
+ "last access: %lds\n"
+ "grows: %u\n"
+ "grows failure: %u\n"
+ "shrinks: %u\n"
+ "cache access: %lu\n"
"cache missing: %lu\n"
- "lowest free pages: %lu\n"
+ "low free mark: %lu\n"
"max waitqueue depth: %lu\n"
- "max wait time: "CFS_TIME_T"\n"
+ "max wait time: "CFS_TIME_T"/%u\n"
,
num_physpages,
PAGES_PER_POOL,
page_pools.epp_max_pages,
page_pools.epp_max_pools,
- atomic_read(&page_pools.epp_users),
- atomic_read(&page_pools.epp_users_gone),
- page_pools.epp_waitqlen,
- page_pools.epp_pages_short,
page_pools.epp_total_pages,
page_pools.epp_free_pages,
- page_pools.epp_st_adds,
- page_pools.epp_st_failadds,
- page_pools.epp_st_reqs,
+ page_pools.epp_idle_idx,
+ cfs_time_current_sec() - page_pools.epp_last_shrink,
+ cfs_time_current_sec() - page_pools.epp_last_access,
+ page_pools.epp_st_grows,
+ page_pools.epp_st_grow_fails,
+ page_pools.epp_st_shrinks,
+ page_pools.epp_st_access,
page_pools.epp_st_missings,
page_pools.epp_st_lowfree,
page_pools.epp_st_max_wqlen,
- page_pools.epp_st_max_wait
+ page_pools.epp_st_max_wait, HZ
);
spin_unlock(&page_pools.epp_lock);
return rc;
}
+static void enc_pools_release_free_pages(long npages)
+{
+ int p_idx, g_idx;
+
+ LASSERT(npages <= page_pools.epp_free_pages);
+
+ p_idx = (page_pools.epp_free_pages - 1) / PAGES_PER_POOL;
+ g_idx = (page_pools.epp_free_pages - 1) % PAGES_PER_POOL;
+ LASSERT(page_pools.epp_pools[p_idx]);
+
+ page_pools.epp_free_pages -= npages;
+ page_pools.epp_total_pages -= npages;
+
+ while (npages-- > 0) {
+ LASSERT(page_pools.epp_pools[p_idx][g_idx] != NULL);
+
+ cfs_free_page(page_pools.epp_pools[p_idx][g_idx]);
+ page_pools.epp_pools[p_idx][g_idx] = NULL;
+
+ if (g_idx-- == 0) {
+ p_idx--;
+ g_idx = PAGES_PER_POOL - 1;
+
+ LASSERT(page_pools.epp_pools[p_idx]);
+ }
+ }
+}
+
+/*
+ * could be called frequently for query (@nr_to_scan == 0)
+ */
+static int enc_pools_shrink(int nr_to_scan, unsigned int gfp_mask)
+{
+ unsigned long ret;
+
+ spin_lock(&page_pools.epp_lock);
+
+ if (nr_to_scan) {
+ if (nr_to_scan > page_pools.epp_free_pages)
+ nr_to_scan = page_pools.epp_free_pages;
+
+ enc_pools_release_free_pages(nr_to_scan);
+ CDEBUG(D_SEC, "released %d pages, %ld left\n",
+ nr_to_scan, page_pools.epp_free_pages);
+
+ page_pools.epp_st_shrinks++;
+ page_pools.epp_last_shrink = cfs_time_current_sec();
+ }
+
+ /*
+ * try to keep at least PTLRPC_MAX_BRW_PAGES pages in the pool
+ */
+ if (page_pools.epp_free_pages <= PTLRPC_MAX_BRW_PAGES) {
+ ret = 0;
+ goto out_unlock;
+ }
+
+ /*
+ * if no pool access for a long time, we consider it's fully idle
+ */
+ if (cfs_time_current_sec() - page_pools.epp_last_access >
+ CACHE_QUIESCENCE_PERIOD)
+ page_pools.epp_idle_idx = IDLE_IDX_MAX;
+
+ LASSERT(page_pools.epp_idle_idx <= IDLE_IDX_MAX);
+ ret = (page_pools.epp_free_pages * page_pools.epp_idle_idx /
+ IDLE_IDX_MAX);
+ if (page_pools.epp_free_pages - ret < PTLRPC_MAX_BRW_PAGES)
+ ret = page_pools.epp_free_pages - PTLRPC_MAX_BRW_PAGES;
+
+out_unlock:
+ spin_unlock(&page_pools.epp_lock);
+ return ret;
+}
+
static inline
int npages_to_npools(unsigned long npages)
{
/*
* return how many pages cleaned up.
*/
-static unsigned long enc_cleanup_pools(cfs_page_t ***pools, int npools)
+static unsigned long enc_pools_cleanup(cfs_page_t ***pools, int npools)
{
unsigned long cleaned = 0;
int i, j;
* we have options to avoid most memory copy with some tricks. but we choose
* the simplest way to avoid complexity. It's not frequently called.
*/
-static void enc_insert_pool(cfs_page_t ***pools, int npools, int npages)
+static void enc_pools_insert(cfs_page_t ***pools, int npools, int npages)
{
int freeslot;
int op_idx, np_idx, og_idx, ng_idx;
page_pools.epp_free_pages += npages;
page_pools.epp_st_lowfree = page_pools.epp_free_pages;
- if (page_pools.epp_total_pages == page_pools.epp_max_pages)
- page_pools.epp_full = 1;
-
CDEBUG(D_SEC, "add %d pages to total %lu\n", npages,
page_pools.epp_total_pages);
int npools, alloced = 0;
int i, j, rc = -ENOMEM;
+ if (npages < PTLRPC_MAX_BRW_PAGES)
+ npages = PTLRPC_MAX_BRW_PAGES;
+
down(&sem_add_pages);
- if (npages > page_pools.epp_max_pages - page_pools.epp_total_pages)
+ if (npages + page_pools.epp_total_pages > page_pools.epp_max_pages)
npages = page_pools.epp_max_pages - page_pools.epp_total_pages;
- if (npages == 0) {
- rc = 0;
- goto out;
- }
+ LASSERT(npages > 0);
- page_pools.epp_st_adds++;
+ page_pools.epp_st_grows++;
npools = npages_to_npools(npages);
OBD_ALLOC(pools, npools * sizeof(*pools));
}
}
- enc_insert_pool(pools, npools, npages);
- CDEBUG(D_SEC, "add %d pages into enc page pools\n", npages);
+ enc_pools_insert(pools, npools, npages);
+ CDEBUG(D_SEC, "added %d pages into pools\n", npages);
rc = 0;
out_pools:
- enc_cleanup_pools(pools, npools);
+ enc_pools_cleanup(pools, npools);
OBD_FREE(pools, npools * sizeof(*pools));
out:
if (rc) {
- page_pools.epp_st_failadds++;
- CERROR("Failed to pre-allocate %d enc pages\n", npages);
+ page_pools.epp_st_grow_fails++;
+ CERROR("Failed to allocate %d enc pages\n", npages);
}
up(&sem_add_pages);
return rc;
}
-/*
- * both "max bulk rpcs inflight" and "lnet MTU" are tunable, we use the
- * default fixed value initially.
- */
-int sptlrpc_enc_pool_add_user(void)
+static inline void enc_pools_wakeup(void)
{
- int page_plus = PTLRPC_MAX_BRW_PAGES * OSC_MAX_RIF_DEFAULT;
- int users, users_gone, shift, rc;
+ if (unlikely(page_pools.epp_waitqlen)) {
+ LASSERT(page_pools.epp_waitqlen > 0);
+ LASSERT(cfs_waitq_active(&page_pools.epp_waitq));
+ cfs_waitq_broadcast(&page_pools.epp_waitq);
+ }
+}
- LASSERT(!in_interrupt());
- LASSERT(atomic_read(&page_pools.epp_users) >= 0);
+static int enc_pools_should_grow(int page_needed, long now)
+{
+ /* don't grow if someone else is growing the pools right now,
+ * or the pools has reached its full capacity
+ */
+ if (page_pools.epp_growing ||
+ page_pools.epp_total_pages == page_pools.epp_max_pages)
+ return 0;
- users_gone = atomic_dec_return(&page_pools.epp_users_gone);
- if (users_gone >= 0) {
- CWARN("%d users gone, skip\n", users_gone + 1);
+ /* if total pages is not enough, we need to grow */
+ if (page_pools.epp_total_pages < page_needed)
+ return 1;
+
+ /* if we just did a shrink due to memory tight, we'd better
+ * wait a while to grow again.
+ */
+ if (now - page_pools.epp_last_shrink < 2)
return 0;
- }
- atomic_inc(&page_pools.epp_users_gone);
/*
- * prepare full pages for first 2 users; 1/2 for next 2 users;
- * 1/4 for next 4 users; 1/8 for next 8 users; 1/16 for next 16 users;
- * ...
+ * here we perhaps need consider other factors like wait queue
+ * length, idle index, etc. ?
*/
- users = atomic_add_return(1, &page_pools.epp_users);
- shift = fls(users - 1);
- shift = shift > 1 ? shift - 1 : 0;
- page_plus = page_plus >> shift;
- page_plus = page_plus > 2 ? page_plus : 2;
- rc = enc_pools_add_pages(page_plus);
- return 0;
-}
-EXPORT_SYMBOL(sptlrpc_enc_pool_add_user);
-
-int sptlrpc_enc_pool_del_user(void)
-{
- atomic_inc(&page_pools.epp_users_gone);
- return 0;
+ /* grow the pools in any other cases */
+ return 1;
}
-EXPORT_SYMBOL(sptlrpc_enc_pool_del_user);
/*
* we allocate the requested pages atomically.
int sptlrpc_enc_pool_get_pages(struct ptlrpc_bulk_desc *desc)
{
cfs_waitlink_t waitlink;
- cfs_time_t tick1 = 0, tick2;
+ unsigned long this_idle = -1;
+ cfs_time_t tick = 0;
+ long now;
int p_idx, g_idx;
int i;
LASSERT(desc->bd_max_iov > 0);
- LASSERT(desc->bd_max_iov <= page_pools.epp_total_pages);
+ LASSERT(desc->bd_max_iov <= page_pools.epp_max_pages);
/* resent bulk, enc pages might have been allocated previously */
if (desc->bd_enc_pages != NULL)
return -ENOMEM;
spin_lock(&page_pools.epp_lock);
-again:
- page_pools.epp_st_reqs++;
+ page_pools.epp_st_access++;
+again:
if (unlikely(page_pools.epp_free_pages < desc->bd_max_iov)) {
- if (tick1 == 0)
- tick1 = cfs_time_current();
+ if (tick == 0)
+ tick = cfs_time_current();
+
+ now = cfs_time_current_sec();
page_pools.epp_st_missings++;
page_pools.epp_pages_short += desc->bd_max_iov;
- if (++page_pools.epp_waitqlen > page_pools.epp_st_max_wqlen)
- page_pools.epp_st_max_wqlen = page_pools.epp_waitqlen;
-
- /* we just wait if someone else is adding more pages, or
- * wait queue length is not deep enough. otherwise try to
- * add more pages in the pools.
- *
- * FIXME the policy of detecting resource tight & growing pool
- * need to be reconsidered. */
- if (page_pools.epp_adding || page_pools.epp_waitqlen < 2 ||
- page_pools.epp_full) {
- set_current_state(TASK_UNINTERRUPTIBLE);
- cfs_waitlink_init(&waitlink);
- cfs_waitq_add(&page_pools.epp_waitq, &waitlink);
+ if (enc_pools_should_grow(desc->bd_max_iov, now)) {
+ page_pools.epp_growing = 1;
spin_unlock(&page_pools.epp_lock);
- cfs_schedule();
+ enc_pools_add_pages(page_pools.epp_pages_short / 2);
spin_lock(&page_pools.epp_lock);
+
+ page_pools.epp_growing = 0;
} else {
- page_pools.epp_adding = 1;
+ if (++page_pools.epp_waitqlen >
+ page_pools.epp_st_max_wqlen)
+ page_pools.epp_st_max_wqlen =
+ page_pools.epp_waitqlen;
+
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ cfs_waitlink_init(&waitlink);
+ cfs_waitq_add(&page_pools.epp_waitq, &waitlink);
spin_unlock(&page_pools.epp_lock);
- enc_pools_add_pages(page_pools.epp_pages_short / 2);
+ cfs_schedule();
spin_lock(&page_pools.epp_lock);
- page_pools.epp_adding = 0;
+ LASSERT(page_pools.epp_waitqlen > 0);
+ page_pools.epp_waitqlen--;
}
LASSERT(page_pools.epp_pages_short >= desc->bd_max_iov);
- LASSERT(page_pools.epp_waitqlen > 0);
page_pools.epp_pages_short -= desc->bd_max_iov;
- page_pools.epp_waitqlen--;
+ this_idle = 0;
goto again;
}
/* record max wait time */
- if (unlikely(tick1 != 0)) {
- tick2 = cfs_time_current();
- if (tick2 - tick1 > page_pools.epp_st_max_wait)
- page_pools.epp_st_max_wait = tick2 - tick1;
+ if (unlikely(tick != 0)) {
+ tick = cfs_time_current() - tick;
+ if (tick > page_pools.epp_st_max_wait)
+ page_pools.epp_st_max_wait = tick;
}
/* proceed with rest of allocation */
if (page_pools.epp_free_pages < page_pools.epp_st_lowfree)
page_pools.epp_st_lowfree = page_pools.epp_free_pages;
+ /*
+ * new idle index = (old * weight + new) / (weight + 1)
+ */
+ if (this_idle == -1) {
+ this_idle = page_pools.epp_free_pages * IDLE_IDX_MAX /
+ page_pools.epp_total_pages;
+ }
+ page_pools.epp_idle_idx = (page_pools.epp_idle_idx * IDLE_IDX_WEIGHT +
+ this_idle) /
+ (IDLE_IDX_WEIGHT + 1);
+
+ page_pools.epp_last_access = cfs_time_current_sec();
+
spin_unlock(&page_pools.epp_lock);
return 0;
}
page_pools.epp_free_pages += desc->bd_max_iov;
- if (unlikely(page_pools.epp_waitqlen)) {
- LASSERT(page_pools.epp_waitqlen > 0);
- LASSERT(cfs_waitq_active(&page_pools.epp_waitq));
- cfs_waitq_broadcast(&page_pools.epp_waitq);
- }
+ enc_pools_wakeup();
spin_unlock(&page_pools.epp_lock);
}
EXPORT_SYMBOL(sptlrpc_enc_pool_put_pages);
+/*
+ * we don't do much stuff for add_user/del_user anymore, except adding some
+ * initial pages in add_user() if current pools are empty, rest would be
+ * handled by the pools's self-adaption.
+ */
+int sptlrpc_enc_pool_add_user(void)
+{
+ int need_grow = 0;
+
+ spin_lock(&page_pools.epp_lock);
+ if (page_pools.epp_growing == 0 && page_pools.epp_total_pages == 0) {
+ page_pools.epp_growing = 1;
+ need_grow = 1;
+ }
+ spin_unlock(&page_pools.epp_lock);
+
+ if (need_grow) {
+ enc_pools_add_pages(PTLRPC_MAX_BRW_PAGES);
+
+ spin_lock(&page_pools.epp_lock);
+ page_pools.epp_growing = 0;
+ enc_pools_wakeup();
+ spin_unlock(&page_pools.epp_lock);
+ }
+ return 0;
+}
+EXPORT_SYMBOL(sptlrpc_enc_pool_add_user);
+
+int sptlrpc_enc_pool_del_user(void)
+{
+ return 0;
+}
+EXPORT_SYMBOL(sptlrpc_enc_pool_del_user);
+
+static inline void enc_pools_alloc(void)
+{
+ LASSERT(page_pools.epp_max_pools);
+ /*
+ * on system with huge memory but small page size, this might lead to
+ * high-order allocation. but it's not common, and we suppose memory
+ * be not too much fragmented at module loading time.
+ */
+ OBD_ALLOC(page_pools.epp_pools,
+ page_pools.epp_max_pools * sizeof(*page_pools.epp_pools));
+}
+
+static inline void enc_pools_free(void)
+{
+ LASSERT(page_pools.epp_max_pools);
+ LASSERT(page_pools.epp_pools);
+
+ OBD_FREE(page_pools.epp_pools,
+ page_pools.epp_max_pools * sizeof(*page_pools.epp_pools));
+}
+
int sptlrpc_enc_pool_init(void)
{
- /* constants */
- page_pools.epp_max_pages = num_physpages / 4;
+ /*
+ * maximum capacity is 1/8 of total physical memory.
+ * is the 1/8 a good number?
+ */
+ page_pools.epp_max_pages = num_physpages / 8;
page_pools.epp_max_pools = npages_to_npools(page_pools.epp_max_pages);
- atomic_set(&page_pools.epp_users, 0);
- atomic_set(&page_pools.epp_users_gone, 0);
-
cfs_waitq_init(&page_pools.epp_waitq);
page_pools.epp_waitqlen = 0;
page_pools.epp_pages_short = 0;
- page_pools.epp_adding = 0;
- page_pools.epp_full = 0;
+ page_pools.epp_growing = 0;
+
+ page_pools.epp_idle_idx = 0;
+ page_pools.epp_last_shrink = cfs_time_current_sec();
+ page_pools.epp_last_access = cfs_time_current_sec();
spin_lock_init(&page_pools.epp_lock);
page_pools.epp_total_pages = 0;
page_pools.epp_free_pages = 0;
- page_pools.epp_st_adds = 0;
- page_pools.epp_st_failadds = 0;
- page_pools.epp_st_reqs = 0;
+ page_pools.epp_st_grows = 0;
+ page_pools.epp_st_grow_fails = 0;
+ page_pools.epp_st_shrinks = 0;
+ page_pools.epp_st_access = 0;
page_pools.epp_st_missings = 0;
page_pools.epp_st_lowfree = 0;
page_pools.epp_st_max_wqlen = 0;
page_pools.epp_st_max_wait = 0;
- OBD_ALLOC(page_pools.epp_pools,
- page_pools.epp_max_pools * sizeof(*page_pools.epp_pools));
+ enc_pools_alloc();
if (page_pools.epp_pools == NULL)
return -ENOMEM;
+ pools_shrinker = set_shrinker(pools_shrinker_seeks, enc_pools_shrink);
+ if (pools_shrinker == NULL) {
+ enc_pools_free();
+ return -ENOMEM;
+ }
+
return 0;
}
{
unsigned long cleaned, npools;
+ LASSERT(pools_shrinker);
LASSERT(page_pools.epp_pools);
LASSERT(page_pools.epp_total_pages == page_pools.epp_free_pages);
+ remove_shrinker(pools_shrinker);
+
npools = npages_to_npools(page_pools.epp_total_pages);
- cleaned = enc_cleanup_pools(page_pools.epp_pools, npools);
+ cleaned = enc_pools_cleanup(page_pools.epp_pools, npools);
LASSERT(cleaned == page_pools.epp_total_pages);
- OBD_FREE(page_pools.epp_pools,
- page_pools.epp_max_pools * sizeof(*page_pools.epp_pools));
+ enc_pools_free();
}
#else /* !__KERNEL__ */
[BULK_CSUM_ALG_SHA512] = { "sha512", 64 },
};
-const char * sptlrpc_bulk_csum_alg2name(__u32 csum_alg)
+const char * sptlrpc_bulk_csum_alg2name(__u8 csum_alg)
{
if (csum_alg < BULK_CSUM_ALG_MAX)
return csum_types[csum_alg].name;
- return "unknown_cksum";
+ return "unknown";
}
EXPORT_SYMBOL(sptlrpc_bulk_csum_alg2name);
-int bulk_sec_desc_size(__u32 csum_alg, int request, int read)
+int bulk_sec_desc_size(__u8 csum_alg, int request, int read)
{
int size = sizeof(struct ptlrpc_bulk_sec_desc);
if (lustre_msg_swabbed(msg)) {
__swab32s(&bsd->bsd_version);
- __swab32s(&bsd->bsd_pad);
- __swab32s(&bsd->bsd_csum_alg);
- __swab32s(&bsd->bsd_priv_alg);
+ __swab16s(&bsd->bsd_pad);
}
if (bsd->bsd_version != 0) {
LASSERT(rsize >= sizeof(*bsdr));
LASSERT(alg < BULK_CSUM_ALG_MAX);
- if (read)
+ if (read) {
bsdr->bsd_csum_alg = alg;
- else {
+ } else {
rc = generate_bulk_csum(desc, alg, bsdr, rsize);
- if (rc) {
- CERROR("client bulk write: failed to perform "
+ if (rc)
+ CERROR("bulk write: client failed to compute "
"checksum: %d\n", rc);
- }
+
+ /* For sending we only compute the wrong checksum instead
+ * of corrupting the data so it is still correct on a redo */
+ if (rc == 0 && OBD_FAIL_CHECK(OBD_FAIL_OSC_CHECKSUM_SEND) &&
+ bsdr->bsd_csum_alg != BULK_CSUM_ALG_NULL)
+ bsdr->bsd_csum[0] ^= 0x1;
}
return rc;
if (!memcmp(cli, srv, csum_size)) {
/* checksum confirmed */
CDEBUG(D_SEC, "bulk write checksum (%s) confirmed\n",
- csum_types[bsdr->bsd_csum_alg].name);
+ csum_types[bsdr->bsd_csum_alg].name);
return 0;
}
}
EXPORT_SYMBOL(bulk_csum_cli_reply);
+#ifdef __KERNEL__
+static void corrupt_bulk_data(struct ptlrpc_bulk_desc *desc)
+{
+ char *ptr;
+ unsigned int off, i;
+
+ for (i = 0; i < desc->bd_iov_count; i++) {
+ if (desc->bd_iov[i].kiov_len == 0)
+ continue;
+
+ ptr = cfs_kmap(desc->bd_iov[i].kiov_page);
+ off = desc->bd_iov[i].kiov_offset & ~CFS_PAGE_MASK;
+ ptr[off] ^= 0x1;
+ cfs_kunmap(desc->bd_iov[i].kiov_page);
+ return;
+ }
+}
+#else
+static void corrupt_bulk_data(struct ptlrpc_bulk_desc *desc)
+{
+}
+#endif /* __KERNEL__ */
+
int bulk_csum_svc(struct ptlrpc_bulk_desc *desc, int read,
struct ptlrpc_bulk_sec_desc *bsdv, int vsize,
struct ptlrpc_bulk_sec_desc *bsdr, int rsize)
CERROR("bulk read: server failed to generate %s "
"checksum: %d\n",
csum_types[bsdv->bsd_csum_alg].name, rc);
- } else
+
+ /* corrupt the data after we compute the checksum, to
+ * simulate an OST->client data error */
+ if (rc == 0 && OBD_FAIL_CHECK(OBD_FAIL_OSC_CHECKSUM_RECEIVE))
+ corrupt_bulk_data(desc);
+ } else {
rc = verify_bulk_csum(desc, 0, bsdv, vsize, bsdr, rsize);
+ }
return rc;
}
[BULK_PRIV_ALG_ARC4] = { "arc4", 0 },
};
-const char * sptlrpc_bulk_priv_alg2name(__u32 priv_alg)
+const char * sptlrpc_bulk_priv_alg2name(__u8 priv_alg)
{
if (priv_alg < BULK_PRIV_ALG_MAX)
return priv_types[priv_alg].name;
- return "unknown_priv";
+ return "unknown";
}
EXPORT_SYMBOL(sptlrpc_bulk_priv_alg2name);
-__u32 sptlrpc_bulk_priv_alg2flags(__u32 priv_alg)
+__u32 sptlrpc_bulk_priv_alg2flags(__u8 priv_alg)
{
if (priv_alg < BULK_PRIV_ALG_MAX)
return priv_types[priv_alg].flags;
--- /dev/null
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ * Copyright (C) 2007 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.
+ */
+
+#ifndef EXPORT_SYMTAB
+#define EXPORT_SYMTAB
+#endif
+#define DEBUG_SUBSYSTEM S_SEC
+
+#include <libcfs/libcfs.h>
+#ifndef __KERNEL__
+#include <liblustre.h>
+#include <libcfs/list.h>
+#else
+#include <linux/crypto.h>
+#include <linux/key.h>
+#endif
+
+#include <obd.h>
+#include <obd_class.h>
+#include <obd_support.h>
+#include <lustre_net.h>
+#include <lustre_import.h>
+#include <lustre_dlm.h>
+#include <lustre_sec.h>
+
+#include "ptlrpc_internal.h"
+
+const char *sptlrpc_part2name(enum lustre_sec_part part)
+{
+ switch (part) {
+ case LUSTRE_SP_CLI:
+ return "cli";
+ case LUSTRE_SP_MDT:
+ return "mdt";
+ case LUSTRE_SP_OST:
+ return "ost";
+ case LUSTRE_SP_MGS:
+ return "mgs";
+ case LUSTRE_SP_ANY:
+ return "any";
+ default:
+ return "err";
+ }
+}
+EXPORT_SYMBOL(sptlrpc_part2name);
+
+enum lustre_sec_part sptlrpc_target_sec_part(struct obd_device *obd)
+{
+ const char *type = obd->obd_type->typ_name;
+
+ if (!strcmp(type, LUSTRE_MDT_NAME))
+ return LUSTRE_SP_MDT;
+ if (!strcmp(type, LUSTRE_OST_NAME))
+ return LUSTRE_SP_OST;
+ if (!strcmp(type, LUSTRE_MGS_NAME))
+ return LUSTRE_SP_MGS;
+
+ CERROR("unknown target %p(%s)\n", obd, type);
+ return LUSTRE_SP_ANY;
+}
+EXPORT_SYMBOL(sptlrpc_target_sec_part);
+
+/****************************************
+ * user supplied flavor string parsing *
+ ****************************************/
+
+typedef enum {
+ BULK_TYPE_N = 0,
+ BULK_TYPE_I = 1,
+ BULK_TYPE_P = 2
+} bulk_type_t;
+
+static void get_default_flavor(struct sptlrpc_flavor *sf)
+{
+ sf->sf_rpc = SPTLRPC_FLVR_NULL;
+ sf->sf_bulk_priv = BULK_PRIV_ALG_NULL;
+ sf->sf_bulk_csum = BULK_CSUM_ALG_NULL;
+ sf->sf_flags = 0;
+}
+
+static void get_flavor_by_rpc(struct sptlrpc_rule *rule, __u16 rpc_flavor)
+{
+ get_default_flavor(&rule->sr_flvr);
+
+ rule->sr_flvr.sf_rpc = rpc_flavor;
+
+ switch (rpc_flavor) {
+ case SPTLRPC_FLVR_NULL:
+ case SPTLRPC_FLVR_PLAIN:
+ case SPTLRPC_FLVR_KRB5N:
+ case SPTLRPC_FLVR_KRB5A:
+ break;
+ case SPTLRPC_FLVR_KRB5P:
+ rule->sr_flvr.sf_bulk_priv = BULK_PRIV_ALG_ARC4;
+ /* fall through */
+ case SPTLRPC_FLVR_KRB5I:
+ rule->sr_flvr.sf_bulk_csum = BULK_CSUM_ALG_SHA1;
+ break;
+ default:
+ LBUG();
+ }
+}
+
+static void get_flavor_by_bulk(struct sptlrpc_rule *rule, bulk_type_t bulk_type)
+{
+ switch (bulk_type) {
+ case BULK_TYPE_N:
+ rule->sr_flvr.sf_bulk_csum = BULK_CSUM_ALG_NULL;
+ rule->sr_flvr.sf_bulk_priv = BULK_PRIV_ALG_NULL;
+ break;
+ case BULK_TYPE_I:
+ rule->sr_flvr.sf_bulk_csum = BULK_CSUM_ALG_SHA1;
+ rule->sr_flvr.sf_bulk_priv = BULK_PRIV_ALG_NULL;
+ break;
+ case BULK_TYPE_P:
+ rule->sr_flvr.sf_bulk_csum = BULK_CSUM_ALG_SHA1;
+ rule->sr_flvr.sf_bulk_priv = BULK_PRIV_ALG_ARC4;
+ break;
+ default:
+ LBUG();
+ }
+}
+
+static __u16 __flavors[] = {
+ SPTLRPC_FLVR_NULL,
+ SPTLRPC_FLVR_PLAIN,
+ SPTLRPC_FLVR_KRB5N,
+ SPTLRPC_FLVR_KRB5A,
+ SPTLRPC_FLVR_KRB5I,
+ SPTLRPC_FLVR_KRB5P,
+};
+
+#define __nflavors ARRAY_SIZE(__flavors)
+
+/*
+ * flavor string format: rpc[-bulk{n|i|p}[:cksum/enc]]
+ * for examples:
+ * null
+ * plain-bulki
+ * krb5p-bulkn
+ * krb5i-bulkp
+ * krb5i-bulkp:sha512/arc4
+ */
+static int parse_flavor(char *str, struct sptlrpc_rule *rule)
+{
+ const char *f;
+ char *bulk, *alg, *enc;
+ char buf[64];
+ bulk_type_t bulk_type;
+ __u8 i;
+ ENTRY;
+
+ if (str == NULL || str[0] == '\0') {
+ rule->sr_flvr.sf_rpc = SPTLRPC_FLVR_INVALID;
+ goto out;
+ }
+
+ for (i = 0; i < __nflavors; i++) {
+ f = sptlrpc_rpcflavor2name(__flavors[i]);
+ if (strncmp(str, f, strlen(f)) == 0)
+ break;
+ }
+
+ if (i >= __nflavors)
+ GOTO(invalid, -EINVAL);
+
+ /* prepare local buffer thus we can modify it as we want */
+ strncpy(buf, str, 64);
+ buf[64 - 1] = '\0';
+
+ /* find bulk string */
+ bulk = strchr(buf, '-');
+ if (bulk)
+ *bulk++ = '\0';
+
+ /* now the first part must equal to rpc flavor name */
+ if (strcmp(buf, f) != 0)
+ GOTO(invalid, -EINVAL);
+
+ get_flavor_by_rpc(rule, __flavors[i]);
+
+ if (bulk == NULL)
+ goto out;
+
+ /* find bulk algorithm string */
+ alg = strchr(bulk, ':');
+ if (alg)
+ *alg++ = '\0';
+
+ /* verify bulk section */
+ if (strcmp(bulk, "bulkn") == 0) {
+ rule->sr_flvr.sf_bulk_csum = BULK_CSUM_ALG_NULL;
+ rule->sr_flvr.sf_bulk_priv = BULK_PRIV_ALG_NULL;
+ bulk_type = BULK_TYPE_N;
+ } else if (strcmp(bulk, "bulki") == 0)
+ bulk_type = BULK_TYPE_I;
+ else if (strcmp(bulk, "bulkp") == 0)
+ bulk_type = BULK_TYPE_P;
+ else
+ GOTO(invalid, -EINVAL);
+
+ /* null flavor don't support bulk i/p */
+ if (__flavors[i] == SPTLRPC_FLVR_NULL && bulk_type != BULK_TYPE_N)
+ GOTO(invalid, -EINVAL);
+
+ /* plain policy dosen't support bulk p */
+ if (__flavors[i] == SPTLRPC_FLVR_PLAIN && bulk_type == BULK_TYPE_P)
+ GOTO(invalid, -EINVAL);
+
+ get_flavor_by_bulk(rule, bulk_type);
+
+ if (alg == NULL)
+ goto out;
+
+ /* find encryption algorithm string */
+ enc = strchr(alg, '/');
+ if (enc)
+ *enc++ = '\0';
+
+ /* checksum algorithm */
+ for (i = 0; i < BULK_CSUM_ALG_MAX; i++) {
+ if (strcmp(alg, sptlrpc_bulk_csum_alg2name(i)) == 0) {
+ rule->sr_flvr.sf_bulk_csum = i;
+ break;
+ }
+ }
+ if (i >= BULK_CSUM_ALG_MAX)
+ GOTO(invalid, -EINVAL);
+
+ /* privacy algorithm */
+ if (enc) {
+ for (i = 0; i < BULK_PRIV_ALG_MAX; i++) {
+ if (strcmp(enc, sptlrpc_bulk_priv_alg2name(i)) == 0) {
+ rule->sr_flvr.sf_bulk_priv = i;
+ break;
+ }
+ }
+ if (i >= BULK_PRIV_ALG_MAX)
+ GOTO(invalid, -EINVAL);
+ }
+
+ /*
+ * bulk combination sanity checks
+ */
+ if (bulk_type == BULK_TYPE_P &&
+ rule->sr_flvr.sf_bulk_priv == BULK_PRIV_ALG_NULL)
+ GOTO(invalid, -EINVAL);
+
+ if (bulk_type == BULK_TYPE_I &&
+ (rule->sr_flvr.sf_bulk_csum == BULK_CSUM_ALG_NULL ||
+ rule->sr_flvr.sf_bulk_priv != BULK_PRIV_ALG_NULL))
+ GOTO(invalid, -EINVAL);
+
+ if (bulk_type == BULK_TYPE_N &&
+ (rule->sr_flvr.sf_bulk_csum != BULK_CSUM_ALG_NULL ||
+ rule->sr_flvr.sf_bulk_priv != BULK_PRIV_ALG_NULL))
+ GOTO(invalid, -EINVAL);
+
+out:
+ return 0;
+invalid:
+ CERROR("invalid flavor string: %s\n", str);
+ return -EINVAL;
+}
+
+/****************************************
+ * configure rules *
+ ****************************************/
+
+static void sptlrpc_rule_init(struct sptlrpc_rule *rule)
+{
+ rule->sr_netid = LNET_NIDNET(LNET_NID_ANY);
+ rule->sr_from = LUSTRE_SP_ANY;
+ rule->sr_to = LUSTRE_SP_ANY;
+ rule->sr_padding = 0;
+
+ get_default_flavor(&rule->sr_flvr);
+}
+
+/*
+ * format: network[.direction]=flavor
+ */
+int sptlrpc_parse_rule(char *param, struct sptlrpc_rule *rule)
+{
+ char *flavor, *dir;
+ int rc;
+
+ sptlrpc_rule_init(rule);
+
+ flavor = strchr(param, '=');
+ if (flavor == NULL) {
+ CERROR("invalid param, no '='\n");
+ RETURN(-EINVAL);
+ }
+ *flavor++ = '\0';
+
+ dir = strchr(param, '.');
+ if (dir)
+ *dir++ = '\0';
+
+ /* 1.1 network */
+ if (strcmp(param, "default")) {
+ rule->sr_netid = libcfs_str2net(param);
+ if (rule->sr_netid == LNET_NIDNET(LNET_NID_ANY)) {
+ CERROR("invalid network name: %s\n", param);
+ RETURN(-EINVAL);
+ }
+ }
+
+ /* 1.2 direction */
+ if (dir) {
+ if (!strcmp(dir, "mdt2ost")) {
+ rule->sr_from = LUSTRE_SP_MDT;
+ rule->sr_to = LUSTRE_SP_OST;
+ } else if (!strcmp(dir, "mdt2mdt")) {
+ rule->sr_from = LUSTRE_SP_MDT;
+ rule->sr_to = LUSTRE_SP_MDT;
+ } else if (!strcmp(dir, "cli2ost")) {
+ rule->sr_from = LUSTRE_SP_CLI;
+ rule->sr_to = LUSTRE_SP_OST;
+ } else if (!strcmp(dir, "cli2mdt")) {
+ rule->sr_from = LUSTRE_SP_CLI;
+ rule->sr_to = LUSTRE_SP_MDT;
+ } else {
+ CERROR("invalid rule dir segment: %s\n", dir);
+ RETURN(-EINVAL);
+ }
+ }
+
+ /* 2.1 flavor */
+ rc = parse_flavor(flavor, rule);
+ if (rc)
+ RETURN(-EINVAL);
+
+ RETURN(0);
+}
+EXPORT_SYMBOL(sptlrpc_parse_rule);
+
+void sptlrpc_rule_set_free(struct sptlrpc_rule_set *rset)
+{
+ LASSERT(rset->srs_nslot ||
+ (rset->srs_nrule == 0 && rset->srs_rules == NULL));
+
+ if (rset->srs_nslot) {
+ OBD_FREE(rset->srs_rules,
+ rset->srs_nslot * sizeof(*rset->srs_rules));
+ sptlrpc_rule_set_init(rset);
+ }
+}
+EXPORT_SYMBOL(sptlrpc_rule_set_free);
+
+/*
+ * return 0 if the rule set could accomodate one more rule.
+ * if @expand != 0, the rule set might be expanded.
+ */
+int sptlrpc_rule_set_expand(struct sptlrpc_rule_set *rset, int expand)
+{
+ struct sptlrpc_rule *rules;
+ int nslot;
+
+ if (rset->srs_nrule < rset->srs_nslot)
+ return 0;
+
+ if (expand == 0)
+ return -E2BIG;
+
+ if (rset->srs_nslot == 0)
+ nslot = 8;
+ else
+ nslot = rset->srs_nslot + 8;
+
+ /* better use realloc() if available */
+ OBD_ALLOC(rules, nslot * sizeof(*rset->srs_rules));
+ if (rules == NULL)
+ return -ENOMEM;
+
+ memcpy(rules, rset->srs_rules,
+ rset->srs_nrule * sizeof(*rset->srs_rules));
+
+ if (rset->srs_rules)
+ OBD_FREE(rset->srs_rules,
+ rset->srs_nslot * sizeof(*rset->srs_rules));
+
+ rset->srs_rules = rules;
+ rset->srs_nslot = nslot;
+ return 0;
+}
+EXPORT_SYMBOL(sptlrpc_rule_set_expand);
+
+static inline int rule_spec_dir(struct sptlrpc_rule *rule)
+{
+ return (rule->sr_from != LUSTRE_SP_ANY ||
+ rule->sr_to != LUSTRE_SP_ANY);
+}
+static inline int rule_spec_net(struct sptlrpc_rule *rule)
+{
+ return (rule->sr_netid != LNET_NIDNET(LNET_NID_ANY));
+}
+static inline int rule_match_dir(struct sptlrpc_rule *r1,
+ struct sptlrpc_rule *r2)
+{
+ return (r1->sr_from == r2->sr_from && r1->sr_to == r2->sr_to);
+}
+static inline int rule_match_net(struct sptlrpc_rule *r1,
+ struct sptlrpc_rule *r2)
+{
+ return (r1->sr_netid == r2->sr_netid);
+}
+
+/*
+ * merge @rule into @rset.
+ * if @expand != 0 then @rset slots might be expanded.
+ */
+int sptlrpc_rule_set_merge(struct sptlrpc_rule_set *rset,
+ struct sptlrpc_rule *rule,
+ int expand)
+{
+ struct sptlrpc_rule *p = rset->srs_rules;
+ int spec_dir, spec_net;
+ int rc, n, match = 0;
+
+ spec_net = rule_spec_net(rule);
+ spec_dir = rule_spec_dir(rule);
+
+ for (n = 0; n < rset->srs_nrule; n++) {
+ p = &rset->srs_rules[n];
+
+ /* test network match, if failed:
+ * - spec rule: skip rules which is also spec rule match, until
+ * we hit a wild rule, which means no more chance
+ * - wild rule: skip until reach the one which is also wild
+ * and matches
+ */
+ if (!rule_match_net(p, rule)) {
+ if (spec_net) {
+ if (rule_spec_net(p))
+ continue;
+ else
+ break;
+ } else {
+ continue;
+ }
+ }
+
+ /* test dir match, same logic as net matching */
+ if (!rule_match_dir(p, rule)) {
+ if (spec_dir) {
+ if (rule_spec_dir(p))
+ continue;
+ else
+ break;
+ } else {
+ continue;
+ }
+ }
+
+ /* find a match */
+ match = 1;
+ break;
+ }
+
+ if (match) {
+ LASSERT(n >= 0 && n < rset->srs_nrule);
+
+ if (rule->sr_flvr.sf_rpc == SPTLRPC_FLVR_INVALID) {
+ /* remove this rule */
+ if (n < rset->srs_nrule - 1)
+ memmove(&rset->srs_rules[n],
+ &rset->srs_rules[n + 1],
+ (rset->srs_nrule - n - 1) *
+ sizeof(*rule));
+ rset->srs_nrule--;
+ } else {
+ /* override the rule */
+ memcpy(&rset->srs_rules[n], rule, sizeof(*rule));
+ }
+ } else {
+ LASSERT(n >= 0 && n <= rset->srs_nrule);
+
+ if (rule->sr_flvr.sf_rpc != SPTLRPC_FLVR_INVALID) {
+ rc = sptlrpc_rule_set_expand(rset, expand);
+ if (rc)
+ return rc;
+
+ if (n < rset->srs_nrule)
+ memmove(&rset->srs_rules[n + 1],
+ &rset->srs_rules[n],
+ (rset->srs_nrule - n) * sizeof(*rule));
+ memcpy(&rset->srs_rules[n], rule, sizeof(*rule));
+ rset->srs_nrule++;
+ } else {
+ CWARN("ignore the unmatched deletion\n");
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(sptlrpc_rule_set_merge);
+
+int sptlrpc_rule_set_from_log(struct sptlrpc_rule_set *rset,
+ struct sptlrpc_conf_log *log)
+{
+ LASSERT(rset);
+ LASSERT(log);
+
+ sptlrpc_rule_set_free(rset);
+
+ if (log->scl_nrule == 0)
+ return 0;
+
+ OBD_ALLOC(rset->srs_rules, log->scl_nrule * sizeof(*log->scl_rules));
+ if (!rset->srs_rules)
+ return -ENOMEM;
+
+ memcpy(rset->srs_rules, log->scl_rules,
+ log->scl_nrule * sizeof(*log->scl_rules));
+ rset->srs_nslot = rset->srs_nrule = log->scl_nrule;
+ return 0;
+}
+EXPORT_SYMBOL(sptlrpc_rule_set_from_log);
+
+/*
+ * according to NID/from choose a flavor from rule set.
+ */
+void sptlrpc_rule_set_choose(struct sptlrpc_rule_set *rset,
+ enum lustre_sec_part from,
+ lnet_nid_t nid,
+ struct sptlrpc_flavor *sf)
+{
+ struct sptlrpc_rule *r;
+ int n;
+
+ for (n = 0; n < rset->srs_nrule; n++) {
+ r = &rset->srs_rules[n];
+
+ if (LNET_NIDNET(nid) != LNET_NIDNET(LNET_NID_ANY) &&
+ r->sr_netid != LNET_NIDNET(LNET_NID_ANY) &&
+ LNET_NIDNET(nid) != r->sr_netid)
+ continue;
+
+ if (from != LUSTRE_SP_ANY && r->sr_from != LUSTRE_SP_ANY &&
+ from != r->sr_from)
+ continue;
+
+ *sf = r->sr_flvr;
+ return;
+ }
+
+ /* no match found, set as default flavor */
+ get_default_flavor(sf);
+}
+EXPORT_SYMBOL(sptlrpc_rule_set_choose);
+
+void sptlrpc_rule_set_dump(struct sptlrpc_rule_set *rset)
+{
+ struct sptlrpc_rule *r;
+ int n;
+
+ for (n = 0; n < rset->srs_nrule; n++) {
+ r = &rset->srs_rules[n];
+ CWARN("<%02d> from %x to %x, net %x, rpc %x\n", n,
+ r->sr_from, r->sr_to, r->sr_netid, r->sr_flvr.sf_rpc);
+ }
+}
+EXPORT_SYMBOL(sptlrpc_rule_set_dump);
+
+/****************************************
+ * sptlrpc config log *
+ ****************************************/
+
+struct sptlrpc_conf_log *sptlrpc_conf_log_alloc(void)
+{
+ struct sptlrpc_conf_log *log;
+
+ OBD_ALLOC_PTR(log);
+ if (log == NULL)
+ return ERR_PTR(-ENOMEM);
+
+ log->scl_max = SPTLRPC_CONF_LOG_MAX;
+ return log;
+}
+EXPORT_SYMBOL(sptlrpc_conf_log_alloc);
+
+void sptlrpc_conf_log_free(struct sptlrpc_conf_log *log)
+{
+ LASSERT(log->scl_max == SPTLRPC_CONF_LOG_MAX);
+ OBD_FREE_PTR(log);
+}
+EXPORT_SYMBOL(sptlrpc_conf_log_free);
+
+static __u32 get_log_rule_flags(enum lustre_sec_part from,
+ enum lustre_sec_part to,
+ unsigned int fl_udesc)
+{
+ /* MDT->MDT; MDT->OST */
+ if (from == LUSTRE_SP_MDT)
+ return PTLRPC_SEC_FL_ROOTONLY;
+ /* CLI->OST */
+ if (from == LUSTRE_SP_CLI && to == LUSTRE_SP_OST)
+ return PTLRPC_SEC_FL_ROOTONLY | PTLRPC_SEC_FL_BULK;
+ /* CLI->MDT */
+ if (from == LUSTRE_SP_CLI && to == LUSTRE_SP_MDT)
+ if (fl_udesc)
+ return PTLRPC_SEC_FL_UDESC;
+
+ return 0;
+}
+
+/*
+ * generate config log: merge general and target rules, which
+ * match @from @to
+ */
+int sptlrpc_conf_log_populate(struct sptlrpc_rule_set *gen,
+ struct sptlrpc_rule_set *tgt,
+ enum lustre_sec_part from,
+ enum lustre_sec_part to,
+ unsigned int fl_udesc,
+ struct sptlrpc_conf_log *log)
+{
+ struct sptlrpc_rule_set *src[2] = { gen, tgt };
+ struct sptlrpc_rule_set dst;
+ struct sptlrpc_rule *rule;
+ __u32 flags;
+ int i, n, rc;
+
+ LASSERT(log);
+
+ dst.srs_nslot = log->scl_max;
+ dst.srs_nrule = 0;
+ dst.srs_rules = log->scl_rules;
+
+ /* merge general rules firstly, then target-specific rules */
+ for (i = 0; i < 2; i++) {
+ if (src[i] == NULL)
+ continue;
+
+ for (n = 0; n < src[i]->srs_nrule; n++) {
+ rule = &src[i]->srs_rules[n];
+
+ if (from != LUSTRE_SP_ANY &&
+ rule->sr_from != LUSTRE_SP_ANY &&
+ rule->sr_from != from)
+ continue;
+ if (to != LUSTRE_SP_ANY &&
+ rule->sr_to != LUSTRE_SP_ANY &&
+ rule->sr_to != to)
+ continue;
+
+ rc = sptlrpc_rule_set_merge(&dst, rule, 0);
+ if (rc) {
+ CERROR("can't merge: %d\n", rc);
+ return rc;
+ }
+ }
+ }
+
+ log->scl_nrule = dst.srs_nrule;
+
+ /* set flags for each rule */
+ flags = get_log_rule_flags(from, to, fl_udesc);
+
+ for (i = 0; i < log->scl_nrule; i++) {
+ log->scl_rules[i].sr_flvr.sf_flags = flags;
+
+ /* also clear the from/to fields which don't need to be known
+ * accordingly. @from == ANY means this log is for target,
+ * otherwise for client. */
+ if (from != LUSTRE_SP_ANY)
+ log->scl_rules[i].sr_from = LUSTRE_SP_ANY;
+ log->scl_rules[i].sr_to = LUSTRE_SP_ANY;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(sptlrpc_conf_log_populate);
+
+/*
+ * extract config log from @lcfg
+ */
+struct sptlrpc_conf_log *sptlrpc_conf_log_extract(struct lustre_cfg *lcfg)
+{
+ struct sptlrpc_conf_log *log;
+ struct sptlrpc_rule *r;
+ int i;
+ ENTRY;
+
+ log = lustre_cfg_buf(lcfg, 1);
+ if (log == NULL) {
+ CERROR("no sptlrpc config data\n");
+ RETURN(ERR_PTR(-EINVAL));
+ }
+
+ if (lcfg->lcfg_version == __swab32(LUSTRE_CFG_VERSION)) {
+ __swab32s(&log->scl_max);
+ __swab32s(&log->scl_nrule);
+ }
+
+ if (LUSTRE_CFG_BUFLEN(lcfg, 1) <
+ log->scl_max * sizeof(log->scl_rules[0])) {
+ CERROR("mal-formed config log\n");
+ RETURN(ERR_PTR(-EINVAL));
+ }
+
+ if (lcfg->lcfg_version == __swab32(LUSTRE_CFG_VERSION)) {
+ for (i = 0; i < log->scl_nrule; i++) {
+ r = &log->scl_rules[i];
+ __swab32s(&r->sr_netid);
+ __swab16s(&r->sr_flvr.sf_rpc);
+ __swab32s(&r->sr_flvr.sf_flags);
+ }
+ }
+
+ RETURN(log);
+}
+EXPORT_SYMBOL(sptlrpc_conf_log_extract);
+
+void sptlrpc_conf_log_cleanup(struct sptlrpc_conf_log *log)
+{
+ log->scl_nrule = 0;
+ memset(log->scl_rules, 0, sizeof(log->scl_rules));
+}
+EXPORT_SYMBOL(sptlrpc_conf_log_cleanup);
+
+void sptlrpc_conf_log_dump(struct sptlrpc_conf_log *log)
+{
+ struct sptlrpc_rule *r;
+ int n;
+
+ CWARN("max %u, rule# %u part %u\n",
+ log->scl_max, log->scl_nrule, log->scl_part);
+
+ for (n = 0; n < log->scl_nrule; n++) {
+ r = &log->scl_rules[n];
+ CWARN("<%02d> %x -> %x, net %x, rpc %x\n", n,
+ r->sr_from, r->sr_to, r->sr_netid, r->sr_flvr.sf_rpc);
+ }
+}
+EXPORT_SYMBOL(sptlrpc_conf_log_dump);
+
+/*
+ * caller should guarantee that no concurrent calls to this function
+ */
+#define SEC_ADAPT_DELAY (10)
+
+int sptlrpc_cliobd_process_config(struct obd_device *obd,
+ struct lustre_cfg *lcfg)
+{
+ struct sptlrpc_conf_log *log;
+ struct obd_import *imp;
+ int rc;
+
+ log = sptlrpc_conf_log_extract(lcfg);
+ if (IS_ERR(log)) {
+ CERROR("extract log error: %ld\n", PTR_ERR(log));
+ return PTR_ERR(log);
+ }
+
+ obd->u.cli.cl_sec_part = log->scl_part;
+
+ rc = sptlrpc_rule_set_from_log(&obd->u.cli.cl_sptlrpc_rset, log);
+ if (rc) {
+ CERROR("failed create rule set: %d\n", rc);
+ return rc;
+ }
+
+ imp = obd->u.cli.cl_import;
+ if (imp == NULL)
+ return 0;
+
+ /* even if imp_sec_expire is already set, we'll override it to a
+ * newer (later) time */
+ spin_lock(&imp->imp_lock);
+ if (imp->imp_sec)
+ imp->imp_sec_expire = cfs_time_current_sec() + SEC_ADAPT_DELAY;
+ spin_unlock(&imp->imp_lock);
+ return 0;
+}
+EXPORT_SYMBOL(sptlrpc_cliobd_process_config);
#ifndef __KERNEL__
#include <liblustre.h>
+#else
+#include <libcfs/libcfs.h>
#endif
#include <obd_support.h>
void sptlrpc_gc_add_sec(struct ptlrpc_sec *sec)
{
- if (!list_empty(&sec->ps_gc_list)) {
- CERROR("sec %p(%s) already in gc list\n",
- sec, sec->ps_policy->sp_name);
- return;
- }
+ LASSERT(sec->ps_policy->sp_cops->gc_ctx);
+ LASSERT(sec->ps_gc_interval > 0);
+ LASSERT(list_empty(&sec->ps_gc_list));
+
+ sec->ps_gc_next = cfs_time_current_sec() + sec->ps_gc_interval;
spin_lock(&sec_gc_list_lock);
list_add_tail(&sec_gc_list, &sec->ps_gc_list);
might_sleep();
+ /* signal before list_del to make iteration in gc thread safe */
+ atomic_inc(&sec_gc_wait_del);
+
spin_lock(&sec_gc_list_lock);
list_del_init(&sec->ps_gc_list);
spin_unlock(&sec_gc_list_lock);
/* barrier */
- atomic_inc(&sec_gc_wait_del);
mutex_down(&sec_gc_mutex);
mutex_up(&sec_gc_mutex);
+
atomic_dec(&sec_gc_wait_del);
CDEBUG(D_SEC, "del sec %p(%s)\n", sec, sec->ps_policy->sp_name);
static void sec_do_gc(struct ptlrpc_sec *sec)
{
- cfs_time_t now = cfs_time_current_sec();
+ LASSERT(sec->ps_policy->sp_cops->gc_ctx);
if (unlikely(sec->ps_gc_next == 0)) {
CWARN("sec %p(%s) has 0 gc time\n",
return;
}
- if (unlikely(sec->ps_policy->sp_cops->gc_ctx == NULL)) {
- CWARN("sec %p(%s) is not prepared for gc\n",
- sec, sec->ps_policy->sp_name);
- return;
- }
-
CDEBUG(D_SEC, "check on sec %p(%s)\n", sec, sec->ps_policy->sp_name);
- if (time_after(sec->ps_gc_next, now))
+ if (cfs_time_after(sec->ps_gc_next, cfs_time_current_sec()))
return;
sec->ps_policy->sp_cops->gc_ctx(sec);
- sec->ps_gc_next = now + sec->ps_gc_interval;
+ sec->ps_gc_next = cfs_time_current_sec() + sec->ps_gc_interval;
}
static int sec_gc_main(void *arg)
struct ptlrpc_thread *thread = (struct ptlrpc_thread *) arg;
struct l_wait_info lwi;
- cfs_daemonize("sptlrpc_ctx_gc");
+ cfs_daemonize("sptlrpc_gc");
/* Record that the thread is running */
thread->t_flags = SVC_RUNNING;
cfs_waitq_signal(&thread->t_ctl_waitq);
while (1) {
- struct ptlrpc_sec *sec, *next;
+ struct ptlrpc_sec *sec;
thread->t_flags &= ~SVC_SIGNAL;
sec_process_ctx_list();
again:
+ /* go through sec list do gc.
+ * FIXME here we iterate through the whole list each time which
+ * is not optimal. we perhaps want to use balanced binary tree
+ * to trace each sec as order of expiry time.
+ * another issue here is we wakeup as fixed interval instead of
+ * according to each sec's expiry time */
mutex_down(&sec_gc_mutex);
- list_for_each_entry_safe(sec, next, &sec_gc_list, ps_gc_list) {
+ list_for_each_entry(sec, &sec_gc_list, ps_gc_list) {
/* if someone is waiting to be deleted, let it
* proceed as soon as possible. */
if (atomic_read(&sec_gc_wait_del)) {
- CWARN("deletion pending, retry\n");
+ CWARN("deletion pending, start over\n");
mutex_up(&sec_gc_mutex);
goto again;
}
}
mutex_up(&sec_gc_mutex);
+ /* check ctx list again before sleep */
+ sec_process_ctx_list();
+
lwi = LWI_TIMEOUT(SEC_GC_INTERVAL * HZ, NULL, NULL);
l_wait_event(thread->t_ctl_waitq,
thread->t_flags & (SVC_STOPPING | SVC_SIGNAL),
strncat(buf, "reverse,", bufsize);
if (flags & PTLRPC_SEC_FL_ROOTONLY)
strncat(buf, "rootonly,", bufsize);
+ if (flags & PTLRPC_SEC_FL_UDESC)
+ strncat(buf, "udesc,", bufsize);
if (flags & PTLRPC_SEC_FL_BULK)
strncat(buf, "bulk,", bufsize);
if (buf[0] == '\0')
}
-int sptlrpc_lprocfs_rd(char *page, char **start, off_t off, int count,
- int *eof, void *data)
+static int sptlrpc_info_lprocfs_seq_show(struct seq_file *seq, void *v)
{
- struct obd_device *obd = data;
- struct sec_flavor_config *conf = &obd->u.cli.cl_sec_conf;
- struct ptlrpc_sec *sec = NULL;
- char flags_str[32];
- int written;
-
- if (obd == NULL)
- return 0;
-
- LASSERT(strcmp(obd->obd_type->typ_name, LUSTRE_OSC_NAME) == 0 ||
- strcmp(obd->obd_type->typ_name, LUSTRE_MDC_NAME) == 0 ||
- strcmp(obd->obd_type->typ_name, LUSTRE_MGC_NAME) == 0);
- LASSERT(conf->sfc_bulk_csum < BULK_CSUM_ALG_MAX);
- LASSERT(conf->sfc_bulk_priv < BULK_PRIV_ALG_MAX);
-
- if (obd->u.cli.cl_import)
- sec = obd->u.cli.cl_import->imp_sec;
-
- if (sec == NULL) {
- written = snprintf(page, count, "\n");
+ struct obd_device *dev = seq->private;
+ struct client_obd *cli = &dev->u.cli;
+ struct ptlrpc_sec *sec = NULL;
+ char flags_str[32];
+
+ LASSERT(strcmp(dev->obd_type->typ_name, LUSTRE_OSC_NAME) == 0 ||
+ strcmp(dev->obd_type->typ_name, LUSTRE_MDC_NAME) == 0 ||
+ strcmp(dev->obd_type->typ_name, LUSTRE_MGC_NAME) == 0);
+
+ if (cli->cl_import)
+ sec = sptlrpc_import_sec_ref(cli->cl_import);
+ if (sec == NULL)
goto out;
+
+ sec_flags2str(sec->ps_flvr.sf_flags, flags_str, sizeof(flags_str));
+
+ seq_printf(seq, "rpc flavor: %s\n",
+ sptlrpc_rpcflavor2name(sec->ps_flvr.sf_rpc));
+ seq_printf(seq, "bulk flavor: %s/%s\n",
+ sptlrpc_bulk_csum_alg2name(sec->ps_flvr.sf_bulk_csum),
+ sptlrpc_bulk_priv_alg2name(sec->ps_flvr.sf_bulk_priv));
+ seq_printf(seq, "flags: %s\n", flags_str);
+ seq_printf(seq, "id: %d\n", sec->ps_id);
+ seq_printf(seq, "refcount: %d\n", atomic_read(&sec->ps_refcount));
+ seq_printf(seq, "nctx: %d\n", atomic_read(&sec->ps_nctx));
+ seq_printf(seq, "gc internal %ld\n", sec->ps_gc_interval);
+ seq_printf(seq, "gc next %ld\n",
+ sec->ps_gc_interval ?
+ sec->ps_gc_next - cfs_time_current_sec() : 0);
+
+ sptlrpc_sec_put(sec);
+out:
+ return 0;
+}
+LPROC_SEQ_FOPS_RO(sptlrpc_info_lprocfs);
+
+static int sptlrpc_ctxs_lprocfs_seq_show(struct seq_file *seq, void *v)
+{
+ struct obd_device *dev = seq->private;
+ struct client_obd *cli = &dev->u.cli;
+ struct ptlrpc_sec *sec = NULL;
+
+ LASSERT(strcmp(dev->obd_type->typ_name, LUSTRE_OSC_NAME) == 0 ||
+ strcmp(dev->obd_type->typ_name, LUSTRE_MDC_NAME) == 0 ||
+ strcmp(dev->obd_type->typ_name, LUSTRE_MGC_NAME) == 0);
+
+ if (cli->cl_import)
+ sec = sptlrpc_import_sec_ref(cli->cl_import);
+ if (sec == NULL)
+ goto out;
+
+ if (sec->ps_policy->sp_cops->display)
+ sec->ps_policy->sp_cops->display(sec, seq);
+
+ sptlrpc_sec_put(sec);
+out:
+ return 0;
+}
+LPROC_SEQ_FOPS_RO(sptlrpc_ctxs_lprocfs);
+
+int sptlrpc_lprocfs_cliobd_attach(struct obd_device *dev)
+{
+ int rc;
+
+ if (strcmp(dev->obd_type->typ_name, LUSTRE_OSC_NAME) != 0 &&
+ strcmp(dev->obd_type->typ_name, LUSTRE_MDC_NAME) != 0 &&
+ strcmp(dev->obd_type->typ_name, LUSTRE_MGC_NAME) != 0) {
+ CERROR("can't register lproc for obd type %s\n",
+ dev->obd_type->typ_name);
+ return -EINVAL;
}
- sec_flags2str(sec->ps_flags, flags_str, sizeof(flags_str));
-
- written = snprintf(page, count,
- "rpc msg flavor: %s\n"
- "bulk checksum: %s\n"
- "bulk encrypt: %s\n"
- "flags: %s\n"
- "ctx cache busy %d\n"
- "gc interval %lu\n"
- "gc next %ld\n",
- sptlrpc_flavor2name(sec->ps_flavor),
- sptlrpc_bulk_csum_alg2name(conf->sfc_bulk_csum),
- sptlrpc_bulk_priv_alg2name(conf->sfc_bulk_priv),
- flags_str,
- atomic_read(&sec->ps_busy),
- sec->ps_gc_interval,
- sec->ps_gc_interval ?
- sec->ps_gc_next - cfs_time_current_sec() : 0
- );
-
- if (sec->ps_policy->sp_cops->display) {
- written += sec->ps_policy->sp_cops->display(
- sec, page + written, count - written);
+ rc = lprocfs_obd_seq_create(dev, "srpc.info", 0444,
+ &sptlrpc_info_lprocfs_fops, dev);
+ if (rc) {
+ CERROR("create proc entry srpc.info for %s: %d\n",
+ dev->obd_name, rc);
+ return rc;
}
-out:
- return written;
+ rc = lprocfs_obd_seq_create(dev, "srpc.contexts", 0444,
+ &sptlrpc_ctxs_lprocfs_fops, dev);
+ if (rc) {
+ CERROR("create proc entry srpc.contexts for %s: %d\n",
+ dev->obd_name, rc);
+ return rc;
+ }
+
+ return 0;
}
-EXPORT_SYMBOL(sptlrpc_lprocfs_rd);
+EXPORT_SYMBOL(sptlrpc_lprocfs_cliobd_attach);
static struct lprocfs_vars sptlrpc_lprocfs_vars[] = {
- { "enc_pool", sptlrpc_proc_read_enc_pool, NULL, NULL },
+ { "encrypt_page_pools", sptlrpc_proc_read_enc_pool, NULL, NULL },
{ NULL }
};
#else /* !__KERNEL__ */
+int sptlrpc_lprocfs_cliobd_attach(struct obd_device *dev)
+{
+ return 0;
+}
+
int sptlrpc_lproc_init(void)
{
return 0;
static struct ptlrpc_cli_ctx null_cli_ctx;
static struct ptlrpc_svc_ctx null_svc_ctx;
+/*
+ * null sec temporarily use the third byte of lm_secflvr to identify
+ * the source sec part.
+ */
+static inline
+void null_encode_sec_part(struct lustre_msg *msg, enum lustre_sec_part sp)
+{
+ msg->lm_secflvr |= (((__u32) sp) & 0xFF) << 16;
+}
+
+static inline
+enum lustre_sec_part null_decode_sec_part(struct lustre_msg *msg)
+{
+ switch (msg->lm_magic) {
+ case LUSTRE_MSG_MAGIC_V2:
+ return (msg->lm_secflvr >> 16) & 0xFF;
+ case LUSTRE_MSG_MAGIC_V2_SWABBED:
+ return (msg->lm_secflvr >> 8) & 0xFF;
+ default:
+ return LUSTRE_SP_ANY;
+ }
+}
+
static
int null_ctx_refresh(struct ptlrpc_cli_ctx *ctx)
{
static
int null_ctx_sign(struct ptlrpc_cli_ctx *ctx, struct ptlrpc_request *req)
{
- if (req->rq_reqbuf->lm_magic != LUSTRE_MSG_MAGIC_V1)
+ if (req->rq_reqbuf->lm_magic != LUSTRE_MSG_MAGIC_V1) {
req->rq_reqbuf->lm_secflvr = SPTLRPC_FLVR_NULL;
+
+ if (!req->rq_import->imp_dlm_fake) {
+ struct obd_device *obd = req->rq_import->imp_obd;
+ null_encode_sec_part(req->rq_reqbuf,
+ obd->u.cli.cl_sec_part);
+ }
+ }
req->rq_reqdata_len = req->rq_reqlen;
return 0;
}
};
static
-struct ptlrpc_sec* null_create_sec(struct obd_import *imp,
- struct ptlrpc_svc_ctx *ctx,
- __u32 flavor,
- unsigned long flags)
+struct ptlrpc_sec *null_create_sec(struct obd_import *imp,
+ struct ptlrpc_svc_ctx *svc_ctx,
+ struct sptlrpc_flavor *sf)
{
- LASSERT(SEC_FLAVOR_POLICY(flavor) == SPTLRPC_POLICY_NULL);
+ LASSERT(RPC_FLVR_POLICY(sf->sf_rpc) == SPTLRPC_POLICY_NULL);
+
+ if (sf->sf_bulk_priv != BULK_PRIV_ALG_NULL ||
+ sf->sf_bulk_csum != BULK_CSUM_ALG_NULL) {
+ CERROR("null sec don't support bulk algorithm: %u/%u\n",
+ sf->sf_bulk_priv, sf->sf_bulk_csum);
+ return NULL;
+ }
+
+ /* general layer has take a module reference for us, because we never
+ * really destroy the sec, simply release the reference here.
+ */
+ sptlrpc_policy_put(&null_policy);
return &null_sec;
}
{
if (!req->rq_pool) {
LASSERTF(req->rq_reqmsg == req->rq_reqbuf,
- "reqmsg %p is not reqbuf %p in null sec\n",
- req->rq_reqmsg, req->rq_reqbuf);
+ "req %p: reqmsg %p is not reqbuf %p in null sec\n",
+ req, req->rq_reqmsg, req->rq_reqbuf);
LASSERTF(req->rq_reqbuf_len >= req->rq_reqlen,
- "reqlen %d should smaller than buflen %d\n",
- req->rq_reqlen, req->rq_reqbuf_len);
+ "req %p: reqlen %d should smaller than buflen %d\n",
+ req, req->rq_reqlen, req->rq_reqbuf_len);
OBD_FREE(req->rq_reqbuf, req->rq_reqbuf_len);
req->rq_reqmsg = req->rq_reqbuf = NULL;
req->rq_reqbuf_len = 0;
}
+
+ req->rq_reqmsg = NULL;
}
static
OBD_FREE(req->rq_repbuf, req->rq_repbuf_len);
req->rq_repbuf = NULL;
req->rq_repbuf_len = 0;
+
+ req->rq_repmsg = NULL;
}
static
static
int null_accept(struct ptlrpc_request *req)
{
- LASSERT(SEC_FLAVOR_POLICY(req->rq_sec_flavor) == SPTLRPC_POLICY_NULL);
+ LASSERT(RPC_FLVR_POLICY(req->rq_flvr.sf_rpc) == SPTLRPC_POLICY_NULL);
- if (SEC_FLAVOR_RPC(req->rq_sec_flavor) != SPTLRPC_FLVR_NULL) {
- CERROR("Invalid flavor 0x%x\n", req->rq_sec_flavor);
+ if (req->rq_flvr.sf_rpc != SPTLRPC_FLVR_NULL) {
+ CERROR("Invalid rpc flavor 0x%x\n", req->rq_flvr.sf_rpc);
return SECSVC_DROP;
}
+ req->rq_sp_from = null_decode_sec_part(req->rq_reqbuf);
+
req->rq_reqmsg = req->rq_reqbuf;
req->rq_reqlen = req->rq_reqdata_len;
null_sec.ps_policy = &null_policy;
atomic_set(&null_sec.ps_refcount, 1); /* always busy */
+ null_sec.ps_id = -1;
null_sec.ps_import = NULL;
- null_sec.ps_flavor = SPTLRPC_FLVR_NULL;
- null_sec.ps_flags = 0;
+ null_sec.ps_flvr.sf_rpc = SPTLRPC_FLVR_NULL;
+ null_sec.ps_flvr.sf_bulk_priv = BULK_PRIV_ALG_NULL;
+ null_sec.ps_flvr.sf_bulk_csum = BULK_CSUM_ALG_NULL;
+ null_sec.ps_flvr.sf_flags = 0;
+ null_sec.ps_part = LUSTRE_SP_ANY;
+ null_sec.ps_dying = 0;
spin_lock_init(&null_sec.ps_lock);
- atomic_set(&null_sec.ps_busy, 1); /* for "null_cli_ctx" */
+ atomic_set(&null_sec.ps_nctx, 1); /* for "null_cli_ctx" */
INIT_LIST_HEAD(&null_sec.ps_gc_list);
null_sec.ps_gc_interval = 0;
null_sec.ps_gc_next = 0;
/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
* vim:expandtab:shiftwidth=8:tabstop=8:
*
- * Copyright (C) 2006 Cluster File Systems, Inc.
+ * Copyright (C) 2006-2007 Cluster File Systems, Inc.
* Author: Eric Mei <ericm@clusterfs.com>
*
* This file is part of Lustre, http://www.lustre.org.
#include <lustre_net.h>
#include <lustre_sec.h>
+struct plain_sec {
+ struct ptlrpc_sec pls_base;
+ rwlock_t pls_lock;
+ struct ptlrpc_cli_ctx *pls_ctx;
+};
+
+static inline struct plain_sec *sec2plsec(struct ptlrpc_sec *sec)
+{
+ return container_of(sec, struct plain_sec, pls_base);
+}
+
static struct ptlrpc_sec_policy plain_policy;
static struct ptlrpc_ctx_ops plain_ctx_ops;
-static struct ptlrpc_sec plain_sec;
-static struct ptlrpc_cli_ctx plain_cli_ctx;
static struct ptlrpc_svc_ctx plain_svc_ctx;
+/*
+ * flavor flags (maximum 8 flags)
+ */
+#define PLAIN_WFLVR_FLAGS_OFFSET (12)
+#define PLAIN_WFLVR_FLAG_BULK (1 << (0 + PLAIN_WFLVR_FLAGS_OFFSET))
+#define PLAIN_WFLVR_FLAG_USER (1 << (1 + PLAIN_WFLVR_FLAGS_OFFSET))
+
+#define PLAIN_WFLVR_HAS_BULK(wflvr) \
+ (((wflvr) & PLAIN_WFLVR_FLAG_BULK) != 0)
+#define PLAIN_WFLVR_HAS_USER(wflvr) \
+ (((wflvr) & PLAIN_WFLVR_FLAG_USER) != 0)
+
+#define PLAIN_WFLVR_TO_RPC(wflvr) \
+ ((wflvr) & ((1 << PLAIN_WFLVR_FLAGS_OFFSET) - 1))
+
+/*
+ * similar to null sec, temporarily use the third byte of lm_secflvr to identify
+ * the source sec part.
+ */
+static inline
+void plain_encode_sec_part(struct lustre_msg *msg, enum lustre_sec_part sp)
+{
+ msg->lm_secflvr |= (((__u32) sp) & 0xFF) << 16;
+}
+
+static inline
+enum lustre_sec_part plain_decode_sec_part(struct lustre_msg *msg)
+{
+ return (msg->lm_secflvr >> 16) & 0xFF;
+}
+
+/*
+ * for simplicity, plain policy rpc use fixed layout.
+ */
+#define PLAIN_PACK_SEGMENTS (3)
+
+#define PLAIN_PACK_MSG_OFF (0)
+#define PLAIN_PACK_USER_OFF (1)
+#define PLAIN_PACK_BULK_OFF (2)
+
/****************************************
* cli_ctx apis *
****************************************/
}
static
+int plain_ctx_validate(struct ptlrpc_cli_ctx *ctx)
+{
+ return 0;
+}
+
+static
int plain_ctx_sign(struct ptlrpc_cli_ctx *ctx, struct ptlrpc_request *req)
{
struct lustre_msg_v2 *msg = req->rq_reqbuf;
ENTRY;
- msg->lm_secflvr = req->rq_sec_flavor;
+ msg->lm_secflvr = req->rq_flvr.sf_rpc;
+ if (req->rq_pack_bulk)
+ msg->lm_secflvr |= PLAIN_WFLVR_FLAG_BULK;
+ if (req->rq_pack_udesc)
+ msg->lm_secflvr |= PLAIN_WFLVR_FLAG_USER;
+
+ plain_encode_sec_part(msg, ctx->cc_sec->ps_part);
+
req->rq_reqdata_len = lustre_msg_size_v2(msg->lm_bufcount,
msg->lm_buflens);
RETURN(0);
int plain_ctx_verify(struct ptlrpc_cli_ctx *ctx, struct ptlrpc_request *req)
{
struct lustre_msg *msg = req->rq_repbuf;
+ __u16 wflvr;
ENTRY;
- if (SEC_FLAVOR_HAS_BULK(req->rq_sec_flavor)) {
- if (msg->lm_bufcount != 2) {
- CERROR("Protocol error: invalid buf count %d\n",
- msg->lm_bufcount);
- RETURN(-EPROTO);
- }
+ if (msg->lm_bufcount != PLAIN_PACK_SEGMENTS) {
+ CERROR("unexpected reply buf count %u\n", msg->lm_bufcount);
+ RETURN(-EPROTO);
+ }
- if (bulk_sec_desc_unpack(msg, 1)) {
- CERROR("Mal-formed bulk checksum reply\n");
- RETURN(-EINVAL);
- }
+ wflvr = WIRE_FLVR_RPC(msg->lm_secflvr);
+
+ /* expect no user desc in reply */
+ if (PLAIN_WFLVR_HAS_USER(wflvr)) {
+ CERROR("Unexpected udesc flag in reply\n");
+ RETURN(-EPROTO);
+ }
+
+ /* whether we sent with bulk or not, we expect the same in reply */
+ if (!equi(req->rq_pack_bulk == 1, PLAIN_WFLVR_HAS_BULK(wflvr))) {
+ CERROR("%s bulk checksum in reply\n",
+ req->rq_pack_bulk ? "Missing" : "Unexpected");
+ RETURN(-EPROTO);
}
- req->rq_repmsg = lustre_msg_buf(msg, 0, 0);
- req->rq_replen = msg->lm_buflens[0];
+ if (req->rq_pack_bulk &&
+ bulk_sec_desc_unpack(msg, PLAIN_PACK_BULK_OFF)) {
+ CERROR("Mal-formed bulk checksum reply\n");
+ RETURN(-EINVAL);
+ }
+
+ req->rq_repmsg = lustre_msg_buf(msg, PLAIN_PACK_MSG_OFF, 0);
+ req->rq_replen = msg->lm_buflens[PLAIN_PACK_MSG_OFF];
RETURN(0);
}
struct ptlrpc_request *req,
struct ptlrpc_bulk_desc *desc)
{
- struct sec_flavor_config *conf;
-
- LASSERT(req->rq_import);
- LASSERT(SEC_FLAVOR_HAS_BULK(req->rq_sec_flavor));
- LASSERT(req->rq_reqbuf->lm_bufcount >= 2);
+ LASSERT(req->rq_pack_bulk);
+ LASSERT(req->rq_reqbuf->lm_bufcount == PLAIN_PACK_SEGMENTS);
- conf = &req->rq_import->imp_obd->u.cli.cl_sec_conf;
return bulk_csum_cli_request(desc, req->rq_bulk_read,
- conf->sfc_bulk_csum,
+ req->rq_flvr.sf_bulk_csum,
req->rq_reqbuf,
- req->rq_reqbuf->lm_bufcount - 1);
+ PLAIN_PACK_BULK_OFF);
}
static
struct ptlrpc_request *req,
struct ptlrpc_bulk_desc *desc)
{
- LASSERT(SEC_FLAVOR_HAS_BULK(req->rq_sec_flavor));
- LASSERT(req->rq_reqbuf->lm_bufcount >= 2);
- LASSERT(req->rq_repbuf->lm_bufcount >= 2);
+ LASSERT(req->rq_pack_bulk);
+ LASSERT(req->rq_reqbuf->lm_bufcount == PLAIN_PACK_SEGMENTS);
+ LASSERT(req->rq_repbuf->lm_bufcount == PLAIN_PACK_SEGMENTS);
return bulk_csum_cli_reply(desc, req->rq_bulk_read,
- req->rq_reqbuf,
- req->rq_reqbuf->lm_bufcount - 1,
- req->rq_repbuf,
- req->rq_repbuf->lm_bufcount - 1);
+ req->rq_reqbuf, PLAIN_PACK_BULK_OFF,
+ req->rq_repbuf, PLAIN_PACK_BULK_OFF);
}
/****************************************
****************************************/
static
-struct ptlrpc_sec* plain_create_sec(struct obd_import *imp,
- struct ptlrpc_svc_ctx *ctx,
- __u32 flavor,
- unsigned long flags)
+struct ptlrpc_cli_ctx *plain_sec_install_ctx(struct plain_sec *plsec)
{
- ENTRY;
- LASSERT(SEC_FLAVOR_POLICY(flavor) == SPTLRPC_POLICY_PLAIN);
- RETURN(&plain_sec);
+ struct ptlrpc_cli_ctx *ctx, *ctx_new;
+
+ OBD_ALLOC_PTR(ctx_new);
+
+ write_lock(&plsec->pls_lock);
+
+ ctx = plsec->pls_ctx;
+ if (ctx) {
+ atomic_inc(&ctx->cc_refcount);
+
+ if (ctx_new)
+ OBD_FREE_PTR(ctx_new);
+ } else if (ctx_new) {
+ ctx = ctx_new;
+
+ atomic_set(&ctx->cc_refcount, 1); /* for cache */
+ ctx->cc_sec = &plsec->pls_base;
+ ctx->cc_ops = &plain_ctx_ops;
+ ctx->cc_expire = 0;
+ ctx->cc_flags = PTLRPC_CTX_CACHED | PTLRPC_CTX_UPTODATE;
+ ctx->cc_vcred.vc_uid = 0;
+ spin_lock_init(&ctx->cc_lock);
+ INIT_LIST_HEAD(&ctx->cc_req_list);
+ INIT_LIST_HEAD(&ctx->cc_gc_chain);
+
+ plsec->pls_ctx = ctx;
+ atomic_inc(&plsec->pls_base.ps_nctx);
+ atomic_inc(&plsec->pls_base.ps_refcount);
+
+ atomic_inc(&ctx->cc_refcount); /* for caller */
+ }
+
+ write_unlock(&plsec->pls_lock);
+
+ return ctx;
}
static
void plain_destroy_sec(struct ptlrpc_sec *sec)
{
+ struct plain_sec *plsec = sec2plsec(sec);
ENTRY;
- LASSERT(sec == &plain_sec);
+
+ LASSERT(sec->ps_policy == &plain_policy);
+ LASSERT(sec->ps_import);
+ LASSERT(atomic_read(&sec->ps_refcount) == 0);
+ LASSERT(atomic_read(&sec->ps_nctx) == 0);
+ LASSERT(plsec->pls_ctx == NULL);
+
+ class_import_put(sec->ps_import);
+
+ OBD_FREE_PTR(plsec);
EXIT;
}
static
+void plain_kill_sec(struct ptlrpc_sec *sec)
+{
+ sec->ps_dying = 1;
+}
+
+static
+struct ptlrpc_sec *plain_create_sec(struct obd_import *imp,
+ struct ptlrpc_svc_ctx *svc_ctx,
+ struct sptlrpc_flavor *sf)
+{
+ struct plain_sec *plsec;
+ struct ptlrpc_sec *sec;
+ struct ptlrpc_cli_ctx *ctx;
+ ENTRY;
+
+ LASSERT(RPC_FLVR_POLICY(sf->sf_rpc) == SPTLRPC_POLICY_PLAIN);
+
+ if (sf->sf_bulk_priv != BULK_PRIV_ALG_NULL) {
+ CERROR("plain policy don't support bulk encryption: %u\n",
+ sf->sf_bulk_priv);
+ RETURN(NULL);
+ }
+
+ OBD_ALLOC_PTR(plsec);
+ if (plsec == NULL)
+ RETURN(NULL);
+
+ /*
+ * initialize plain_sec
+ */
+ plsec->pls_lock = RW_LOCK_UNLOCKED;
+ plsec->pls_ctx = NULL;
+
+ sec = &plsec->pls_base;
+ sec->ps_policy = &plain_policy;
+ atomic_set(&sec->ps_refcount, 0);
+ atomic_set(&sec->ps_nctx, 0);
+ sec->ps_id = sptlrpc_get_next_secid();
+ sec->ps_import = class_import_get(imp);
+ sec->ps_flvr = *sf;
+ sec->ps_lock = SPIN_LOCK_UNLOCKED;
+ INIT_LIST_HEAD(&sec->ps_gc_list);
+ sec->ps_gc_interval = 0;
+ sec->ps_gc_next = 0;
+
+ /* install ctx immediately if this is a reverse sec */
+ if (svc_ctx) {
+ ctx = plain_sec_install_ctx(plsec);
+ if (ctx == NULL) {
+ plain_destroy_sec(sec);
+ RETURN(NULL);
+ }
+ sptlrpc_cli_ctx_put(ctx, 1);
+ }
+
+ RETURN(sec);
+}
+
+static
struct ptlrpc_cli_ctx *plain_lookup_ctx(struct ptlrpc_sec *sec,
struct vfs_cred *vcred,
int create, int remove_dead)
{
+ struct plain_sec *plsec = sec2plsec(sec);
+ struct ptlrpc_cli_ctx *ctx;
ENTRY;
- atomic_inc(&plain_cli_ctx.cc_refcount);
- RETURN(&plain_cli_ctx);
+
+ read_lock(&plsec->pls_lock);
+ ctx = plsec->pls_ctx;
+ if (ctx)
+ atomic_inc(&ctx->cc_refcount);
+ read_unlock(&plsec->pls_lock);
+
+ if (unlikely(ctx == NULL))
+ ctx = plain_sec_install_ctx(plsec);
+
+ RETURN(ctx);
+}
+
+static
+void plain_release_ctx(struct ptlrpc_sec *sec,
+ struct ptlrpc_cli_ctx *ctx, int sync)
+{
+ LASSERT(atomic_read(&sec->ps_refcount) > 0);
+ LASSERT(atomic_read(&sec->ps_nctx) > 0);
+ LASSERT(atomic_read(&ctx->cc_refcount) == 0);
+ LASSERT(ctx->cc_sec == sec);
+
+ OBD_FREE_PTR(ctx);
+
+ atomic_dec(&sec->ps_nctx);
+ sptlrpc_sec_put(sec);
}
static
int plain_flush_ctx_cache(struct ptlrpc_sec *sec,
- uid_t uid,
- int grace, int force)
+ uid_t uid, int grace, int force)
{
- return 0;
+ struct plain_sec *plsec = sec2plsec(sec);
+ struct ptlrpc_cli_ctx *ctx;
+ ENTRY;
+
+ /* do nothing unless caller want to flush for 'all' */
+ if (uid != -1)
+ RETURN(0);
+
+ write_lock(&plsec->pls_lock);
+ ctx = plsec->pls_ctx;
+ plsec->pls_ctx = NULL;
+ write_unlock(&plsec->pls_lock);
+
+ if (ctx)
+ sptlrpc_cli_ctx_put(ctx, 1);
+ RETURN(0);
}
static
struct ptlrpc_request *req,
int msgsize)
{
- struct sec_flavor_config *conf;
- int bufcnt = 1, buflens[2], alloc_len;
+ int buflens[PLAIN_PACK_SEGMENTS] = { 0, };
+ int alloc_len;
ENTRY;
- buflens[0] = msgsize;
+ buflens[PLAIN_PACK_MSG_OFF] = msgsize;
- if (SEC_FLAVOR_HAS_USER(req->rq_sec_flavor))
- buflens[bufcnt++] = sptlrpc_current_user_desc_size();
+ if (req->rq_pack_udesc)
+ buflens[PLAIN_PACK_USER_OFF] = sptlrpc_current_user_desc_size();
- if (SEC_FLAVOR_HAS_BULK(req->rq_sec_flavor)) {
+ if (req->rq_pack_bulk) {
LASSERT(req->rq_bulk_read || req->rq_bulk_write);
- conf = &req->rq_import->imp_obd->u.cli.cl_sec_conf;
- buflens[bufcnt++] = bulk_sec_desc_size(conf->sfc_bulk_csum, 1,
- req->rq_bulk_read);
+ buflens[PLAIN_PACK_BULK_OFF] = bulk_sec_desc_size(
+ req->rq_flvr.sf_bulk_csum, 1,
+ req->rq_bulk_read);
}
- alloc_len = lustre_msg_size_v2(bufcnt, buflens);
+ alloc_len = lustre_msg_size_v2(PLAIN_PACK_SEGMENTS, buflens);
if (!req->rq_reqbuf) {
LASSERT(!req->rq_pool);
memset(req->rq_reqbuf, 0, alloc_len);
}
- lustre_init_msg_v2(req->rq_reqbuf, bufcnt, buflens, NULL);
+ lustre_init_msg_v2(req->rq_reqbuf, PLAIN_PACK_SEGMENTS, buflens, NULL);
req->rq_reqmsg = lustre_msg_buf_v2(req->rq_reqbuf, 0, 0);
- if (SEC_FLAVOR_HAS_USER(req->rq_sec_flavor))
- sptlrpc_pack_user_desc(req->rq_reqbuf, 1);
+ if (req->rq_pack_udesc)
+ sptlrpc_pack_user_desc(req->rq_reqbuf, PLAIN_PACK_USER_OFF);
RETURN(0);
}
req->rq_reqbuf = NULL;
req->rq_reqbuf_len = 0;
}
+
+ req->rq_reqmsg = NULL;
EXIT;
}
struct ptlrpc_request *req,
int msgsize)
{
- struct sec_flavor_config *conf;
- int bufcnt = 1, buflens[2], alloc_len;
+ int buflens[PLAIN_PACK_SEGMENTS] = { 0, };
+ int alloc_len;
ENTRY;
- buflens[0] = msgsize;
+ buflens[PLAIN_PACK_MSG_OFF] = msgsize;
- if (SEC_FLAVOR_HAS_BULK(req->rq_sec_flavor)) {
+ if (req->rq_pack_bulk) {
LASSERT(req->rq_bulk_read || req->rq_bulk_write);
- conf = &req->rq_import->imp_obd->u.cli.cl_sec_conf;
- buflens[bufcnt++] = bulk_sec_desc_size(conf->sfc_bulk_csum, 0,
- req->rq_bulk_read);
+ buflens[PLAIN_PACK_BULK_OFF] = bulk_sec_desc_size(
+ req->rq_flvr.sf_bulk_csum, 0,
+ req->rq_bulk_read);
}
- alloc_len = lustre_msg_size_v2(bufcnt, buflens);
+ alloc_len = lustre_msg_size_v2(PLAIN_PACK_SEGMENTS, buflens);
alloc_len = size_roundup_power2(alloc_len);
OBD_ALLOC(req->rq_repbuf, alloc_len);
OBD_FREE(req->rq_repbuf, req->rq_repbuf_len);
req->rq_repbuf = NULL;
req->rq_repbuf_len = 0;
+
+ req->rq_repmsg = NULL;
EXIT;
}
int newmsg_size, newbuf_size;
ENTRY;
- /* embedded msg always at seg 0 */
LASSERT(req->rq_reqbuf);
LASSERT(req->rq_reqbuf_len >= req->rq_reqlen);
- LASSERT(lustre_msg_buf(req->rq_reqbuf, 0, 0) == req->rq_reqmsg);
+ LASSERT(lustre_msg_buf(req->rq_reqbuf, PLAIN_PACK_MSG_OFF, 0) ==
+ req->rq_reqmsg);
/* compute new embedded msg size. */
oldsize = req->rq_reqmsg->lm_buflens[segment];
req->rq_reqmsg->lm_buflens[segment] = oldsize;
/* compute new wrapper msg size. */
- oldsize = req->rq_reqbuf->lm_buflens[0];
- req->rq_reqbuf->lm_buflens[0] = newmsg_size;
+ oldsize = req->rq_reqbuf->lm_buflens[PLAIN_PACK_MSG_OFF];
+ req->rq_reqbuf->lm_buflens[PLAIN_PACK_MSG_OFF] = newmsg_size;
newbuf_size = lustre_msg_size_v2(req->rq_reqbuf->lm_bufcount,
req->rq_reqbuf->lm_buflens);
- req->rq_reqbuf->lm_buflens[0] = oldsize;
+ req->rq_reqbuf->lm_buflens[PLAIN_PACK_MSG_OFF] = oldsize;
/* request from pool should always have enough buffer */
LASSERT(!req->rq_pool || req->rq_reqbuf_len >= newbuf_size);
OBD_FREE(req->rq_reqbuf, req->rq_reqbuf_len);
req->rq_reqbuf = newbuf;
req->rq_reqbuf_len = newbuf_size;
- req->rq_reqmsg = lustre_msg_buf(req->rq_reqbuf, 0, 0);
+ req->rq_reqmsg = lustre_msg_buf(req->rq_reqbuf,
+ PLAIN_PACK_MSG_OFF, 0);
}
- _sptlrpc_enlarge_msg_inplace(req->rq_reqbuf, 0, newmsg_size);
+ _sptlrpc_enlarge_msg_inplace(req->rq_reqbuf, PLAIN_PACK_MSG_OFF,
+ newmsg_size);
_sptlrpc_enlarge_msg_inplace(req->rq_reqmsg, segment, newsize);
req->rq_reqlen = newmsg_size;
int plain_accept(struct ptlrpc_request *req)
{
struct lustre_msg *msg = req->rq_reqbuf;
- int bufcnt = 1;
ENTRY;
- LASSERT(SEC_FLAVOR_POLICY(req->rq_sec_flavor) == SPTLRPC_POLICY_PLAIN);
+ LASSERT(RPC_FLVR_POLICY(req->rq_flvr.sf_rpc) == SPTLRPC_POLICY_PLAIN);
- if (SEC_FLAVOR_RPC(req->rq_sec_flavor) != SPTLRPC_FLVR_PLAIN) {
- CERROR("Invalid flavor 0x%x\n", req->rq_sec_flavor);
- return SECSVC_DROP;
+ if (msg->lm_bufcount < PLAIN_PACK_SEGMENTS) {
+ CERROR("unexpected request buf count %u\n", msg->lm_bufcount);
+ RETURN(SECSVC_DROP);
}
- if (SEC_FLAVOR_HAS_USER(req->rq_sec_flavor)) {
- if (msg->lm_bufcount < ++bufcnt) {
- CERROR("Protocal error: too small buf count %d\n",
- msg->lm_bufcount);
- RETURN(SECSVC_DROP);
- }
+ if (req->rq_flvr.sf_rpc != SPTLRPC_FLVR_PLAIN) {
+ CERROR("Invalid rpc flavor %x\n", req->rq_flvr.sf_rpc);
+ RETURN(SECSVC_DROP);
+ }
+
+ req->rq_sp_from = plain_decode_sec_part(msg);
- if (sptlrpc_unpack_user_desc(msg, bufcnt - 1)) {
+ if (PLAIN_WFLVR_HAS_USER(msg->lm_secflvr)) {
+ if (sptlrpc_unpack_user_desc(msg, PLAIN_PACK_USER_OFF)) {
CERROR("Mal-formed user descriptor\n");
RETURN(SECSVC_DROP);
}
- req->rq_user_desc = lustre_msg_buf(msg, bufcnt - 1, 0);
+ req->rq_pack_udesc = 1;
+ req->rq_user_desc = lustre_msg_buf(msg, PLAIN_PACK_USER_OFF, 0);
}
- if (SEC_FLAVOR_HAS_BULK(req->rq_sec_flavor)) {
- if (msg->lm_bufcount != ++bufcnt) {
- CERROR("Protocal error: invalid buf count %d\n",
- msg->lm_bufcount);
- RETURN(SECSVC_DROP);
- }
-
- if (bulk_sec_desc_unpack(msg, bufcnt - 1)) {
+ if (PLAIN_WFLVR_HAS_BULK(msg->lm_secflvr)) {
+ if (bulk_sec_desc_unpack(msg, PLAIN_PACK_BULK_OFF)) {
CERROR("Mal-formed bulk checksum request\n");
RETURN(SECSVC_DROP);
}
+
+ req->rq_pack_bulk = 1;
}
- req->rq_reqmsg = lustre_msg_buf(msg, 0, 0);
- req->rq_reqlen = msg->lm_buflens[0];
+ req->rq_reqmsg = lustre_msg_buf(msg, PLAIN_PACK_MSG_OFF, 0);
+ req->rq_reqlen = msg->lm_buflens[PLAIN_PACK_MSG_OFF];
req->rq_svc_ctx = &plain_svc_ctx;
atomic_inc(&req->rq_svc_ctx->sc_refcount);
static
int plain_alloc_rs(struct ptlrpc_request *req, int msgsize)
{
- struct ptlrpc_reply_state *rs;
+ struct ptlrpc_reply_state *rs;
struct ptlrpc_bulk_sec_desc *bsd;
- int bufcnt = 1, buflens[2];
- int rs_size = sizeof(*rs);
+ int buflens[PLAIN_PACK_SEGMENTS] = { 0, };
+ int rs_size = sizeof(*rs);
ENTRY;
LASSERT(msgsize % 8 == 0);
- buflens[0] = msgsize;
- if (SEC_FLAVOR_HAS_BULK(req->rq_sec_flavor) &&
- (req->rq_bulk_read || req->rq_bulk_write)) {
+ buflens[PLAIN_PACK_MSG_OFF] = msgsize;
+
+ if (req->rq_pack_bulk && (req->rq_bulk_read || req->rq_bulk_write)) {
bsd = lustre_msg_buf(req->rq_reqbuf,
- req->rq_reqbuf->lm_bufcount - 1,
- sizeof(*bsd));
+ PLAIN_PACK_BULK_OFF, sizeof(*bsd));
LASSERT(bsd);
- buflens[bufcnt++] = bulk_sec_desc_size(bsd->bsd_csum_alg, 0,
- req->rq_bulk_read);
+ buflens[PLAIN_PACK_BULK_OFF] = bulk_sec_desc_size(
+ bsd->bsd_csum_alg, 0,
+ req->rq_bulk_read);
}
- rs_size += lustre_msg_size_v2(bufcnt, buflens);
+ rs_size += lustre_msg_size_v2(PLAIN_PACK_SEGMENTS, buflens);
rs = req->rq_reply_state;
rs->rs_repbuf = (struct lustre_msg *) (rs + 1);
rs->rs_repbuf_len = rs_size - sizeof(*rs);
- lustre_init_msg_v2(rs->rs_repbuf, bufcnt, buflens, NULL);
- rs->rs_msg = lustre_msg_buf_v2(rs->rs_repbuf, 0, 0);
+ lustre_init_msg_v2(rs->rs_repbuf, PLAIN_PACK_SEGMENTS, buflens, NULL);
+ rs->rs_msg = lustre_msg_buf_v2(rs->rs_repbuf, PLAIN_PACK_MSG_OFF, 0);
req->rq_reply_state = rs;
RETURN(0);
LASSERT(rs);
LASSERT(msg);
- if (req->rq_replen != msg->lm_buflens[0])
- len = lustre_shrink_msg(msg, 0, req->rq_replen, 1);
+ if (req->rq_replen != msg->lm_buflens[PLAIN_PACK_MSG_OFF])
+ len = lustre_shrink_msg(msg, PLAIN_PACK_MSG_OFF,
+ req->rq_replen, 1);
else
len = lustre_msg_size_v2(msg->lm_bufcount, msg->lm_buflens);
- msg->lm_secflvr = req->rq_sec_flavor;
+ msg->lm_secflvr = req->rq_flvr.sf_rpc;
+ if (req->rq_pack_bulk)
+ msg->lm_secflvr |= PLAIN_WFLVR_FLAG_BULK;
+
rs->rs_repdata_len = len;
RETURN(0);
}
struct ptlrpc_bulk_desc *desc)
{
struct ptlrpc_reply_state *rs = req->rq_reply_state;
- int voff, roff;
LASSERT(rs);
-
- voff = req->rq_reqbuf->lm_bufcount - 1;
- roff = rs->rs_repbuf->lm_bufcount - 1;
+ LASSERT(req->rq_pack_bulk);
+ LASSERT(req->rq_reqbuf->lm_bufcount >= PLAIN_PACK_SEGMENTS);
+ LASSERT(rs->rs_repbuf->lm_bufcount == PLAIN_PACK_SEGMENTS);
return bulk_csum_svc(desc, req->rq_bulk_read,
- lustre_msg_buf(req->rq_reqbuf, voff, 0),
- lustre_msg_buflen(req->rq_reqbuf, voff),
- lustre_msg_buf(rs->rs_repbuf, roff, 0),
- lustre_msg_buflen(rs->rs_repbuf, roff));
+ lustre_msg_buf(req->rq_reqbuf,
+ PLAIN_PACK_BULK_OFF, 0),
+ lustre_msg_buflen(req->rq_reqbuf,
+ PLAIN_PACK_BULK_OFF),
+ lustre_msg_buf(rs->rs_repbuf,
+ PLAIN_PACK_BULK_OFF, 0),
+ lustre_msg_buflen(rs->rs_repbuf,
+ PLAIN_PACK_BULK_OFF));
}
static
struct ptlrpc_bulk_desc *desc)
{
struct ptlrpc_reply_state *rs = req->rq_reply_state;
- int voff, roff;
LASSERT(rs);
-
- voff = req->rq_reqbuf->lm_bufcount - 1;
- roff = rs->rs_repbuf->lm_bufcount - 1;
+ LASSERT(req->rq_pack_bulk);
+ LASSERT(req->rq_reqbuf->lm_bufcount >= PLAIN_PACK_SEGMENTS);
+ LASSERT(rs->rs_repbuf->lm_bufcount == PLAIN_PACK_SEGMENTS);
return bulk_csum_svc(desc, req->rq_bulk_read,
- lustre_msg_buf(req->rq_reqbuf, voff, 0),
- lustre_msg_buflen(req->rq_reqbuf, voff),
- lustre_msg_buf(rs->rs_repbuf, roff, 0),
- lustre_msg_buflen(rs->rs_repbuf, roff));
+ lustre_msg_buf(req->rq_reqbuf,
+ PLAIN_PACK_BULK_OFF, 0),
+ lustre_msg_buflen(req->rq_reqbuf,
+ PLAIN_PACK_BULK_OFF),
+ lustre_msg_buf(rs->rs_repbuf,
+ PLAIN_PACK_BULK_OFF, 0),
+ lustre_msg_buflen(rs->rs_repbuf,
+ PLAIN_PACK_BULK_OFF));
}
static struct ptlrpc_ctx_ops plain_ctx_ops = {
.refresh = plain_ctx_refresh,
+ .validate = plain_ctx_validate,
.sign = plain_ctx_sign,
.verify = plain_ctx_verify,
.wrap_bulk = plain_cli_wrap_bulk,
static struct ptlrpc_sec_cops plain_sec_cops = {
.create_sec = plain_create_sec,
.destroy_sec = plain_destroy_sec,
+ .kill_sec = plain_kill_sec,
.lookup_ctx = plain_lookup_ctx,
+ .release_ctx = plain_release_ctx,
.flush_ctx_cache = plain_flush_ctx_cache,
.alloc_reqbuf = plain_alloc_reqbuf,
.alloc_repbuf = plain_alloc_repbuf,
static struct ptlrpc_sec_policy plain_policy = {
.sp_owner = THIS_MODULE,
- .sp_name = "sec.plain",
+ .sp_name = "plain",
.sp_policy = SPTLRPC_POLICY_PLAIN,
.sp_cops = &plain_sec_cops,
.sp_sops = &plain_sec_sops,
};
-static
-void plain_init_internal(void)
-{
- static HLIST_HEAD(__list);
-
- plain_sec.ps_policy = &plain_policy;
- atomic_set(&plain_sec.ps_refcount, 1); /* always busy */
- plain_sec.ps_import = NULL;
- plain_sec.ps_flavor = SPTLRPC_FLVR_PLAIN;
- plain_sec.ps_flags = 0;
- spin_lock_init(&plain_sec.ps_lock);
- atomic_set(&plain_sec.ps_busy, 1); /* for "plain_cli_ctx" */
- CFS_INIT_LIST_HEAD(&plain_sec.ps_gc_list);
- plain_sec.ps_gc_interval = 0;
- plain_sec.ps_gc_next = 0;
-
- hlist_add_head(&plain_cli_ctx.cc_cache, &__list);
- atomic_set(&plain_cli_ctx.cc_refcount, 1); /* for hash */
- plain_cli_ctx.cc_sec = &plain_sec;
- plain_cli_ctx.cc_ops = &plain_ctx_ops;
- plain_cli_ctx.cc_expire = 0;
- plain_cli_ctx.cc_flags = PTLRPC_CTX_CACHED | PTLRPC_CTX_ETERNAL |
- PTLRPC_CTX_UPTODATE;
- plain_cli_ctx.cc_vcred.vc_uid = 0;
- spin_lock_init(&plain_cli_ctx.cc_lock);
- CFS_INIT_LIST_HEAD(&plain_cli_ctx.cc_req_list);
- CFS_INIT_LIST_HEAD(&plain_cli_ctx.cc_gc_chain);
-}
-
int sptlrpc_plain_init(void)
{
int rc;
- plain_init_internal();
-
rc = sptlrpc_register_policy(&plain_policy);
if (rc)
- CERROR("failed to register sec.plain: %d\n", rc);
+ CERROR("failed to register: %d\n", rc);
return rc;
}
rc = sptlrpc_unregister_policy(&plain_policy);
if (rc)
- CERROR("cannot unregister sec.plain: %d\n", rc);
+ CERROR("cannot unregister: %d\n", rc);
}
}
/* go through security check/transform */
- request->rq_auth_uid = INVALID_UID;
- request->rq_auth_mapped_uid = INVALID_UID;
-
rc = sptlrpc_svc_unwrap_request(request);
switch (rc) {
case SECSVC_OK:
rc = sptlrpc_target_export_check(request->rq_export, request);
if (unlikely(rc)) {
DEBUG_REQ(D_ERROR, request,
- "DROPPING req with illeagle security flavor");
+ "DROPPING req with illegal security flavor,");
goto put_conn;
}
noinst_SCRIPTS += llog-test.sh recovery-small.sh replay-dual.sh sanity-quota.sh
noinst_SCRIPTS += replay-ost-single.sh replay-single.sh run-llog.sh sanityN.sh
noinst_SCRIPTS += lockorder.sh socketclient socketserver sanity-sec.sh
+noinst_SCRIPTS += sanity-gss.sh krb5_login.sh
nobase_noinst_SCRIPTS = cfg/insanity-local.sh cfg/insanity-ltest.sh
nobase_noinst_SCRIPTS += cfg/local.sh acl/make-tree acl/run
+nobase_noinst_SCRIPTS += rmtacl/make-tree rmtacl/run
nobase_noinst_DATA = acl/cp.test acl/getfacl-noacl.test acl/inheritance.test
nobase_noinst_DATA += acl/misc.test acl/permissions.test acl/setfacl.test
+nobase_noinst_DATA += rmtacl/misc.test rmtacl/permissions.test
+nobase_noinst_DATA += rmtacl/setfacl.test rmtacl/cp.test
+nobase_noinst_DATA += rmtacl/getfacl-noacl.test rmtacl/inheritance.test
EXTRA_DIST = $(noinst_SCRIPTS) $(noinst_DATA) \
$(nobase_noinst_SCRIPTS) $(nobase_noinst_DATA)
[ "$DEBUG_OFF" ] || DEBUG_OFF="eval sysctl -w lnet.debug=\"$DEBUG_LVL\""
[ "$DEBUG_ON" ] || DEBUG_ON="eval sysctl -w lnet.debug=0x33f0484"
-export TESTSUITE_LIST="RUNTESTS SANITY DBENCH BONNIE IOZONE FSX SANITYN LFSCK LIBLUSTRE REPLAY_SINGLE CONF_SANITY RECOVERY_SMALL REPLAY_OST_SINGLE REPLAY_DUAL INSANITY SANITY_QUOTA"
+export TESTSUITE_LIST="RUNTESTS SANITY DBENCH BONNIE IOZONE FSX SANITYN LFSCK LIBLUSTRE REPLAY_SINGLE CONF_SANITY RECOVERY_SMALL REPLAY_OST_SINGLE REPLAY_DUAL INSANITY SANITY_QUOTA SANITY_SEC"
if [ "$SLOW" = "no" ]; then
# 5 min
. $LUSTRE/tests/test-framework.sh
init_test_env $@
+if $GSS; then
+ # liblustre doesn't support GSS
+ export LIBLUSTRE=no
+fi
+
SETUP=${SETUP:-setupall}
FORMAT=${FORMAT:-formatall}
CLEANUP=${CLEANUP:-stopall}
SANITY_QUOTA="done"
fi
+if [ "$SANITY_SEC" != "no" ]; then
+ title sanity-sec
+ bash sanity-sec.sh
+fi
RC=$?
title FINISHED
gen_config
-init_krb5_env
+init_gss
test_0() {
setup
umount_client $MOUNT
cleanup_nocli
-cleanup_krb5_env
+cleanup_gss
equals_msg `basename $0`: test complete
[ -f "$TESTSUITELOG" ] && cat $TESTSUITELOG || true
exit 0
fi
-if [ -z "$KRB5DIR" ]; then
- KRB5DIR=/usr/kerberos
-fi
-
-$KRB5DIR/bin/klist -5 -s
+klist -5 -s
invalid=$?
if [ $invalid -eq 0 ]; then
echo "***** refresh Kerberos V5 TGT for uid $UID *****"
if [ -z "$GSS_PASS" ]; then
- $KRB5DIR/bin/kinit
+ kinit
else
expect <<EOF
set timeout 30
"user@host $ "
}
-send "$KRB5DIR/bin/kinit\r"
+send "kinit\r"
expect {
timeout {puts "timeout" ;exit 1}
"Password for "
wait $OPENPID
dmesg | grep "entering recovery in server" && \
error "client not evicted" || true
+ do_facet client "sysctl -w lustre.fail_loc=0"
+ do_facet $SINGLEMDS "sysctl -w lustre.fail_loc=0"
}
run_test 18 "ldlm_handle_enqueue succeeds on evicted export (3822)"
--- /dev/null
+- adapt based on test/acl/
--- /dev/null
+The "lfs cp" utility should only copy ACLs if `-p' is given.
+
+ $ umask 022
+ $ mkdir d
+ $ cd d
+ $ touch f
+ $ lfs lsetfacl -m u:bin:rw f
+ $ lfs ls -l f | awk -- '{ print $1 }'
+ > -rw-rw-r--+
+
+ $ lfs cp f g
+ $ lfs ls -l g | awk -- '{ print $1 }'
+ > -rw-r--r--
+
+ $ rm g
+ $ lfs cp -p f g
+ $ lfs ls -l f | awk -- '{ print $1 }'
+ > -rw-rw-r--+
+
+ $ mkdir h
+ $ echo blubb > h/x
+ $ lfs cp -rp h i
+ $ cat i/x
+ > blubb
+
+ $ rm -r i
+
+Use to be "$lfs lsetfacl -R -m u:bin:rwX h", but RHEL4 uncorrectly set the x flag,
+so we change to the following test
+
+ $ lfs lsetfacl -R -m u:bin:rwx h
+ $ lfs lgetfacl --omit-header h/x
+ > user::rw-
+ > user:bin:rwx
+ > group::r--
+ > mask::rwx
+ > other::r--
+ >
+
+ $ lfs cp -rp h i
+ $ lfs lgetfacl --omit-header i/x
+ > user::rw-
+ > user:bin:rwx
+ > group::r--
+ > mask::rwx
+ > other::r--
+ >
+
+ $ cd ..
+ $ rm -r d
--- /dev/null
+Getfacl utility option parsing tests. This test can be run on a
+filesystem with or without ACL support.
+
+ $ mkdir test
+ $ cd test
+ $ umask 027
+ $ touch x
+ $ lfs lgetfacl --omit-header x
+ > user::rw-
+ > group::r--
+ > other::---
+ >
+
+ $ lfs lgetfacl --omit-header --access x
+ > user::rw-
+ > group::r--
+ > other::---
+ >
+
+ $ lfs lgetfacl --omit-header -d x
+ $ lfs lgetfacl --omit-header -d .
+ $ lfs lgetfacl --omit-header -d /
+ > getfacl: Removing leading '/' from absolute path names
+
+ $ lfs lgetfacl --skip-base x
+ $ lfs lgetfacl --omit-header --all-effective x
+ > user::rw-
+ > group::r--
+ > other::---
+ >
+
+ $ lfs lgetfacl --omit-header --no-effective x
+ > user::rw-
+ > group::r--
+ > other::---
+ >
+
+ $ mkdir d
+ $ touch d/y
+ $ ln -s d l
+The result of "lfs lgetfacl -dR . | grep file | sort" is related with
+the dentry item order in parent directory. Such order depends on
+FS implementation. Fix with -P (--physical) option.
+# $ lfs lgetfacl -dR . | grep file | sort
+ $ lfs lgetfacl -dRP . | grep file | sort
+ > # file: .
+ > # file: d
+ > # file: d/y
+ > # file: x
+
+ $ ln -s l ll
+ $ lfs lgetfacl -dLR ll | grep file | sort
+ > # file: ll
+ > # file: ll/y
+
+ $ rm l ll x
+ $ rm -rf d
+ $ cd ..
+ $ rmdir test
--- /dev/null
+ACL inheritance test. Run these tests on a filesystem with ACL support.
+
+
+ $ id -u
+ > 0
+
+ $ mkdir d
+ $ lfs lsetfacl -d -m group:bin:r-x d
+ $ lfs lgetfacl d
+ > # file: d
+ > # owner: root
+ > # group: root
+ > user::rwx
+ > group::r-x
+ > other::r-x
+ > default:user::rwx
+ > default:group::r-x
+ > default:group:bin:r-x
+ > default:mask::r-x
+ > default:other::r-x
+ >
+
+ $ mkdir d/subdir
+ $ lfs lgetfacl d/subdir
+ > # file: d/subdir
+ > # owner: root
+ > # group: root
+ > user::rwx
+ > group::r-x
+ > group:bin:r-x
+ > mask::r-x
+ > other::r-x
+ > default:user::rwx
+ > default:group::r-x
+ > default:group:bin:r-x
+ > default:mask::r-x
+ > default:other::r-x
+ >
+
+ $ touch d/f
+ $ lfs ls -l d/f | awk -- '{ print $1 }'
+ > -rw-r--r--+
+ $ lfs lgetfacl d/f
+ > # file: d/f
+ > # owner: root
+ > # group: root
+ > user::rw-
+ > group::r-x #effective:r--
+ > group:bin:r-x #effective:r--
+ > mask::r--
+ > other::r--
+ >
+
+ $ su bin
+ $ echo i >> d/f
+ > d/f: Permission denied
+
+Changed by CFS: (1). reduce the tree level to 2 (for shortening
+time of local tests). (2). add one more lfs lgetfacl test since dir
+might be distributed around MDS's.
+
+ $ su
+ $ rm d/f
+ $ rmdir d/subdir
+ $ mv d tree
+ $ ./make-tree
+ $ lfs lgetfacl tree/dir0/dir5/file4
+ > # file: tree/dir0/dir5/file4
+ > # owner: root
+ > # group: root
+ > user::rw-
+ > group::r-x #effective:r--
+ > group:bin:r-x #effective:r--
+ > mask::r--
+ > other::r--
+ >
+ $ lfs lgetfacl tree/dir0/dir6/file4
+ > # file: tree/dir0/dir6/file4
+ > # owner: root
+ > # group: root
+ > user::rw-
+ > group::r-x #effective:r--
+ > group:bin:r-x #effective:r--
+ > mask::r--
+ > other::r--
+ >
+ $ echo i >> tree/dir6/dir2/file2
+ $ echo i > tree/dir1/f
+ $ lfs ls -l tree/dir1/f | awk -- '{ print $1 }'
+ > -rw-r--r--+
+in following item, the error message is dependant on distributions.
+success on FC3, but not on FC2 and SLES3 etc. comment out by CFS.
+# $ su bin
+# $ echo i > tree/dir6/dir2/f
+# > tree/dir6/dir2/f: No such file or directory
+# $ su
+
+ $ rm -rf tree
+
+
+Original scripts, comment out by CFS.
+#
+# $ su
+# $ rm d/f
+# $ rmdir d/subdir
+# $ mv d tree
+# $ ./make-tree
+# $ lfs lgetfacl tree/dir0/dir5/dir7/file4
+# > # file: tree/dir0/dir5/dir7/file4
+# > # owner: root
+# > # group: root
+# > user::rw-
+# > group::r-x #effective:r--
+# > group:bin:r-x #effective:r--
+# > mask::r--
+# > other::r--
+# >
+# $ echo i >> tree/dir6/dir2/dir1/file2
+# $ echo i > tree/dir1/f
+# $ lfs ls -l tree/dir1/f | awk -- '{ print $1 }'
+# > -rw-r--r--+
+# $ su bin
+# $ echo i > tree/dir6/dir2/f
+# > tree/dir6/dir2/f: No such file or directory
+# $ su
+#
+# $ rm -rf tree
+
+
+
+
--- /dev/null
+#!/bin/sh
+
+# reduce LEVELS from 3 => 2 by CFS
+LEVELS=2 ; [ -z "$1" ] || LEVELS=$1
+DIRS=10 ; [ -z "$2" ] || DIRS=$2
+FILES=10 ; [ -z "$2" ] || FILES=$3
+NUMBER_OF_ACLS=50 ; [ -z "$3" ] || NUMBER_OF_ACLS=$4
+
+function random_dir() {
+ mkdir -p $1
+ #lfs lsetfacl -s "u::rwx,u:$[($RANDOM % $NUMBER_OF_ACLS)+1000]:rwx,g::rx,o:-" $1
+}
+
+function random_file() {
+ touch $1
+ #lfs lsetfacl -s "u::rw,u:$[($RANDOM % $NUMBER_OF_ACLS)+1000]:rw,g::r,o:-" $1
+}
+
+function create () {
+ local LEVEL=$1
+ if [ $LEVEL -eq 0 ]; then
+ local I=0
+ while [ $I -lt $FILES ]; do
+ random_file file$I
+ I=$[$I+1]
+ done
+ else
+ local I=0
+ while [ $I -lt $DIRS ]; do
+ random_dir dir$I
+ cd dir$I
+ create $[$LEVEL-1]
+ cd ..
+ I=$[$I+1]
+ done
+ fi
+ return
+}
+
+mkdir -p tree
+cd tree
+create $LEVELS
+cd ..
+exit 0
+
--- /dev/null
+Pretty comprehensive ACL tests.
+
+This must be run on a filesystem with ACL support. Also, you will need
+two dummy users (bin and daemon) and a dummy group (daemon).
+
+ $ umask 027
+ $ touch f
+
+Only change a base ACL:
+ $ lfs lsetfacl -m u::r f
+ $ lfs lsetfacl -m u::rw,u:bin:rw f
+ $ lfs ls -dl f | awk '{print $1}'
+ > -rw-rw----+
+
+ $ lfs lgetfacl --omit-header f
+ > user::rw-
+ > user:bin:rw-
+ > group::r--
+ > mask::rw-
+ > other::---
+ >
+
+ $ rm f
+ $ umask 022
+ $ touch f
+ $ lfs lsetfacl -m u:bin:rw f
+ $ lfs ls -dl f | awk '{print $1}'
+ > -rw-rw-r--+
+
+ $ lfs lgetfacl --omit-header f
+ > user::rw-
+ > user:bin:rw-
+ > group::r--
+ > mask::rw-
+ > other::r--
+ >
+
+ $rm f
+ $ umask 027
+ $ mkdir d
+ $ lfs lsetfacl -m u:bin:rwx d
+ $ lfs ls -dl d | awk '{print $1}'
+ > drwxrwx---+
+
+ $ lfs lgetfacl --omit-header d
+ > user::rwx
+ > user:bin:rwx
+ > group::r-x
+ > mask::rwx
+ > other::---
+ >
+
+ $ rmdir d
+ $ umask 022
+ $ mkdir d
+ $ lfs lsetfacl -m u:bin:rwx d
+ $ lfs ls -dl d | awk '{print $1}'
+ > drwxrwxr-x+
+
+ $ lfs lgetfacl --omit-header d
+ > user::rwx
+ > user:bin:rwx
+ > group::r-x
+ > mask::rwx
+ > other::r-x
+ >
+
+ $ rmdir d
+
+
+Multiple users
+
+ $ umask 022
+ $ touch f
+ $ lfs lsetfacl -m u:bin:rw,u:daemon:r f
+ $ lfs ls -dl f | awk '{print $1}'
+ > -rw-rw-r--+
+
+ $ lfs lgetfacl --omit-header f
+ > user::rw-
+ > user:bin:rw-
+ > user:daemon:r--
+ > group::r--
+ > mask::rw-
+ > other::r--
+ >
+
+Multiple groups
+
+ $ lfs lsetfacl -m g:users:rw,g:daemon:r f
+ $ lfs ls -dl f | awk '{print $1}'
+ > -rw-rw-r--+
+
+ $ lfs lgetfacl --omit-header f
+ > user::rw-
+ > user:bin:rw-
+ > user:daemon:r--
+ > group::r--
+ > group:daemon:r--
+ > group:users:rw-
+ > mask::rw-
+ > other::r--
+ >
+
+Remove one group
+
+ $ lfs lsetfacl -x g:users f
+ $ lfs ls -dl f | awk '{print $1}'
+ > -rw-rw-r--+
+
+ $ lfs lgetfacl --omit-header f
+ > user::rw-
+ > user:bin:rw-
+ > user:daemon:r--
+ > group::r--
+ > group:daemon:r--
+ > mask::rw-
+ > other::r--
+ >
+
+Remove one user
+
+ $ lfs lsetfacl -x u:daemon f
+ $ lfs ls -dl f | awk '{print $1}'
+ > -rw-rw-r--+
+
+ $ lfs lgetfacl --omit-header f
+ > user::rw-
+ > user:bin:rw-
+ > group::r--
+ > group:daemon:r--
+ > mask::rw-
+ > other::r--
+ >
+
+ $ rm f
+
+Default ACL
+
+ $ umask 027
+ $ mkdir d
+ $ lfs lsetfacl -m u:bin:rwx,u:daemon:rw,d:u:bin:rwx,d:m:rx d
+ $ lfs ls -dl d | awk '{print $1}'
+ > drwxrwx---+
+
+ $ lfs lgetfacl --omit-header d
+ > user::rwx
+ > user:bin:rwx
+ > user:daemon:rw-
+ > group::r-x
+ > mask::rwx
+ > other::---
+ > default:user::rwx
+ > default:user:bin:rwx #effective:r-x
+ > default:group::r-x
+ > default:mask::r-x
+ > default:other::---
+ >
+
+Umask now ignored?
+
+ $ umask 027
+ $ touch d/f
+ $ lfs ls -dl d/f | awk '{print $1}'
+ > -rw-r-----+
+
+ $ lfs lgetfacl --omit-header d/f
+ > user::rw-
+ > user:bin:rwx #effective:r--
+ > group::r-x #effective:r--
+ > mask::r--
+ > other::---
+ >
+
+ $ rm d/f
+ $ umask 022
+ $ touch d/f
+ $ lfs ls -dl d/f | awk '{print $1}'
+ > -rw-r-----+
+
+ $ lfs lgetfacl --omit-header d/f
+ > user::rw-
+ > user:bin:rwx #effective:r--
+ > group::r-x #effective:r--
+ > mask::r--
+ > other::---
+ >
+
+ $ rm d/f
+
+Default ACL copying
+
+ $ umask 000
+ $ mkdir d/d
+ $ lfs ls -dl d/d | awk '{print $1}'
+ > drwxr-x---+
+
+ $ lfs lgetfacl --omit-header d/d
+ > user::rwx
+ > user:bin:rwx #effective:r-x
+ > group::r-x
+ > mask::r-x
+ > other::---
+ > default:user::rwx
+ > default:user:bin:rwx #effective:r-x
+ > default:group::r-x
+ > default:mask::r-x
+ > default:other::---
+ >
+
+ $ rmdir d/d
+ $ umask 022
+ $ mkdir d/d
+ $ lfs ls -dl d/d | awk '{print $1}'
+ > drwxr-x---+
+
+ $ lfs lgetfacl --omit-header d/d
+ > user::rwx
+ > user:bin:rwx #effective:r-x
+ > group::r-x
+ > mask::r-x
+ > other::---
+ > default:user::rwx
+ > default:user:bin:rwx #effective:r-x
+ > default:group::r-x
+ > default:mask::r-x
+ > default:other::---
+ >
+
+Add some users and groups
+
+ $ lfs lsetfacl -nm u:daemon:rx,d:u:daemon:rx,g:users:rx,g:daemon:rwx d/d
+ $ lfs ls -dl d/d | awk '{print $1}'
+ > drwxr-x---+
+
+ $ lfs lgetfacl --omit-header d/d
+ > user::rwx
+ > user:bin:rwx #effective:r-x
+ > user:daemon:r-x
+ > group::r-x
+ > group:daemon:rwx #effective:r-x
+ > group:users:r-x
+ > mask::r-x
+ > other::---
+ > default:user::rwx
+ > default:user:bin:rwx #effective:r-x
+ > default:user:daemon:r-x
+ > default:group::r-x
+ > default:mask::r-x
+ > default:other::---
+ >
+
+Symlink in directory with default ACL?
+
+ $ ln -s d d/l
+ $ lfs ls -dl d/l | awk '{print $1}'
+ > lrwxrwxrwx
+
+ $ lfs ls -dl -L d/l | awk '{print $1}'
+ > drwxr-x---+
+
+ $ lfs lgetfacl --omit-header d/l
+ > user::rwx
+ > user:bin:rwx #effective:r-x
+ > user:daemon:r-x
+ > group::r-x
+ > group:daemon:rwx #effective:r-x
+ > group:users:r-x
+ > mask::r-x
+ > other::---
+ > default:user::rwx
+ > default:user:bin:rwx #effective:r-x
+ > default:user:daemon:r-x
+ > default:group::r-x
+ > default:mask::r-x
+ > default:other::---
+ >
+
+ $ rm d/l
+
+Does mask manipulation work?
+
+ $ lfs lsetfacl -m g:daemon:rx,u:bin:rx d/d
+ $ lfs ls -dl d/d | awk '{print $1}'
+ > drwxr-x---+
+
+ $ lfs lgetfacl --omit-header d/d
+ > user::rwx
+ > user:bin:r-x
+ > user:daemon:r-x
+ > group::r-x
+ > group:daemon:r-x
+ > group:users:r-x
+ > mask::r-x
+ > other::---
+ > default:user::rwx
+ > default:user:bin:rwx #effective:r-x
+ > default:user:daemon:r-x
+ > default:group::r-x
+ > default:mask::r-x
+ > default:other::---
+ >
+
+ $ lfs lsetfacl -m d:u:bin:rwx d/d
+ $ lfs ls -dl d/d | awk '{print $1}'
+ > drwxr-x---+
+
+ $ lfs lgetfacl --omit-header d/d
+ > user::rwx
+ > user:bin:r-x
+ > user:daemon:r-x
+ > group::r-x
+ > group:daemon:r-x
+ > group:users:r-x
+ > mask::r-x
+ > other::---
+ > default:user::rwx
+ > default:user:bin:rwx
+ > default:user:daemon:r-x
+ > default:group::r-x
+ > default:mask::rwx
+ > default:other::---
+ >
+
+ $ rmdir d/d
+
+Remove the default ACL
+
+ $ lfs lsetfacl -k d
+ $ lfs ls -dl d | awk '{print $1}'
+ > drwxrwx---+
+
+ $ lfs lgetfacl --omit-header d
+ > user::rwx
+ > user:bin:rwx
+ > user:daemon:rw-
+ > group::r-x
+ > mask::rwx
+ > other::---
+ >
+
+Reset to base entries
+
+ $ lfs lsetfacl -b d
+ $ lfs ls -dl d | awk '{print $1}'
+ > drwxr-x---
+
+ $ lfs lgetfacl --omit-header d
+ > user::rwx
+ > group::r-x
+ > other::---
+ >
+
+Now, chmod should change the group_obj entry
+
+ $ chmod 775 d
+ $ lfs ls -dl d | awk '{print $1}'
+ > drwxrwxr-x
+
+ $ lfs lgetfacl --omit-header d
+ > user::rwx
+ > group::rwx
+ > other::r-x
+ >
+
+ $ rmdir d
+ $ umask 002
+ $ mkdir d
+ $ lfs lsetfacl -m u:daemon:rwx,u:bin:rx,d:u:daemon:rwx,d:u:bin:rx d
+ $ lfs ls -dl d | awk '{print $1}'
+ > drwxrwxr-x+
+
+ $ lfs lgetfacl --omit-header d
+ > user::rwx
+ > user:bin:r-x
+ > user:daemon:rwx
+ > group::rwx
+ > mask::rwx
+ > other::r-x
+ > default:user::rwx
+ > default:user:bin:r-x
+ > default:user:daemon:rwx
+ > default:group::rwx
+ > default:mask::rwx
+ > default:other::r-x
+ >
+
+ $ chmod 750 d
+ $ lfs ls -dl d | awk '{print $1}'
+ > drwxr-x---+
+
+ $ lfs lgetfacl --omit-header d
+ > user::rwx
+ > user:bin:r-x
+ > user:daemon:rwx #effective:r-x
+ > group::rwx #effective:r-x
+ > mask::r-x
+ > other::---
+ > default:user::rwx
+ > default:user:bin:r-x
+ > default:user:daemon:rwx
+ > default:group::rwx
+ > default:mask::rwx
+ > default:other::r-x
+ >
+
+ $ chmod 750 d
+ $ lfs ls -dl d | awk '{print $1}'
+ > drwxr-x---+
+
+ $ lfs lgetfacl --omit-header d
+ > user::rwx
+ > user:bin:r-x
+ > user:daemon:rwx #effective:r-x
+ > group::rwx #effective:r-x
+ > mask::r-x
+ > other::---
+ > default:user::rwx
+ > default:user:bin:r-x
+ > default:user:daemon:rwx
+ > default:group::rwx
+ > default:mask::rwx
+ > default:other::r-x
+ >
+
+ $ rmdir d
--- /dev/null
+This script tests if file permissions are properly checked with and
+without ACLs. The script must be run as root to allow switching users.
+The following users are required. They must be a member in the groups
+listed in parentheses.
+
+ bin (bin)
+ daemon (bin, daemon)
+
+
+Cry immediately if we are not running as root.
+
+ $ id -u
+ > 0
+
+
+First, set up a temporary directory and create a regular file with
+defined permissions.
+
+ $ mkdir d
+ $ cd d
+ $ umask 027
+ $ touch f
+ $ lfs ls -l f | awk -- '{ print $1, $3, $4 }'
+ > -rw-r----- root root
+
+
+Make sure root has access to the file. Verify that user daemon does not
+have access to the file owned by root.
+
+ $ echo root > f
+
+ $ su daemon
+ $ echo daemon >> f
+ > f: Permission denied
+
+ $ su
+
+
+Now, change the ownership of the file to bin:bin and verify that this
+gives user bin write access.
+
+ $ chown bin:bin f
+ $ lfs ls -l f | awk -- '{ print $1, $3, $4 }'
+ > -rw-r----- bin bin
+ $ su bin
+ $ echo bin >> f
+
+
+User daemon is a member in the owning group, which has only read access.
+Verify this.
+
+ $ su daemon
+ $ cat f
+ > root
+ > bin
+
+ $ echo daemon >> f
+ > f: Permission denied
+
+
+Now, add an ACL entry for user daemon that grants him rw- access. File
+owners and users capable of CAP_FOWNER are allowed to change ACLs.
+
+ $ su bin
+ $ lfs lsetfacl -m u:daemon:rw f
+ $ lfs lgetfacl --omit-header f
+ > user::rw-
+ > user:daemon:rw-
+ > group::r--
+ > mask::rw-
+ > other::---
+ >
+
+
+Verify that the additional ACL entry grants user daemon write access.
+
+ $ su daemon
+ $ echo daemon >> f
+ $ cat f
+ > root
+ > bin
+ > daemon
+
+
+Remove write access from the group class permission bits, and
+verify that this masks daemon's write permission.
+
+ $ su bin
+ $ chmod g-w f
+ $ lfs lgetfacl --omit-header f
+ > user::rw-
+ > user:daemon:rw- #effective:r--
+ > group::r--
+ > mask::r--
+ > other::---
+ >
+
+ $ su daemon
+ $ echo daemon >> f
+ > f: Permission denied
+
+
+Add an entry for group daemon with rw- access, and change the
+permissions for user daemon to r--. Also change the others permissions t
+rw-. The user entry should take precedence, so daemon should be denied
+access.
+
+ $ su bin
+ $ lfs lsetfacl -m u:daemon:r,g:daemon:rw-,o::rw- f
+
+ $ su daemon
+ $ echo daemon >> f
+ > f: Permission denied
+
+
+Remove the entry for user daemon. The group daemon permissions should
+now give user daemon rw- access.
+
+ $ su bin
+ $ lfs lsetfacl -x u:daemon f
+
+ $ su daemon
+ $ echo daemon2 >> f
+ $ cat f
+ > root
+ > bin
+ > daemon
+ > daemon2
+
+
+Set the group daemon permissions to r-- and verify that after than, user
+daemon does not have write access anymore.
+
+ $ su bin
+ $ lfs lsetfacl -m g:daemon:r f
+
+ $ su daemon
+ $ echo daemon3 >> f
+ > f: Permission denied
+
+
+Now, remove the group daemon entry. Because user daemon is a member in
+the owning group, he should still have no write access.
+
+ $ su bin
+ $ lfs lsetfacl -x g:daemon f
+
+ $ su daemon
+ $ echo daemon4 >> f
+ > f: Permission denied
+
+
+Change the owning group. The other permissions should now grant user
+daemon write access.
+
+ $ su
+ $ chgrp root f
+
+ $ su daemon
+ $ echo daemon5 >> f
+ $ cat f
+ > root
+ > bin
+ > daemon
+ > daemon2
+ > daemon5
+
+
+Verify that permissions in separate matching ACL entries do not
+accumulate.
+
+ $ su
+ $ lfs lsetfacl -m g:bin:r,g:daemon:w f
+
+ $ su daemon
+ $ : < f # open for reading
+ $ : > f # open for writing
+ $ : <> f # open for read-write
+ > f: Permission denied
+
+
+Test if directories can have ACLs. We assume that only one access check
+algorithm is used for all file types the file system, so these tests
+only need to verify that ACL permissions make a difference.
+
+ $ su
+ $ mkdir -m 750 e
+ $ touch e/h
+
+ $ su bin
+ $ shopt -s nullglob ; echo e/*
+ >
+
+ $ echo i > e/i
+ > e/i: Permission denied
+
+ $ su
+ $ lfs lsetfacl -m u:bin:rx e
+
+ $ su bin
+ $ echo e/*
+ > e/h
+following 2 lines seems not valid, which also failed on ext3 in FC3 enviroment,
+although it pass in FC2. commented out by CFS (agreed with HP)
+Replaced "echo" with "touch" can resolve such problem.
+# $ echo i > e/i
+# > e/i: Permission denied
+ $ touch e/i
+ > touch: cannot touch `e/i': Permission denied
+
+ $ su
+ $ lfs lsetfacl -m u:bin:rwx e
+
+ $ su bin
+ $ echo i > e/i
+
+
+Test if symlinks are properly followed.
+
+ $ su
+ $ touch g
+ $ ln -s g l
+ $ lfs lsetfacl -m u:bin:rw l
+ $ lfs ls -l g | awk -- '{ print $1, $3, $4 }'
+ > -rw-rw----+ root root
+
+
+Test if ACLs are effective for block and character special files, fifos,
+sockets. This is done by creating special files locally. The devices do
+not need to exist: The access check is earlier in the code path than the
+test if the device exists.
+
+
+ $ mknod -m 0660 hdt b 91 64 # /dev/hdt
+ $ mknod -m 0660 null c 1 3 # /dev/null
+ $ mkfifo -m 0660 fifo
+
+ $ su bin
+ $ : < hdt
+ > hdt: Permission denied
+ $ : < null
+ > null: Permission denied
+ $ : < fifo
+ > fifo: Permission denied
+
+ $ su
+ $ lfs lsetfacl -m u:bin:rw hdt null fifo
+
+ $ su bin
+ $ : < hdt
+ > hdt: No such device or address
+ $ : < null
+ $ ( echo blah > fifo & ) ; cat fifo
+ > blah
+
+
+Test if CAP_FOWNER is properly honored for directories. This addresses a
+specific bug in XFS 1.2, which does not grant root access to files in
+directories if the file has an ACL and only CAP_FOWNER would grant them.
+
+ $ su
+ $ mkdir -m 600 x
+ $ chown daemon:daemon x
+ $ echo j > x/j
+ $ lfs ls -l x/j | awk -- '{ print $1, $3, $4 }'
+ > -rw-r----- root root
+
+ $ lfs lsetfacl -m u:daemon:r x
+
+ $ lfs ls -l x/j | awk -- '{ print $1, $3, $4 }'
+ > -rw-r----- root root
+ (With the bug this gives: `ls: x/j: Permission denied'.)
+
+ $ echo k > x/k
+ (With the bug this gives: `x/k: Permission denied'.)
+
+ $ chmod 750 x
+
+
+Clean up.
+
+ $ su
+ $ cd ..
+ $ rm -rf d
--- /dev/null
+#!/usr/bin/perl -w -U
+
+#
+# Possible improvements:
+#
+# - distinguish stdout and stderr output
+# - add environment variable like assignments
+# - run up to a specific line
+# - resume at a specific line
+#
+
+use strict;
+use FileHandle;
+use Getopt::Std;
+use POSIX qw(isatty setuid);
+use vars qw($opt_v);
+
+no warnings qw(taint);
+
+getopts('v');
+
+my ($OK, $FAILED) = ("ok", "failed");
+if (isatty(fileno(STDOUT))) {
+ $OK = "\033[32m" . $OK . "\033[m";
+ $FAILED = "\033[31m\033[1m" . $FAILED . "\033[m";
+}
+
+sub exec_test($$);
+sub process_test($$$$);
+
+my ($prog, $in, $out) = ([], [], []);
+my $line_number = 0;
+my $prog_line;
+my ($tests, $failed) = (0,0);
+
+for (;;) {
+ my $line = <>; $line_number++;
+ if (defined $line) {
+ # Substitute %VAR and %{VAR} with environment variables.
+ $line =~ s[%(?:(\w+)|\{(\w+)\})][$ENV{"$1$2"}]eg;
+ }
+ if (defined $line) {
+ if ($line =~ s/^\s*< ?//) {
+ push @$in, $line;
+ } elsif ($line =~ s/^\s*> ?//) {
+ push @$out, $line;
+ } else {
+ process_test($prog, $prog_line, $in, $out);
+
+ $prog = [];
+ $prog_line = 0;
+ }
+ if ($line =~ s/^\s*\$ ?//) {
+ $line =~ s/\s+#.*//; # remove comments here...
+ $prog = [ map { s/\\(.)/$1/g; $_ } split /(?<!\\)\s+/, $line ];
+ $prog_line = $line_number;
+ $in = [];
+ $out = [];
+ }
+ } else {
+ process_test($prog, $prog_line, $in, $out);
+ last;
+ }
+}
+
+my $status = sprintf("%d commands (%d passed, %d failed)",
+ $tests, $tests-$failed, $failed);
+if (isatty(fileno(STDOUT))) {
+ if ($failed) {
+ $status = "\033[31m\033[1m" . $status . "\033[m";
+ } else {
+ $status = "\033[32m" . $status . "\033[m";
+ }
+}
+print $status, "\n";
+exit $failed ? 1 : 0;
+
+
+sub process_test($$$$) {
+ my ($prog, $prog_line, $in, $out) = @_;
+
+ return unless @$prog;
+
+ my $p = [ @$prog ];
+ print "[$prog_line] \$ ", join(' ',
+ map { s/\s/\\$&/g; $_ } @$p), " -- ";
+ my $result = exec_test($prog, $in);
+ my $good = 1;
+ my $nmax = (@$out > @$result) ? @$out : @$result;
+ for (my $n=0; $n < $nmax; $n++) {
+ if (!defined($out->[$n]) || !defined($result->[$n]) ||
+ $out->[$n] ne $result->[$n]) {
+ $good = 0;
+ }
+ }
+ $tests++;
+ $failed++ unless $good;
+ print $good ? $OK : $FAILED, "\n";
+ if (!$good) {
+ for (my $n=0; $n < $nmax; $n++) {
+ my $l = defined($out->[$n]) ? $out->[$n] : "~";
+ chomp $l;
+ my $r = defined($result->[$n]) ? $result->[$n] : "~";
+ chomp $r;
+ print sprintf("%-37s %s %-39s\n", $l, $l eq $r ? "|" : "?", $r);
+ }
+ } elsif ($opt_v) {
+ print join('', @$result);
+ }
+}
+
+
+sub su($) {
+ my ($user) = @_;
+
+ $user ||= "root";
+
+ my ($login, $pass, $uid, $gid) = getpwnam($user)
+ or return [ "su: user $user does not exist\n" ];
+ my @groups = ();
+ my $fh = new FileHandle("/etc/group")
+ or return [ "opening /etc/group: $!\n" ];
+ while (<$fh>) {
+ chomp;
+ my ($group, $passwd, $gid, $users) = split /:/;
+ foreach my $u (split /,/, $users) {
+ push @groups, $gid
+ if ($user eq $u);
+ }
+ }
+ $fh->close;
+
+ my $groups = join(" ", ($gid, $gid, @groups));
+ #print STDERR "[[$groups]]\n";
+ $! = 0; # reset errno
+ $> = 0;
+ $( = $gid;
+ $) = $groups;
+ if ($!) {
+ return [ "su: $!\n" ];
+ }
+ if ($uid != 0) {
+ $> = $uid;
+ #$< = $uid;
+ if ($!) {
+ return [ "su: $prog->[1]: $!\n" ];
+ }
+ }
+ #print STDERR "[($>,$<)($(,$))]";
+ return [];
+}
+
+
+sub sg($) {
+ my ($group) = @_;
+
+ my $gid = getgrnam($group)
+ or return [ "sg: group $group does not exist\n" ];
+ my %groups = map { $_ eq $gid ? () : ($_ => 1) } (split /\s/, $));
+
+ #print STDERR "<<", join("/", keys %groups), ">>\n";
+ my $groups = join(" ", ($gid, $gid, keys %groups));
+ #print STDERR "[[$groups]]\n";
+ $! = 0; # reset errno
+ if ($> != 0) {
+ my $uid = $>;
+ $> = 0;
+ $( = $gid;
+ $) = $groups;
+ $> = $uid;
+ } else {
+ $( = $gid;
+ $) = $groups;
+ }
+ if ($!) {
+ return [ "sg: $!\n" ];
+ }
+ print STDERR "[($>,$<)($(,$))]";
+ return [];
+}
+
+
+sub exec_test($$) {
+ my ($prog, $in) = @_;
+ local (*IN, *IN_DUP, *IN2, *OUT_DUP, *OUT, *OUT2);
+ my $needs_shell = (join('', @$prog) =~ /[][|<>"'`\$\*\?]/);
+
+ if ($prog->[0] eq "umask") {
+ umask oct $prog->[1];
+ return [];
+ } elsif ($prog->[0] eq "cd") {
+ if (!chdir $prog->[1]) {
+ return [ "chdir: $prog->[1]: $!\n" ];
+ }
+ return [];
+ } elsif ($prog->[0] eq "su") {
+ return su($prog->[1]);
+ } elsif ($prog->[0] eq "sg") {
+ return sg($prog->[1]);
+ }
+
+ pipe *IN2, *OUT
+ or die "Can't create pipe for reading: $!";
+ open *IN_DUP, "<&STDIN"
+ or *IN_DUP = undef;
+ open *STDIN, "<&IN2"
+ or die "Can't duplicate pipe for reading: $!";
+ close *IN2;
+
+ open *OUT_DUP, ">&STDOUT"
+ or die "Can't duplicate STDOUT: $!";
+ pipe *IN, *OUT2
+ or die "Can't create pipe for writing: $!";
+ open *STDOUT, ">&OUT2"
+ or die "Can't duplicate pipe for writing: $!";
+ close *OUT2;
+
+ *STDOUT->autoflush();
+ *OUT->autoflush();
+
+ if (fork()) {
+ # Server
+ if (*IN_DUP) {
+ open *STDIN, "<&IN_DUP"
+ or die "Can't duplicate STDIN: $!";
+ close *IN_DUP
+ or die "Can't close STDIN duplicate: $!";
+ }
+ open *STDOUT, ">&OUT_DUP"
+ or die "Can't duplicate STDOUT: $!";
+ close *OUT_DUP
+ or die "Can't close STDOUT duplicate: $!";
+
+ foreach my $line (@$in) {
+ #print "> $line";
+ print OUT $line;
+ }
+ close *OUT
+ or die "Can't close pipe for writing: $!";
+
+ my $result = [];
+ while (<IN>) {
+ #print "< $_";
+ if ($needs_shell) {
+ s#^/bin/sh: line \d+: ##;
+ s#^/bin/sh: ##; # temporarily added by ericm
+ }
+ push @$result, $_;
+ }
+ return $result;
+ } else {
+ # Client
+ $< = $>;
+ close IN
+ or die "Can't close read end for input pipe: $!";
+ close OUT
+ or die "Can't close write end for output pipe: $!";
+ close OUT_DUP
+ or die "Can't close STDOUT duplicate: $!";
+ local *ERR_DUP;
+ open ERR_DUP, ">&STDERR"
+ or die "Can't duplicate STDERR: $!";
+ open STDERR, ">&STDOUT"
+ or die "Can't join STDOUT and STDERR: $!";
+
+ if ($needs_shell) {
+ exec ('/bin/sh', '-c', join(" ", @$prog));
+ } else {
+ exec @$prog;
+ }
+ print STDERR $prog->[0], ": $!\n";
+ exit;
+ }
+}
+
--- /dev/null
+Setfacl utility tests. Run these tests on a filesystem with ACL support.
+
+ $ mkdir d
+ $ chown bin:bin d
+ $ cd d
+
+ $ su bin
+ $ sg bin
+ $ umask 027
+ $ touch g
+ $ lfs ls -dl g | awk '{print $1}'
+ > -rw-r-----
+
+ $ lfs lsetfacl -m m:- g
+ $ lfs ls -dl g | awk '{print $1}'
+ > -rw-------+
+
+ $ lfs lgetfacl g
+ > # file: g
+ > # owner: bin
+ > # group: bin
+ > user::rw-
+ > group::r-- #effective:---
+ > mask::---
+ > other::---
+ >
+
+ $ lfs lsetfacl -x m g
+ $ lfs lgetfacl g
+ > # file: g
+ > # owner: bin
+ > # group: bin
+ > user::rw-
+ > group::r--
+ > other::---
+ >
+
+ $ lfs lsetfacl -m u:daemon:rw g
+ $ lfs lgetfacl g
+ > # file: g
+ > # owner: bin
+ > # group: bin
+ > user::rw-
+ > user:daemon:rw-
+ > group::r--
+ > mask::rw-
+ > other::---
+ >
+
+ $ lfs lsetfacl -m u::rwx,g::r-x,o:- g
+ $ lfs lgetfacl g
+ > # file: g
+ > # owner: bin
+ > # group: bin
+ > user::rwx
+ > user:daemon:rw-
+ > group::r-x
+ > mask::rwx
+ > other::---
+ >
+
+ $ lfs lsetfacl -m u::rwx,g::r-x,o:-,m:- g
+ $ lfs lgetfacl g
+ > # file: g
+ > # owner: bin
+ > # group: bin
+ > user::rwx
+ > user:daemon:rw- #effective:---
+ > group::r-x #effective:---
+ > mask::---
+ > other::---
+ >
+
+ $ lfs lsetfacl -m u::rwx,g::r-x,o:-,u:root:-,m:- g
+ $ lfs lgetfacl g
+ > # file: g
+ > # owner: bin
+ > # group: bin
+ > user::rwx
+ > user:root:---
+ > user:daemon:rw- #effective:---
+ > group::r-x #effective:---
+ > mask::---
+ > other::---
+ >
+
+ $ lfs lsetfacl -m u::rwx,g::r-x,o:-,u:root:-,m:- g
+ $ lfs lgetfacl g
+ > # file: g
+ > # owner: bin
+ > # group: bin
+ > user::rwx
+ > user:root:---
+ > user:daemon:rw- #effective:---
+ > group::r-x #effective:---
+ > mask::---
+ > other::---
+ >
+
+ $ lfs lsetfacl -m u::rwx,g::r-x,o:-,u:root:- g
+ $ lfs lgetfacl g
+ > # file: g
+ > # owner: bin
+ > # group: bin
+ > user::rwx
+ > user:root:---
+ > user:daemon:rw-
+ > group::r-x
+ > mask::rwx
+ > other::---
+ >
+
+ $ lfs lsetfacl --test -x u: g
+ > setfacl: g: Malformed access ACL `user:root:---,user:daemon:rw-,group::r-x,mask::rwx,other::---': Missing or wrong entry at entry 1
+
+ $ lfs lsetfacl --test -x u:x
+ > setfacl: Option -x: Invalid argument near character 3
+
+ $ lfs lsetfacl -m d:u:root:rwx g
+ > setfacl: g: Only directories can have default ACLs
+
+ $ lfs lsetfacl -x m g
+ > setfacl: g: Malformed access ACL `user::rwx,user:root:---,user:daemon:rw-,group::r-x,other::---': Missing or wrong entry at entry 5
+ lfs lsetfacl --test -m d:u:daemon:rwx lfs lsetfacl
+ lfs lsetfacl --test -n -m d:u:daemon:rwx lfs lsetfacl
+
+Check if the mask is properly recalculated
+
+ $ mkdir d
+ $ lfs lsetfacl --test -m u::rwx,u:bin:rwx,g::r-x,o::--- d
+ > d: u::rwx,u:bin:rwx,g::r-x,m::rwx,o::---,*
+
+ $ lfs lsetfacl --test -m u::rwx,u:bin:rwx,g::r-x,m::---,o::--- d
+ > d: u::rwx,u:bin:rwx,g::r-x,m::---,o::---,*
+
+ $ lfs lsetfacl --test -d -m u::rwx,u:bin:rwx,g::r-x,o::--- d
+ > d: *,d:u::rwx,d:u:bin:rwx,d:g::r-x,d:m::rwx,d:o::---
+
+ $ lfs lsetfacl --test -d -m u::rwx,u:bin:rwx,g::r-x,m::---,o::--- d
+ > d: *,d:u::rwx,d:u:bin:rwx,d:g::r-x,d:m::---,d:o::---
+
+ $ su
+ $ cd ..
+ $ rm -r d
ONLY=${ONLY:-"$*"}
# bug number for skipped test:
-ALWAYS_EXCEPT=${ALWAYS_EXCEPT:-""}
+ALWAYS_EXCEPT=${ALWAYS_EXCEPT:-"$SANITY_GSS_EXCEPT"}
# UPDATE THE COMMENT ABOVE WITH BUG NUMBERS WHEN CHANGING ALWAYS_EXCEPT!
-if [ "x$GSS_PIPEFS" != "xy" ]; then
- ALWAYS_EXCEPT="$ALWAYS_EXCEPT 4"
-fi
-[ "$SLOW" = "no" ] && EXCEPT="$EXCEPT"
+[ "$SLOW" = "no" ] && EXCEPT_SLOW="100 101"
-# Tests that fail on uml, maybe elsewhere, FIXME
+# Tests that fail on uml
CPU=`awk '/model/ {print $4}' /proc/cpuinfo`
[ "$CPU" = "UML" ] && EXCEPT="$EXCEPT"
SRCDIR=`dirname $0`
export PATH=$PWD/$SRCDIR:$SRCDIR:$SRCDIR/../utils:$SRCDIR/../utils/gss:$PATH:/sbin
+export NAME=${NAME:-local}
+SAVE_PWD=$PWD
-TMP=${TMP:-/tmp}
+CLEANUP=${CLEANUP:-""}
+SETUP=${SETUP:-""}
-CHECKSTAT=${CHECKSTAT:-"checkstat -v"}
-CREATETEST=${CREATETEST:-createtest}
-LFS=${LFS:-lfs}
-LCTL=${LCTL:-lctl}
-MEMHOG=${MEMHOG:-memhog}
-DIRECTIO=${DIRECTIO:-directio}
-ACCEPTOR_PORT=${ACCEPTOR_PORT:-988}
-UMOUNT=${UMOUNT:-"umount -d"}
+LUSTRE=${LUSTRE:-`dirname $0`/..}
+. $LUSTRE/tests/test-framework.sh
+init_test_env $@
+. ${CONFIG:=$LUSTRE/tests/cfg/$NAME.sh}
if [ $UID -ne 0 ]; then
echo "Warning: running as non-root uid $UID"
RUNAS=${RUNAS:-"runas -u $RUNAS_ID"}
# $RUNAS_ID may get set incorrectly somewhere else
- if [ $RUNAS_ID -eq 0 ]; then
- echo "Error: \$RUNAS_ID set to 0, but \$UID is also 0!"
- exit 1
- fi
+ [ $RUNAS_ID -eq 0 ] && error "\$RUNAS_ID set to 0, but \$UID is also 0!"
fi
-SANITYLOG=${SANITYLOG:-/tmp/sanity-gss.log}
-
-export NAME=${NAME:-local}
-
-SAVE_PWD=$PWD
-
-export SEC=${SEC:-krb5p}
-export KRB5_CCACHE_DIR=/tmp
-export KRB5_CRED=$KRB5_CCACHE_DIR/krb5cc_$RUNAS_ID
-export KRB5_CRED_SAVE=$KRB5_CCACHE_DIR/krb5cc.sanity.save
+# remove $SEC, we'd like to control everything by ourselves
+unset SEC
#
-# check pre-set $SEC
+# global variables of this sanity
#
-case "x$SEC" in
- xkrb5*)
- echo "Using ptlrpc security flavor $SEC"
- ;;
- *)
- echo "SEC=$SEC is invalid, it has to be gss/krb5 flavor"
- exit 1
- ;;
-esac
+KRB5_CCACHE_DIR=/tmp
+KRB5_CRED=$KRB5_CCACHE_DIR/krb5cc_$RUNAS_ID
+KRB5_CRED_SAVE=$KRB5_CCACHE_DIR/krb5cc.sanity.save
+CLICOUNT=2
+cnt_mdt2ost=0
+cnt_mdt2mdt=0
+cnt_cli2ost=0
+cnt_cli2mdt=0
+cnt_all2ost=0
+cnt_all2mdt=0
+cnt_all2all=0
+DBENCH_PID=0
+PROC_CLI="srpc.info"
+
+# set manually
+GSS=true
+GSS_KRB5=true
+
+# we want double mount
+MOUNT_2=${MOUNT_2:-"yes"}
+cleanup_and_setup_lustre
+
+rm -rf $DIR/${TESTSUITE}/[df][0-9]*
+rm -rf $DIR/[df][0-9]*
+
+check_runas_id $RUNAS_ID $RUNAS
-LUSTRE=${LUSTRE:-`dirname $0`/..}
-. $LUSTRE/tests/test-framework.sh
-init_test_env $@
-. ${CONFIG:=$LUSTRE/tests/cfg/local.sh}
+build_test_filter
prepare_krb5_creds() {
- rm -f $CRED_SAVE
+ rm -f $KRB5_CRED_SAVE
$RUNAS krb5_login.sh || exit 1
[ -f $KRB5_CRED ] || exit 2
cp $KRB5_CRED $KRB5_CRED_SAVE
}
-cleanup() {
- echo -n "cln.."
- cleanupall ${FORCE} $* || { echo "FAILed to clean up"; exit 20; }
+combination()
+{
+ local M=$1
+ local N=$2
+ local R=1
+
+ if [ $M -lt $N ]; then
+ R=0
+ else
+ N=$((N + 1))
+ while [ $N -le $M ]; do
+ R=$((R * N))
+ N=$((N + 1))
+ done
+ fi
+
+ echo $R
+ return 0
}
-CLEANUP=${CLEANUP:-:}
-setup() {
- echo -n "mnt.."
- load_modules
- setupall || exit 10
- echo "done"
+calc_connection_cnt() {
+ # MDT->MDT = 2 * C(M, 2)
+ # MDT->OST = M * O
+ # CLI->OST = C * O
+ # CLI->MDT = C * M
+ comb_m2=$(combination $MDSCOUNT 2)
+
+ cnt_mdt2mdt=$((comb_m2 * 2))
+ cnt_mdt2ost=$((MDSCOUNT * OSTCOUNT))
+ cnt_cli2ost=$((CLICOUNT * OSTCOUNT))
+ cnt_cli2mdt=$((CLICOUNT * MDSCOUNT))
+ cnt_all2ost=$((cnt_mdt2ost + cnt_cli2ost))
+ cnt_all2mdt=$((cnt_mdt2mdt + cnt_cli2mdt))
+ cnt_all2all=$((cnt_mdt2ost + cnt_mdt2mdt + cnt_cli2ost + cnt_cli2mdt))
}
-SETUP=${SETUP:-:}
-trace() {
- log "STARTING: $*"
- strace -o $TMP/$1.strace -ttt $*
- RC=$?
- log "FINISHED: $*: rc $RC"
- return 1
+set_rule()
+{
+ local tgt=$1
+ local net=$2
+ local dir=$3
+ local flavor=$4
+ local cmd="$tgt.srpc.flavor"
+
+ if [ $net == "any" ]; then
+ net="default"
+ fi
+ cmd="$cmd.$net"
+
+ if [ $dir != "any" ]; then
+ cmd="$cmd.$dir"
+ fi
+
+ cmd="$cmd=$flavor"
+ log "Setting sptlrpc rule: $cmd"
+ do_facet mgs "$LCTL conf_param $cmd"
+}
+
+count_flvr()
+{
+ output=$1
+ flavor=$2
+
+ echo "$output" | grep rpc | grep $flavor | wc -l
}
-TRACE=${TRACE:-""}
-check_kernel_version() {
- VERSION_FILE=$LPROC/kernel_version
- WANT_VER=$1
- [ ! -f $VERSION_FILE ] && echo "can't find kernel version" && return 1
- GOT_VER=`cat $VERSION_FILE`
- [ $GOT_VER -ge $WANT_VER ] && return 0
- log "test needs at least kernel version $WANT_VER, running $GOT_VER"
+flvr_cnt_cli2mdt()
+{
+ local flavor=$1
+
+ output=`do_facet client cat $LPROC/mdc/*-MDT*-mdc-*/$PROC_CLI 2>/dev/null`
+ count_flvr "$output" $flavor
+}
+
+flvr_cnt_cli2ost()
+{
+ local flavor=$1
+
+ output=`do_facet client cat $LPROC/osc/*OST*-osc-[^M][^D][^T]*/$PROC_CLI 2>/dev/null`
+ count_flvr "$output" $flavor
+}
+
+flvr_cnt_mdt2mdt()
+{
+ local flavor=$1
+ local cnt=0
+
+ if [ $MDSCOUNT -le 1 ]; then
+ echo 0
+ return
+ fi
+
+ for num in `seq $MDSCOUNT`; do
+ output=`do_facet mds$num cat $LPROC/mdc/*-MDT*-mdc[0-9]*/$PROC_CLI 2>/dev/null`
+ tmpcnt=`count_flvr "$output" $flavor`
+ cnt=$((cnt + tmpcnt))
+ done
+ echo $cnt;
+}
+
+flvr_cnt_mdt2ost()
+{
+ local flavor=$1
+ local cnt=0
+
+ for num in `seq $MDSCOUNT`; do
+ output=`do_facet mds$num cat $LPROC/osc/*OST*-osc-MDT*/$PROC_CLI 2>/dev/null`
+ tmpcnt=`count_flvr "$output" $flavor`
+ cnt=$((cnt + tmpcnt))
+ done
+ echo $cnt;
+}
+
+do_check_flavor()
+{
+ local dir=$1 # from to
+ local flavor=$2 # flavor expected
+ local res=0
+
+ if [ $dir == "cli2mdt" ]; then
+ res=`flvr_cnt_cli2mdt $flavor`
+ elif [ $dir == "cli2ost" ]; then
+ res=`flvr_cnt_cli2ost $flavor`
+ elif [ $dir == "mdt2mdt" ]; then
+ res=`flvr_cnt_mdt2mdt $flavor`
+ elif [ $dir == "mdt2ost" ]; then
+ res=`flvr_cnt_mdt2ost $flavor`
+ elif [ $dir == "all2ost" ]; then
+ res1=`flvr_cnt_mdt2ost $flavor`
+ res2=`flvr_cnt_cli2ost $flavor`
+ res=$((res1 + res2))
+ elif [ $dir == "all2mdt" ]; then
+ res1=`flvr_cnt_mdt2mdt $flavor`
+ res2=`flvr_cnt_cli2mdt $flavor`
+ res=$((res1 + res2))
+ elif [ $dir == "all2all" ]; then
+ res1=`flvr_cnt_mdt2ost $flavor`
+ res2=`flvr_cnt_cli2ost $flavor`
+ res3=`flvr_cnt_mdt2mdt $flavor`
+ res4=`flvr_cnt_cli2mdt $flavor`
+ res=$((res1 + res2 + res3 + res4))
+ fi
+
+ echo $res
+}
+
+wait_flavor()
+{
+ local dir=$1 # from to
+ local flavor=$2 # flavor expected
+ local expect=$3 # number expected
+ local res=0
+
+ for ((i=0;i<20;i++)); do
+ echo -n "checking..."
+ res=$(do_check_flavor $dir $flavor)
+ if [ $res -eq $expect ]; then
+ echo "found $res $flavor connections of $dir, OK"
+ return 0
+ else
+ echo "found $res $flavor connections of $dir, not ready ($expect)"
+ sleep 4
+ fi
+ done
+
+ echo "Error checking $flavor of $dir: expect $expect, actual $res"
return 1
}
-_basetest() {
- echo $*
+restore_to_default_flavor()
+{
+ local proc=$LPROC/mgs/MGS/live/$FSNAME
+
+ echo "restoring to default flavor..."
+
+ nrule=`do_facet mgs cat $proc 2>/dev/null | grep "$FSNAME.srpc.flavor." | wc -l`
+
+ # remove all existing rules if any
+ if [ $nrule -ne 0 ]; then
+ echo "remove existing $nrule rules"
+ for rule in `do_facet mgs cat $proc 2>/dev/null | grep "$FSNAME.srpc.flavor."`; do
+ spec=`echo $rule | awk -F = '{print $1}'`
+ do_facet mgs "$LCTL conf_param $spec="
+ done
+ fi
+
+ # verify no rules left
+ nrule=`do_facet mgs cat $proc 2>/dev/null | grep "$FSNAME.srpc.flavor." | wc -l`
+ [ $nrule -ne 0 ] && error "still $nrule rules left"
+
+ # wait for default flavor to be applied
+ # currently default flavor for all connections are 'null'
+ wait_flavor all2all null $cnt_all2all
+ echo "now at default flavor settings"
}
-[ "$SANITYLOG" ] && rm -f $SANITYLOG || true
+set_flavor_all()
+{
+ local flavor=$1
+ echo "setting all flavor to $flavor"
-prepare_krb5_creds
-build_test_filter
-umask 077
+ res=$(do_check_flavor all2all $flavor)
+ if [ $res -eq $cnt_all2all ]; then
+ echo "already have total $res $flavor connections"
+ return
+ fi
-# setup filesystem
-formatall
-setupall
-chmod a+rwx $MOUNT
+ echo "found $res $flavor out of total $cnt_all2all connections"
+ restore_to_default_flavor
+
+ set_rule $FSNAME any any $flavor
+ wait_flavor all2all $flavor $cnt_all2all
+}
+
+start_dbench()
+{
+ NPROC=`cat /proc/cpuinfo 2>/dev/null | grep ^processor | wc -l`
+ [ $NPROC -lt 2 ] && NPROC=2
+ sh rundbench $NPROC 1>/dev/null &
+ DBENCH_PID=$!
+ sleep 2
+
+ num=`ps --no-headers -p $DBENCH_PID 2>/dev/null | wc -l`
+ if [ $num -ne 1 ]; then
+ error "failed to start dbench $NPROC"
+ else
+ echo "started dbench with $NPROC processes at background"
+ fi
+
+ return 0
+}
+
+check_dbench()
+{
+ num=`ps --no-headers -p $DBENCH_PID 2>/dev/null | wc -l`
+ if [ $num -eq 0 ]; then
+ echo "dbench $DBENCH_PID already finished"
+ wait $DBENCH_PID || error "dbench $PID exit with error"
+ start_dbench
+ elif [ $num -ne 1 ]; then
+ killall -9 dbench
+ error "found $num instance of pid $DBENCH_PID ???"
+ fi
+
+ return 0
+}
+
+stop_dbench()
+{
+ for ((;;)); do
+ killall dbench 2>/dev/null
+ num=`ps --no-headers -p $DBENCH_PID | wc -l`
+ if [ $num -eq 0 ]; then
+ echo "dbench finished"
+ break
+ fi
+ echo "dbench $DBENCH_PID is still running, waiting 2s..."
+ sleep 2
+ done
+
+ wait $DBENCH_PID || true
+ sync || true
+}
restore_krb5_cred() {
cp $KRB5_CRED_SAVE $KRB5_CRED
chmod 0600 $KRB5_CRED
}
+check_multiple_gss_daemons() {
+ local facet=$1
+ local gssd=$2
+ local gssd_name=`basename $gssd`
+
+ for ((i=0;i<10;i++)); do
+ do_facet $facet "$gssd -v &"
+ done
+
+ # wait daemons entering "stable" status
+ sleep 5
+
+ num=`do_facet $facet ps -o cmd -C $gssd_name | grep $gssd_name | wc -l`
+ echo "$num instance(s) of $gssd_name are running"
+
+ if [ $num -ne 1 ]; then
+ error "$gssd_name not unique"
+ fi
+}
+
+prepare_krb5_creds
+calc_connection_cnt
+umask 077
+
+test_0() {
+ local my_facet=mds
+
+ echo "bring up gss daemons..."
+ start_gss_daemons
+
+ echo "check with someone already running..."
+ check_multiple_gss_daemons $my_facet $LSVCGSSD
+ if $GSS_PIPEFS; then
+ check_multiple_gss_daemons $my_facet $LGSSD
+ fi
+
+ echo "check with someone run & finished..."
+ do_facet $my_facet killall -q -2 lgssd lsvcgssd || true
+ sleep 5 # wait fully exit
+ check_multiple_gss_daemons $my_facet $LSVCGSSD
+ if $GSS_PIPEFS; then
+ check_multiple_gss_daemons $my_facet $LGSSD
+ fi
+
+ echo "check refresh..."
+ do_facet $my_facet killall -q -2 lgssd lsvcgssd || true
+ sleep 5 # wait fully exit
+ do_facet $my_facet ipcrm -S 0x3b92d473
+ check_multiple_gss_daemons $my_facet $LSVCGSSD
+ if $GSS_PIPEFS; then
+ do_facet $my_facet ipcrm -S 0x3a92d473
+ check_multiple_gss_daemons $my_facet $LGSSD
+ fi
+}
+run_test 0 "start multiple gss daemons"
+
+set_flavor_all krb5p
+
test_1() {
+ local file=$DIR/$tfile
+
+ chmod 0777 $DIR || error "chmod $DIR failed"
# access w/o cred
$RUNAS kdestroy
- $RUNAS touch $MOUNT/f1 && error "unexpected success"
+ $RUNAS touch $file && error "unexpected success"
# access w/ cred
restore_krb5_cred
- $RUNAS touch $MOUNT/f1 || error "should not fail"
- [ -f $MOUNT/f1 ] || error "$MOUNT/f1 not found"
+ $RUNAS touch $file || error "should not fail"
+ [ -f $file ] || error "$file not found"
}
run_test 1 "access with or without krb5 credential"
test_2() {
+ local file1=$DIR/$tfile-1
+ local file2=$DIR/$tfile-2
+
+ chmod 0777 $DIR || error "chmod $DIR failed"
# current access should be ok
- $RUNAS touch $MOUNT/f2_1 || error "can't touch $MOUNT/f2_1"
- [ -f $MOUNT/f2_1 ] || error "$MOUNT/f2_1 not found"
+ $RUNAS touch $file1 || error "can't touch $file1"
+ [ -f $file1 ] || error "$file1 not found"
# cleanup all cred/ctx and touch
$RUNAS kdestroy
$RUNAS $LFS flushctx || error "can't flush ctx"
- $RUNAS touch $MOUNT/f2_2 && error "unexpected success"
+ $RUNAS touch $file2 && error "unexpected success"
# restore and touch
restore_krb5_cred
- $RUNAS touch $MOUNT/f2_2 || error "should not fail"
- [ -f $MOUNT/f2_2 ] || error "$MOUNT/f2_2 not found"
+ $RUNAS touch $file2 || error "should not fail"
+ [ -f $file2 ] || error "$file2 not found"
}
run_test 2 "lfs flushctx"
test_3() {
- local file=$MOUNT/f3
+ local file=$DIR/$tfile
# create file
echo "aaaaaaaaaaaaaaaaa" > $file
run_test 3 "local cache under DLM lock"
test_4() {
- local file1=$MOUNT/f4_1
- local file2=$MOUNT/f4_2
+ local file1=$DIR/$tfile-1
+ local file2=$DIR/$tfile-2
+ ! $GSS_PIPEFS && skip "pipefs not used" && return
+
+ chmod 0777 $DIR || error "chmod $DIR failed"
# current access should be ok
$RUNAS touch $file1 || error "can't touch $file1"
[ -f $file1 ] || error "$file1 not found"
run_test 4 "lgssd dead, operations should wait timeout and fail"
test_5() {
- local file1=$MOUNT/f5_1
- local file2=$MOUNT/f5_2
- local wait_time=`expr $TIMEOUT + $TIMEOUT`
+ local file1=$DIR/$tfile-1
+ local file2=$DIR/$tfile-2
+ local wait_time=$((TIMEOUT + TIMEOUT / 2))
+ chmod 0777 $DIR || error "chmod $DIR failed"
# current access should be ok
$RUNAS touch $file1 || error "can't touch $file1"
[ -f $file1 ] || error "$file1 not found"
run_test 5 "lsvcgssd dead, operations lead to recovery"
test_6() {
- NPROC=`cat /proc/cpuinfo 2>/dev/null | grep ^processor | wc -l`
- [ $NPROC -ne 0 ] || NPROC=2
-
- echo "starting dbench $NPROC"
- sh rundbench $NPROC &
- RUNPID=$!
-
- for ((n=0;;n++)); do
- sleep 2
- num=`ps --no-headers -p $RUNPID | wc -l`
- [ $num -ne 0 ] || break
- echo "flush ctx ..."
- $LFS flushctx
- done
- wait $RUNPID || error "dbench detect error"
+ mkdir $DIR/d6 || error "mkdir $DIR/d6 failed"
+ cp -a /etc/* $DIR/d6/ || error "cp failed"
+ ls -l $DIR/d6/* > /dev/null || error "ls failed"
+ rm -rf $DIR2/d6/* || error "rm failed"
}
-run_test 6 "recoverable from losing context"
+run_test 6 "test basic DLM callback works"
test_7() {
- local tdir=$MOUNT/dir7
+ local tdir=$DIR/d7
local num_osts
#
}
run_test 7 "exercise enlarge_reqbuf()"
-check_multiple_gss_daemons() {
- local facet=$1
- local gssd=$2
- local gssd_name=`basename $gssd`
+test_90() {
+ if [ "$SLOW" = "no" ]; then
+ total=10
+ else
+ total=60
+ fi
- for ((i=0;i<10;i++)); do
- do_facet $facet "$gssd -v &"
+ start_dbench
+
+ for ((n=0;n<$total;n++)); do
+ sleep 2
+ check_dbench
+ echo "flush ctx ($n/$total) ..."
+ $LFS flushctx
done
+ check_dbench
+ stop_dbench
+}
+run_test 90 "recoverable from losing contexts under load"
- # wait daemons entering "stable" status
- sleep 5
+test_99() {
+ local nrule_old=0
+ local nrule_new=0
+ local max=32
- num=`do_facet $facet ps -o cmd -C $gssd_name | grep $gssd_name | wc -l`
- echo "$num instance(s) of $gssd_name are running"
+ #
+ # general rules
+ #
+ nrule_old=`do_facet mgs cat $LPROC/mgs/MGS/live/$FSNAME 2>/dev/null \
+ | grep "$FSNAME.srpc.flavor." | wc -l`
+ echo "original general rules: $nrule_old"
- if [ $num -ne 1 ]; then
- error "$gssd_name not unique"
+ for ((i = $nrule_old; i < $max; i++)); do
+ set_rule $FSNAME elan$i any krb5n || error "set rule $i"
+ done
+ set_rule $FSNAME elan100 any krb5n && error "set $max rule should fail"
+ for ((i = $nrule_old; i < $max; i++)); do
+ set_rule $FSNAME elan$i any || error "remove rule $i"
+ done
+
+ nrule_new=`do_facet mgs cat $LPROC/mgs/MGS/live/$FSNAME 2>/dev/null \
+ | grep "$FSNAME.srpc.flavor." | wc -l`
+ if [ $nrule_new != $nrule_old ]; then
+ error "general rule: $nrule_new != $nrule_old"
fi
+
+ #
+ # target-specific rules
+ #
+ nrule_old=`do_facet mgs cat $LPROC/mgs/MGS/live/$FSNAME 2>/dev/null \
+ | grep "$FSNAME-MDT0000.srpc.flavor." | wc -l`
+ echo "original target rules: $nrule_old"
+
+ for ((i = $nrule_old; i < $max; i++)); do
+ set_rule $FSNAME-MDT0000 elan$i any krb5i || error "set rule $i"
+ done
+ set_rule $FSNAME-MDT0000 elan100 any krb5i && error "set $max rule should fail"
+ for ((i = $nrule_old; i < $max; i++)); do
+ set_rule $FSNAME-MDT0000 elan$i any || error "remove rule $i"
+ done
+
+ nrule_new=`do_facet mgs cat $LPROC/mgs/MGS/live/$FSNAME 2>/dev/null \
+ | grep "$FSNAME-MDT0000.srpc.flavor." | wc -l`
+ if [ $nrule_new != $nrule_old ]; then
+ error "general rule: $nrule_new != $nrule_old"
+ fi
+}
+run_test 99 "maximum sptlrpc rules limitation"
+
+error_dbench()
+{
+ local err_str=$1
+
+ killall -9 dbench
+ sleep 1
+
+ error $err_str
}
test_100() {
- local facet=mds
+ # started from default flavors
+ restore_to_default_flavor
- # cleanup everything at first
- cleanupall
+ # running dbench background
+ start_dbench
- echo "bring up gss daemons..."
- start_gss_daemons
+ #
+ # all: null -> krb5n -> krb5a -> krb5i -> krb5p -> plain
+ #
+ set_rule $FSNAME any any krb5n
+ wait_flavor all2all krb5n $cnt_all2all || error_dbench "1"
+ check_dbench
- echo "check with someone already running..."
- check_multiple_gss_daemons $facet $LSVCGSSD
- if [ "x$GSS_PIPEFS" == "xy" ]; then
- check_multiple_gss_daemons $facet $LGSSD
- fi
+ set_rule $FSNAME any any krb5a
+ wait_flavor all2all krb5a $cnt_all2all || error_dbench "2"
+ check_dbench
- echo "check with someone run & finished..."
- do_facet $facet killall -q -2 lgssd lsvcgssd || true
- sleep 5 # wait fully exit
- check_multiple_gss_daemons $facet $LSVCGSSD
- if [ "x$GSS_PIPEFS" == "xy" ]; then
- check_multiple_gss_daemons $facet $LGSSD
- fi
+ set_rule $FSNAME any any krb5i
+ wait_flavor all2all krb5i $cnt_all2all || error_dbench "3"
+ check_dbench
- echo "check refresh..."
- do_facet $facet killall -q -2 lgssd lsvcgssd || true
- sleep 5 # wait fully exit
- do_facet $facet ipcrm -S 0x3b92d473
- check_multiple_gss_daemons $facet $LSVCGSSD
- if [ "x$GSS_PIPEFS" == "xy" ]; then
- do_facet $facet ipcrm -S 0x3a92d473
- check_multiple_gss_daemons $facet $LGSSD
+ set_rule $FSNAME any any krb5p
+ wait_flavor all2all krb5p $cnt_all2all || error_dbench "4"
+ check_dbench
+
+ set_rule $FSNAME any any plain
+ wait_flavor all2all plain $cnt_all2all || error_dbench "5"
+ check_dbench
+
+ #
+ # M - M: krb5a
+ # C - M: krb5i
+ # M - O: krb5p
+ # C - O: krb5n
+ #
+ set_rule $FSNAME any mdt2mdt krb5a
+ wait_flavor mdt2mdt krb5a $cnt_mdt2mdt || error_dbench "6"
+ check_dbench
+
+ set_rule $FSNAME any cli2mdt krb5i
+ wait_flavor cli2mdt krb5i $cnt_cli2mdt || error_dbench "7"
+ check_dbench
+
+ set_rule $FSNAME any mdt2ost krb5p
+ wait_flavor mdt2ost krb5p $cnt_mdt2ost || error_dbench "8"
+ check_dbench
+
+ set_rule $FSNAME any cli2ost krb5n
+ wait_flavor cli2ost krb5n $cnt_cli2ost || error_dbench "9"
+ check_dbench
+
+ #
+ # * - MDT0: krb5p
+ # * - OST0: krb5i
+ #
+ # nothing should be changed because they are override by above dir rules
+ #
+ set_rule $FSNAME-MDT0000 any any krb5p
+ set_rule $FSNAME-OST0000 any any krb5i
+ wait_flavor mdt2mdt krb5a $cnt_mdt2mdt || error_dbench "10"
+ wait_flavor cli2mdt krb5i $cnt_cli2mdt || error_dbench "11"
+ check_dbench
+ wait_flavor mdt2ost krb5p $cnt_mdt2ost || error_dbench "12"
+ wait_flavor cli2ost krb5n $cnt_cli2ost || error_dbench "13"
+
+ #
+ # delete all dir-specific rules
+ #
+ set_rule $FSNAME any mdt2mdt
+ set_rule $FSNAME any cli2mdt
+ set_rule $FSNAME any mdt2ost
+ set_rule $FSNAME any cli2ost
+ wait_flavor mdt2mdt krb5p $((MDSCOUNT - 1)) || error_dbench "14"
+ wait_flavor cli2mdt krb5p $CLICOUNT || error_dbench "15"
+ check_dbench
+ wait_flavor mdt2ost krb5i $MDSCOUNT || error_dbench "16"
+ wait_flavor cli2ost krb5i $CLICOUNT || error_dbench "17"
+ check_dbench
+
+ #
+ # remove:
+ # * - MDT0: krb5p
+ # * - OST0: krb5i
+ #
+ set_rule $FSNAME-MDT0000 any any
+ set_rule $FSNAME-OST0000 any any || error_dbench "18"
+ wait_flavor all2all plain $cnt_all2all || error_dbench "19"
+ check_dbench
+
+ stop_dbench
+}
+run_test 100 "change security flavor on the fly under load"
+
+switch_sec_test()
+{
+ local count=$1
+ local flavor0=$2
+ local flavor1=$3
+ local flavor2=$4
+ local df_pid=0
+ local wait_time=$((TIMEOUT + TIMEOUT / 4))
+ local num
+
+ #
+ # stop gss daemon, then switch to flavor1 (which should be a gss flavor),
+ # and run a 'df' which should hanging, wait the request timeout and
+ # resend, then switch the flavor to another one. To exercise the code of
+ # switching ctx/sec for a resend request.
+ #
+ echo ">>>>>>>>>>>>>>> Testing $flavor0 -> $flavor1 -> $flavor2..."
+
+ echo "(0) set base flavor $flavor0"
+ set_rule $FSNAME any cli2mdt $flavor0
+ wait_flavor cli2mdt $flavor0 $count
+ df $MOUNT
+ if [ $? -ne 0 ]; then
+ error "initial df failed"
fi
stop_gss_daemons
+ sleep 1
+
+ echo "(1) $flavor0 -> $flavor1"
+ set_rule $FSNAME any cli2mdt $flavor1
+ wait_flavor cli2mdt $flavor1 $count
+ df $MOUNT &
+ df_pid=$!
+ sleep 1
+
+ echo "waiting $wait_time seconds for df ($df_pid)"
+ sleep $wait_time
+ num=`ps --no-headers -p $df_pid 2>/dev/null | wc -l`
+ [ $num -eq 1 ] || error "df already ended ($num)"
+ echo "process $df_pid is still hanging there... OK"
+
+ echo "(2) set end flavor $flavor2"
+ set_rule $FSNAME any cli2mdt $flavor2
+ wait_flavor cli2mdt $flavor2 $count
+ start_gss_daemons
+ wait $df_pid || error "df returned error"
}
-run_test 100 "start multiple gss daemons"
-TMPDIR=$OLDTMPDIR
-TMP=$OLDTMP
-HOME=$OLDHOME
+test_101()
+{
+ # started from default flavors
+ restore_to_default_flavor
+
+ switch_sec_test $cnt_cli2mdt null krb5n null
+ switch_sec_test $cnt_cli2mdt null krb5a null
+ switch_sec_test $cnt_cli2mdt null krb5i null
+ switch_sec_test $cnt_cli2mdt null krb5p null
+ switch_sec_test $cnt_cli2mdt null krb5i plain
+ switch_sec_test $cnt_cli2mdt plain krb5p plain
+ switch_sec_test $cnt_cli2mdt plain krb5n krb5a
+ switch_sec_test $cnt_cli2mdt krb5a krb5i krb5p
+ switch_sec_test $cnt_cli2mdt krb5p krb5a krb5n
+ switch_sec_test $cnt_cli2mdt krb5n krb5p krb5i
+}
+run_test 101 "switch ctx as well as sec for resending request"
-log "cleanup: ======================================================"
-if [ "`mount | grep ^$NAME`" ]; then
- rm -rf $DIR/[Rdfs][1-9]*
-fi
+error_102()
+{
+ local err_str=$1
-cleanupall -f || error "cleanup failed"
+ killall -9 dbench
+ sleep 1
+ error $err_str
+}
+
+test_102() {
+ # started from default flavors
+ restore_to_default_flavor
+
+ # run dbench background
+ start_dbench
+
+ echo "Testing null->krb5n->krb5a->krb5i->krb5p->plain->null"
+ set_rule $FSNAME any any krb5n
+ set_rule $FSNAME any any krb5a
+ set_rule $FSNAME any any krb5i
+ set_rule $FSNAME any any krb5p
+ set_rule $FSNAME any any plain
+ set_rule $FSNAME any any null
+
+ check_dbench
+ wait_flavor all2all null $cnt_all2all || error_dbench "1"
+ check_dbench
+
+ echo "waiting for 15s and check again"
+ sleep 15
+ check_dbench
+
+ echo "Testing null->krb5i->null->krb5i->null..."
+ for ((i=0; i<10; i++)); do
+ set_rule $FSNAME any any krb5i
+ set_rule $FSNAME any any null
+ done
+ set_rule $FSNAME any any krb5i
+
+ check_dbench
+ wait_flavor all2all krb5i $cnt_all2all || error_dbench "2"
+ check_dbench
+
+ echo "waiting for 15s and check again"
+ sleep 15
+ check_dbench
+
+ stop_dbench
+}
+run_test 102 "survive from insanely fast flavor switch"
-echo '=========================== finished ==============================='
-[ -f "$SANITYLOG" ] && cat $SANITYLOG && exit 1 || true
+equals_msg `basename $0`: test complete, cleaning up
+check_and_cleanup_lustre
+[ -f "$TESTSUITELOG" ] && cat $TESTSUITELOG || true
#!/bin/bash
#
-# Run select tests by setting SEC_ONLY, or as arguments to the script.
-# Skip specific tests by setting SEC_EXCEPT.
+# Run select tests by setting ONLY, or as arguments to the script.
+# Skip specific tests by setting EXCEPT.
#
set -e
+ONLY=${ONLY:-"$*"}
+[ "$EXCEPT" ] && echo "Skipping tests: `echo $EXCEPT`"
+
SRCDIR=`dirname $0`
export PATH=$PWD/$SRCDIR:$SRCDIR:$PWD/$SRCDIR/../utils:$PATH:/sbin
+export NAME=${NAME:-local}
+
+LUSTRE=${LUSTRE:-`dirname $0`/..}
+. $LUSTRE/tests/test-framework.sh
+init_test_env $@
+. ${CONFIG:=$LUSTRE/tests/cfg/$NAME.sh}
+
+RUNAS=${RUNAS:-"$LUSTRE/tests/runas"}
+WTL=${WTL:-"$LUSTRE/tests/write_time_limit"}
-SEC_ONLY=${SEC_ONLY:-"$*"}
-[ "$SEC_EXCEPT" ] && echo "Skipping tests: `echo $SEC_EXCEPT`"
-
-TMP=${TMP:-/tmp}
-LFS=${LFS:-lfs}
-LCTL=${LCTL:-lctl}
-RUNAS=${RUNAS:-runas}
-WTL=${WTL:-write_time_limit}
-
-LPROC=/proc/fs/lustre
-ENABLE_IDENTITY=/usr/sbin/l_getidentity
-DISABLE_IDENTITY=NONE
-LUSTRE_CONF_DIR=/etc/lustre
-PERM_CONF=$LUSTRE_CONF_DIR/perm.conf
-LDLM_LPROC=$LPROC/ldlm
+PERM_CONF=/etc/lustre/perm.conf
LLITE_LPROC=$LPROC/llite
MDC_LPROC=$LPROC/mdc
MDT_LPROC=$LPROC/mdt
OST_LPROC=$LPROC/obdfilter
-sec_log() {
- echo "$*"
- $LCTL mark "$*" 2> /dev/null || true
-}
-
-SANITYSECLOG=${SANITYSECLOG:-/tmp/sanity-sec.log}
-[ "$SANITYSECLOG" ] && rm -f $SANITYSECLOG || true
-
-sec_error() {
- sec_log "FAIL: $TESTNAME $@"
- if [ "$SANITYSECLOG" ]; then
- echo "FAIL: $TESTNAME $@" >> $SANITYSECLOG
- else
- exit 1
- fi
-}
-
-sec_pass() {
- echo PASS $@
-}
-
-sec_skip () {
- sec_log "$0: SKIP: $TESTNAME $@"
- [ "$SANITYSECLOG" ] && echo "$0: SKIP: $TESTNAME $@" >> $SANITYSECLOG
-}
-
-ID1=500
-ID2=501
+SANITYSECLOG=${TESTSUITELOG:-$TMP/$(basename $0 .sh).log}
+FAIL_ON_ERROR=false
+ID0=${ID0:-500}
+ID1=${ID1:-501}
+USER0=`cat /etc/passwd|grep :$ID0:$ID0:|cut -d: -f1`
USER1=`cat /etc/passwd|grep :$ID1:$ID1:|cut -d: -f1`
-USER2=`cat /etc/passwd|grep :$ID2:$ID2:|cut -d: -f1`
-if [ -z "$USER1" ]; then
- echo "===== Please add user1 (uid=$ID1 gid=$ID1)! Skip sanity-sec ====="
- sec_error "===== Please add user1 (uid=$ID1 gid=$ID1)! ====="
- exit 0
-fi
+[ -z "$USER0" ] && \
+ echo "Please add user0 (uid=$ID0 gid=$ID0)! Skip sanity-sec" && exit 0
-if [ -z "$USER2" ]; then
- echo "===== Please add user2 (uid=$ID2 gid=$ID2)! Skip sanity-sec ====="
- sec_error "===== Please add user2 (uid=$ID2 gid=$ID2)! ====="
- exit 0
-fi
+[ -z "$USER1" ] && \
+ echo "Please add user1 (uid=$ID1 gid=$ID1)! Skip sanity-sec" && exit 0
-export NAME=${NAME:-local}
-
-LUSTRE=${LUSTRE:-`dirname $0`/..}
-. $LUSTRE/tests/test-framework.sh
-init_test_env $@
-. ${CONFIG:=$LUSTRE/tests/cfg/$NAME.sh}
-
-mounted_lustre_filesystems() {
- awk '($3 ~ "lustre" && $1 ~ ":") { print $2 }' /proc/mounts
-}
-
-MOUNTED="`mounted_lustre_filesystems`"
-if [ -z "$MOUNTED" ]; then
- formatall
- setupall
- MOUNTED="`mounted_lustre_filesystems`"
- [ -z "$MOUNTED" ] && sec_error "NAME=$NAME not mounted"
- S_MOUNTED=yes
-fi
-
-[ `echo $MOUNT | wc -w` -gt 1 ] && sec_error "NAME=$NAME mounted more than once"
+check_and_setup_lustre
DIR=${DIR:-$MOUNT}
-[ -z "`echo $DIR | grep $MOUNT`" ] && echo "$DIR not in $MOUNT" && \
- sec_cleanup && exit 99
+[ -z "`echo $DIR | grep $MOUNT`" ] && \
+ error "$DIR not in $MOUNT" && sec_cleanup && exit 1
-[ `ls -l $LDLM_LPROC/namespaces 2>/dev/null | grep *-mdc-* | wc -l` -gt 1 ] \
- && echo "skip multi-MDS test" && sec_cleanup && exit 0
+[ `echo $MOUNT | wc -w` -gt 1 ] && \
+ echo "NAME=$MOUNT mounted more than once" && sec_cleanup && exit 0
-OST_COUNT=$(ls -l $LDLM_LPROC/namespaces 2>/dev/null | grep osc | grep -v MDT | wc -l)
+[ $MDSCOUNT -gt 1 ] && \
+ echo "skip multi-MDS test" && sec_cleanup && exit 0
# for GSS_SUP
GSS_REF=$(lsmod | grep ^ptlrpc_gss | awk '{print $3}')
echo "without GSS support"
fi
-# for MDT_TYPE
-MDT_REF=$(lsmod | grep ^mdt | awk '{print $3}')
-if [ ! -z "$MDT_REF" -a "$MDT_REF" != "0" ]; then
- MDT_TYPE="local"
- echo "local mdt"
-else
- MDT_TYPE="remote"
- echo "remote mdt"
-fi
-
-MDT="`do_facet $SINGLEMDS ls -l $MDT_LPROC/ | grep MDT | awk '{print $9}'`"
+MDT="`do_facet $SINGLEMDS \"ls -l $MDT_LPROC/ 2>/dev/null\" | grep MDT | awk '{print $9}'`"
if [ ! -z "$MDT" ]; then
- IDENTITY_UPCALL=$MDT_LPROC/$MDT/identity_upcall
- IDENTITY_UPCALL_BAK="`more $IDENTITY_UPCALL`"
IDENTITY_FLUSH=$MDT_LPROC/$MDT/identity_flush
- ROOTSQUASH_UID=$MDT_LPROC/$MDT/rootsquash_uid
- ROOTSQUASH_GID=$MDT_LPROC/$MDT/rootsquash_gid
- NOSQUASH_NIDS=$MDT_LPROC/$MDT/nosquash_nids
MDSCAPA=$MDT_LPROC/$MDT/capa
CAPA_TIMEOUT=$MDT_LPROC/$MDT/capa_timeout
fi
SAVE_PWD=$PWD
-sec_run_one() {
- BEFORE=`date +%s`
- sec_log "== test $1 $2= `date +%H:%M:%S` ($BEFORE)"
- export TESTNAME=test_$1
- test_$1 || sec_error "exit with rc=$?"
- unset TESTNAME
- sec_pass "($((`date +%s` - $BEFORE))s)"
-}
-
-build_test_filter() {
- for O in $SEC_ONLY; do
- eval SEC_ONLY_${O}=true
- done
- for E in $SEC_EXCEPT; do
- eval SEC_EXCEPT_${E}=true
- done
-}
-
-_basetest() {
- echo $*
-}
-
-basetest() {
- IFS=abcdefghijklmnopqrstuvwxyz _basetest $1
-}
-
-sec_run_test() {
- base=`basetest $1`
- if [ "$SEC_ONLY" ]; then
- testname=SEC_ONLY_$1
- if [ ${!testname}x != x ]; then
- sec_run_one $1 "$2"
- return $?
- fi
- testname=SEC_ONLY_$base
- if [ ${!testname}x != x ]; then
- sec_run_one $1 "$2"
- return $?
- fi
- echo -n "."
- return 0
- fi
- testname=SEC_EXCEPT_$1
- if [ ${!testname}x != x ]; then
- echo "skipping excluded test $1"
- return 0
- fi
- testname=SEC_EXCEPT_$base
- if [ ${!testname}x != x ]; then
- echo "skipping excluded test $1 (base $base)"
- return 0
- fi
- sec_run_one $1 "$2"
- return $?
-}
-
build_test_filter
sec_login() {
local group=$2
if ! $RUNAS -u $user krb5_login.sh; then
- echo "$user login kerberos failed."
+ error "$user login kerberos failed."
exit 1
fi
- if ! $RUNAS -u $user -g $group ls $DIR > /dev/null; then
+ if ! $RUNAS -u $user -g $group ls $DIR > /dev/null 2>&1; then
$RUNAS -u $user lfs flushctx -k
$RUNAS -u $user krb5_login.sh
- if ! $RUNAS -u $user -g $group ls $DIR > /dev/null; then
- echo "init $user $group failed."
+ if ! $RUNAS -u $user -g $group ls $DIR > /dev/null 2>&1; then
+ error "init $user $group failed."
exit 2
fi
fi
}
-setup() {
- if [ ! -z "$MDT" ]; then
- do_facet $SINGLEMDS echo $ENABLE_IDENTITY > $IDENTITY_UPCALL
- do_facet $SINGLEMDS echo -1 > $IDENTITY_FLUSH
+declare -a identity_old
+
+sec_setup() {
+ for num in `seq $MDSCOUNT`; do
+ switch_identity $num true || identity_old[$num]=$?
+ done
+
+ if ! $RUNAS -u $ID0 ls $DIR > /dev/null 2>&1; then
+ sec_login $USER0 $USER0
fi
if ! $RUNAS -u $ID1 ls $DIR > /dev/null 2>&1; then
sec_login $USER1 $USER1
fi
-
- if ! $RUNAS -u $ID2 ls $DIR > /dev/null 2>&1; then
- sec_login $USER2 $USER2
- fi
}
-setup
+sec_setup
# run as different user
test_0() {
rm -rf $DIR/d0
mkdir $DIR/d0
- chown $USER1 $DIR/d0 || sec_error
- $RUNAS -u $ID1 ls $DIR || sec_error
- $RUNAS -u $ID1 touch $DIR/f0 && sec_error
- $RUNAS -u $ID1 touch $DIR/d0/f1 || sec_error
- $RUNAS -u $ID2 touch $DIR/d0/f2 && sec_error
- touch $DIR/d0/f3 || sec_error
- chown root $DIR/d0
- chgrp $USER1 $DIR/d0
- chmod 775 $DIR/d0
- $RUNAS -u $ID1 touch $DIR/d0/f4 || sec_error
- $RUNAS -u $ID2 touch $DIR/d0/f5 && sec_error
- touch $DIR/d0/f6 || sec_error
+ chown $USER0 $DIR/d0 || error "chown (1)"
+ $RUNAS -u $ID0 ls $DIR || error "ls (2)"
+ $RUNAS -u $ID0 touch $DIR/f0 && error "touch (3)"
+ $RUNAS -u $ID0 touch $DIR/d0/f1 || error "touch (4)"
+ $RUNAS -u $ID1 touch $DIR/d0/f2 && error "touch (5)"
+ touch $DIR/d0/f3 || error "touch (6)"
+ chown root $DIR/d0 || error "chown (7)"
+ chgrp $USER0 $DIR/d0 || error "chgrp (8)"
+ chmod 775 $DIR/d0 || error "chmod (9)"
+ $RUNAS -u $ID0 touch $DIR/d0/f4 || error "touch (10)"
+ $RUNAS -u $ID1 touch $DIR/d0/f5 && error "touch (11)"
+ touch $DIR/d0/f6 || error "touch (12)"
rm -rf $DIR/d0
}
-sec_run_test 0 "uid permission ============================="
+run_test 0 "uid permission ============================="
# setuid/gid
test_1() {
- [ $GSS_SUP = 0 ] && sec_skip "without GSS support." && return
- [ -z "$MDT" ] && sec_skip "do not support do_facet operations." && return
+ [ $GSS_SUP = 0 ] && skip "without GSS support." && return
+ [ -z "$MDT" ] && skip "do not support do_facet operations." && return
+ [ "$CLIENT_TYPE" = "remote" ] && \
+ skip "test_1 for local client only" && return
- do_facet $SINGLEMDS rm -f $PERM_CONF
- do_facet $SINGLEMDS echo -1 > $IDENTITY_FLUSH
+ do_facet $SINGLEMDS "rm -f $PERM_CONF"
+ do_facet $SINGLEMDS "echo -1 > $IDENTITY_FLUSH"
rm -rf $DIR/d1
mkdir $DIR/d1
- chown $USER1 $DIR/d1 || sec_error
- $RUNAS -u $ID2 -v $ID1 touch $DIR/d1/f0 && sec_error
- do_facet $SINGLEMDS echo "\* $ID2 setuid" > $PERM_CONF
- echo "enable uid $ID2 setuid"
- do_facet $SINGLEMDS echo -1 > $IDENTITY_FLUSH
- $RUNAS -u $ID2 -v $ID1 touch $DIR/d1/f1 || sec_error
-
- chown root $DIR/d1
- chgrp $USER1 $DIR/d1
- chmod 770 $DIR/d1
- $RUNAS -u $ID2 -g $ID2 touch $DIR/d1/f2 && sec_error
- $RUNAS -u $ID2 -g $ID2 -j $ID1 touch $DIR/d1/f3 && sec_error
- do_facet $SINGLEMDS echo "\* $ID2 setuid,setgid" > $PERM_CONF
- echo "enable uid $ID2 setuid,setgid"
- do_facet $SINGLEMDS echo -1 > $IDENTITY_FLUSH
- $RUNAS -u $ID2 -g $ID2 -j $ID1 touch $DIR/d1/f4 || sec_error
- $RUNAS -u $ID2 -v $ID1 -g $ID2 -j $ID1 touch $DIR/d1/f5 || sec_error
+ chown $USER0 $DIR/d1 || error "chown (1)"
+ $RUNAS -u $ID1 -v $ID0 touch $DIR/d1/f0 && error "touch (2)"
+ do_facet $SINGLEMDS "echo '* $ID1 setuid' > $PERM_CONF"
+ echo "enable uid $ID1 setuid"
+ do_facet $SINGLEMDS "echo -1 > $IDENTITY_FLUSH"
+ $RUNAS -u $ID1 -v $ID0 touch $DIR/d1/f1 || error "touch (3)"
+
+ chown root $DIR/d1 || error "chown (4)"
+ chgrp $USER0 $DIR/d1 || error "chgrp (5)"
+ chmod 770 $DIR/d1 || error "chmod (6)"
+ $RUNAS -u $ID1 -g $ID1 touch $DIR/d1/f2 && error "touch (7)"
+ $RUNAS -u $ID1 -g $ID1 -j $ID0 touch $DIR/d1/f3 && error "touch (8)"
+ do_facet $SINGLEMDS "echo '* $ID1 setuid,setgid' > $PERM_CONF"
+ echo "enable uid $ID1 setuid,setgid"
+ do_facet $SINGLEMDS "echo -1 > $IDENTITY_FLUSH"
+ $RUNAS -u $ID1 -g $ID1 -j $ID0 touch $DIR/d1/f4 || error "touch (9)"
+ $RUNAS -u $ID1 -v $ID0 -g $ID1 -j $ID0 touch $DIR/d1/f5 || error "touch (10)"
rm -rf $DIR/d1
- do_facet $SINGLEMDS rm -f $PERM_CONF
- do_facet $SINGLEMDS echo -1 > $IDENTITY_FLUSH
+ do_facet $SINGLEMDS "rm -f $PERM_CONF"
+ do_facet $SINGLEMDS "echo -1 > $IDENTITY_FLUSH"
+}
+run_test 1 "setuid/gid ============================="
+
+run_rmtacl_subtest() {
+ $SAVE_PWD/rmtacl/run $SAVE_PWD/rmtacl/$1.test
+ return $?
}
-sec_run_test 1 "setuid/gid ============================="
# remote_acl
# for remote client only
test_2 () {
[ "$CLIENT_TYPE" = "local" ] && \
- sec_skip "remote_acl for remote client only" && return
+ skip "remote_acl for remote client only" && return
[ -z "$(grep ^acl $MDC_LPROC/*-mdc-*/connect_flags)" ] && \
- sec_skip "must have acl enabled" && return
+ skip "must have acl enabled" && return
[ -z "$(which setfacl 2>/dev/null)" ] && \
- sec_skip "could not find setfacl" && return
- [ "$UID" != 0 ] && sec_skip "must run as root" && return
-
- rm -rf $DIR/d2
- mkdir $DIR/d2
- chmod 755 $DIR/d2
- echo xxx > $DIR/d2/f0
- chmod 644 $DIR/d2/f0
-
- $LFS getfacl $DIR/d2/f0 || sec_error
- $RUNAS -u $ID1 cat $DIR/d2/f0 || sec_error
- $RUNAS -u $ID1 touch $DIR/d2/f0 && sec_error
-
- $LFS setfacl -m u:$USER1:w $DIR/d2/f0 || sec_error
- $LFS getfacl $DIR/d2/f0 || sec_error
- echo "set user $USER1 write permission on file $DIR/d2/f0"
- $RUNAS -u $ID1 touch $DIR/d2/f0 || sec_error
- $RUNAS -u $ID1 cat $DIR/d2/f0 && sec_error
-
- rm -rf $DIR/d2
+ skip "could not find setfacl" && return
+ [ "$UID" != 0 ] && skip "must run as root" && return
+
+ sec_login root root
+ sec_login bin bin
+ sec_login daemon daemon
+ sec_login games users
+
+ SAVE_UMASK=`umask`
+ umask 0022
+ cd $DIR
+
+ if [ ! -z "$MDT" ]; then
+ do_facet $SINGLEMDS "echo '* 0 rmtacl' > $PERM_CONF"
+ do_facet $SINGLEMDS "echo -1 > $IDENTITY_FLUSH"
+ fi
+
+ if lfs rgetfacl $DIR; then
+ echo "performing cp ..."
+ run_rmtacl_subtest cp || error "cp"
+ else
+ echo "server doesn't permit current user 'lfs r{s,g}etfacl', skip cp test."
+ fi
+ echo "performing getfacl-noacl..."
+ run_rmtacl_subtest getfacl-noacl || error "getfacl-noacl"
+ echo "performing misc..."
+ run_rmtacl_subtest misc || error "misc"
+ echo "performing permissions..."
+ run_rmtacl_subtest permissions || error "permissions"
+ echo "performing setfacl..."
+ run_rmtacl_subtest setfacl || error "setfacl"
+
+ # inheritance test got from HP
+ echo "performing inheritance..."
+ cp $SAVE_PWD/rmtacl/make-tree .
+ chmod +x make-tree
+ run_rmtacl_subtest inheritance || error "inheritance"
+ rm -f make-tree
+
+ if [ ! -z "$MDT" ]; then
+ do_facet $SINGLEMDS "rm -f $PERM_CONF"
+ do_facet $SINGLEMDS "echo -1 > $IDENTITY_FLUSH"
+ fi
+
+ cd $SAVE_PWD
+ umask $SAVE_UMASK
}
-sec_run_test 2 "rmtacl ============================="
+run_test 2 "rmtacl ============================="
# rootsquash
-# for remote mdt only
+# root_squash will be redesigned in Lustre 1.7
test_3() {
- [ $GSS_SUP = 0 ] && sec_skip "without GSS support." && return
- [ -z "$MDT" ] && sec_skip "do not support do_facet operations." && return
- [ "$MDT_TYPE" = "local" ] && sec_skip "rootsquash for remote mdt only" && return
-
- do_facet $SINGLEMDS echo "-\*" > $NOSQUASH_NIDS
- do_facet $SINGLEMDS echo 0 > $ROOTSQUASH_UID
- do_facet $SINGLEMDS echo 0 > $ROOTSQUASH_GID
-
- rm -rf $DIR/d3
- mkdir $DIR/d3
- chown $USER1 $DIR/d3
- chmod 700 $DIR/d3
- do_facet $SINGLEMDS echo $ID1 > $ROOTSQUASH_UID
- echo "set rootsquash uid = $ID1"
- touch $DIR/f3_0 && sec_error
- touch $DIR/d3/f3_1 || sec_error
-
- do_facet $SINGLEMDS echo 0 > $ROOTSQUASH_UID
- echo "disable rootsquash"
- chown root $DIR/d3
- chgrp $USER2 $DIR/d3
- chmod 770 $DIR/d3
-
- do_facet $SINGLEMDS echo $ID1 > $ROOTSQUASH_UID
- echo "set rootsquash uid = $ID1"
- touch $DIR/d3/f3_2 && sec_error
- do_facet $SINGLEMDS echo $ID2 > $ROOTSQUASH_GID
- echo "set rootsquash gid = $ID2"
- touch $DIR/d3/f3_3 || sec_error
-
- do_facet $SINGLEMDS echo "+\*" > $NOSQUASH_NIDS
- echo "add host in rootsquash skip list"
- touch $DIR/f3_4 || sec_error
-
- do_facet $SINGLEMDS echo 0 > $ROOTSQUASH_UID
- do_facet $SINGLEMDS echo 0 > $ROOTSQUASH_GID
- do_facet $SINGLEMDS echo "-\*" > $NOSQUASH_NIDS
- rm -rf $DIR/d3
- rm -f $DIR/f3_?
+ skip "root_squash will be redesigned in Lustre 1.7" && return
}
-sec_run_test 3 "rootsquash ============================="
+run_test 3 "rootsquash ============================="
# bug 3285 - supplementary group should always succeed.
# NB: the supplementary groups are set for local client only,
rm -rf $DIR/d4
mkdir $DIR/d4
chmod 771 $DIR/d4
- chgrp $ID1 $DIR/d4
- $RUNAS -u $ID1 ls $DIR/d4 || sec_error "setgroups(1) failed"
+ chgrp $ID0 $DIR/d4
+ $RUNAS -u $ID0 ls $DIR/d4 || error "setgroups (1)"
if [ "$CLIENT_TYPE" != "remote" ]; then
if [ ! -z "$MDT" ]; then
- do_facet $SINGLEMDS echo "\* $ID2 setgrp" > $PERM_CONF
- do_facet $SINGLEMDS echo -1 > $IDENTITY_FLUSH
+ do_facet $SINGLEMDS "echo '* $ID1 setgrp' > $PERM_CONF"
+ do_facet $SINGLEMDS "echo -1 > $IDENTITY_FLUSH"
fi
- $RUNAS -u $ID2 -G1,2,$ID1 ls $DIR/d4 || sec_error "setgroups(2) failed"
+ $RUNAS -u $ID1 -G1,2,$ID0 ls $DIR/d4 || error "setgroups (2)"
if [ ! -z "$MDT" ]; then
- do_facet $SINGLEMDS rm -f $PERM_CONF
- do_facet $SINGLEMDS echo -1 > $IDENTITY_FLUSH
+ do_facet $SINGLEMDS "rm -f $PERM_CONF"
+ do_facet $SINGLEMDS "echo -1 > $IDENTITY_FLUSH"
fi
fi
- $RUNAS -u $ID2 -G1,2 ls $DIR/d4 && sec_error "setgroups(3) failed"
+ $RUNAS -u $ID1 -G1,2 ls $DIR/d4 && error "setgroups (3)"
rm -rf $DIR/d4
}
-sec_run_test 4 "set supplementary group ==============="
+run_test 4 "set supplementary group ==============="
mds_capability_timeout() {
[ $# -lt 1 ] && echo "Miss mds capability timeout value" && return 1
echo "Set mds capability timeout as $1 seconds"
- do_facet $SINGLEMDS echo $1 > $CAPA_TIMEOUT
+ do_facet $SINGLEMDS "echo $1 > $CAPA_TIMEOUT"
return 0
}
*) echo "Invalid mds capability switch value" && return 2;;
esac
- do_facet $SINGLEMDS echo $1 > $MDSCAPA
+ do_facet $SINGLEMDS "echo $1 > $MDSCAPA"
return 0
}
*) echo "Invalid oss capability switch value" && return 2;;
esac
- i=0;
- while [ $i -lt $OST_COUNT ]; do
- j=$i;
- i=`expr $i + 1`
- OST="`do_facet ost$i ls -l $OST_LPROC/ | grep OST | awk '{print $9}' | grep $j$`"
- do_facet ost$i echo $1 > $OST_LPROC/$OST/capa
+ for i in `seq $OSTCOUNT`; do
+ local j=`expr $i - 1`
+ local OST="`do_facet ost$i \"ls -l $OST_LPROC/\" | grep OST | awk '{print $9}' | grep $j$`"
+ do_facet ost$i "echo $1 > $OST_LPROC/$OST/capa"
done
return 0
}
test_5() {
local file=$DIR/f5
- [ -z "$MDT" ] && sec_skip "do not support do_facet operations." && return
+ [ -z "$MDT" ] && skip "do not support do_facet operations." && return
turn_capability_off
+ if [ $? != 0 ]; then
+ error "turn_capability_off"
+ return 1
+ fi
rm -f $file
# Disable proc variable
- mds_capability_switch 0 || return 1
- oss_capability_switch 1 || return 2
+ mds_capability_switch 0
+ if [ $? != 0 ]; then
+ error "mds_capability_switch 0"
+ return 2
+ fi
+ oss_capability_switch 1
+ if [ $? != 0 ]; then
+ error "oss_capability_switch 1"
+ return 3
+ fi
# proc variable disabled -- access to the objects in the filesystem
# is not allowed
"-- access to the objects in the filesystem is denied."
$WTL $file 30
if [ $? == 0 ]; then
- echo "Write worked well even though secrets not supplied."
- return 3
+ error "Write worked well even though secrets not supplied."
+ return 4
fi
- turn_capability_on || return 4
+ turn_capability_on
+ if [ $? != 0 ]; then
+ error "turn_capability_on"
+ return 4
+ fi
sleep 5
# proc variable enabled, secrets supplied -- write should work now
"-- write should work now)."
$WTL $file 30
if [ $? != 0 ]; then
- echo "Write failed even though secrets supplied."
+ error "Write failed even though secrets supplied."
return 5
fi
turn_capability_off
+ if [ $? != 0 ]; then
+ error "turn_capability_off"
+ return 7
+ fi
rm -f $file
}
-sec_run_test 5 "capa secrets ========================="
+run_test 5 "capa secrets ========================="
# Expiry: A test program is performing I/O on a file. It has credential
# with an expiry half a minute later. While the program is running the
test_6() {
local file=$DIR/f6
- [ -z "$MDT" ] && sec_skip "do not support do_facet operations." && return
+ [ -z "$MDT" ] && skip "do not support do_facet operations." && return
turn_capability_off
+ if [ $? != 0 ]; then
+ error "turn_capability_off"
+ return 1
+ fi
rm -f $file
- turn_capability_on 30 || return 1
+ turn_capability_on 30
+ if [ $? != 0 ]; then
+ error "turn_capability_on 30"
+ return 2
+ fi
# Token expiry
- $WTL $file 60 || return 2
+ $WTL $file 60
+ if [ $? != 0 ]; then
+ error "$WTL $file 60"
+ return 3
+ fi
# Reset MDS capability timeout
- mds_capability_timeout 30 || exit 3
+ mds_capability_timeout 30
+ if [ $? != 0 ]; then
+ error "mds_capability_timeout 30"
+ return 4
+ fi
$WTL $file 60 &
local PID=$!
sleep 5
# To disable automatic renew, only need turn capa off on MDS.
- mds_capability_switch 0 || return 4
+ mds_capability_switch 0
+ if [ $? != 0 ]; then
+ error "mds_capability_switch 0"
+ return 5
+ fi
echo "We expect I/O failure."
wait $PID
if [ $? == 0 ]; then
echo "no I/O failure got."
- return 5
+ return 6
fi
turn_capability_off
+ if [ $? != 0 ]; then
+ error "turn_capability_off"
+ return 7
+ fi
rm -f $file
}
-sec_run_test 6 "capa expiry ========================="
+run_test 6 "capa expiry ========================="
log "cleanup: ======================================================"
-unsetup() {
- if [ ! -z "$MDT" ]; then
- do_facet $SINGLEMDS echo $IDENTITY_UPCALL_BAK > $IDENTITY_UPCALL
- do_facet $SINGLEMDS echo -1 > $IDENTITY_FLUSH
- fi
+sec_unsetup() {
+ for num in `seq $MDSCOUNT`; do
+ if [ "${identity_old[$num]}" = 1 ]; then
+ switch_identity $num false || identity_old[$num]=$?
+ fi
+ done
+ $RUNAS -u $ID0 ls $DIR
$RUNAS -u $ID1 ls $DIR
- $RUNAS -u $ID2 ls $DIR
}
-unsetup
+sec_unsetup
sec_cleanup() {
- if [ "$S_MOUNTED" = "yes" ]; then
- cleanupall -f || sec_error "cleanup failed"
+ if [ "$I_MOUNTED" = "yes" ]; then
+ cleanupall -f || error "sec_cleanup"
fi
}
sec_cleanup
[ `$GETSTRIPE $DIR/d27/f01 | grep -A 10 obdidx | wc -l` -eq 4 ] ||
error "two-stripe file doesn't have two stripes"
pass
- log "== test_27d: write to two stripe file file f01 ================"
+ log "== test_27c: write to two stripe file file f01 ================"
dd if=/dev/zero of=$DIR/d27/f01 bs=4k count=4 || error "dd failed"
}
run_test 27c "create two stripe file f01 ======================="
}
run_test 66 "update inode blocks count on client ==============="
-test_67() {
- [ ! -f sanity-sec.sh ] && skip "missing subtest sanity-sec.sh" && return
- sh sanity-sec.sh
-}
-run_test 67 "security test ====================================="
-
LLOOP=
cleanup_68() {
trap 0
export ORIG_CSUM=""
set_checksums()
{
+ # Note: in sptlrpc modes which enable its own bulk checksum, the
+ # original crc32_le bulk checksum will be automatically disabled,
+ # and the OBD_FAIL_OSC_CHECKSUM_SEND/OBD_FAIL_OSC_CHECKSUM_RECEIVE
+ # will be checked by sptlrpc code against sptlrpc bulk checksum.
+ # In this case set_checksums() will not be no-op, because sptlrpc
+ # bulk checksum will be enabled all through the test.
+
[ "$ORIG_CSUM" ] || ORIG_CSUM=`cat $LPROC/osc/*/checksums | head -n1`
for f in $LPROC/osc/*/checksums; do
echo $1 >> $f
[ -z "$(which setfacl 2>/dev/null)" ] && skip "could not find setfacl" && return
$GSS && skip "could not run under gss" && return
+ declare -a identity_old
+
+ for num in `seq $MDSCOUNT`; do
+ switch_identity $num true || identity_old[$num]=$?
+ done
+
SAVE_UMASK=`umask`
umask 0022
cd $DIR
run_acl_subtest getfacl-noacl || error
echo "performing misc..."
run_acl_subtest misc || error
-# XXX add back permission test when we support supplementary groups.
-# echo "performing permissions..."
-# run_acl_subtest permissions || error
+ echo "performing permissions..."
+ run_acl_subtest permissions || error
echo "performing setfacl..."
run_acl_subtest setfacl || error
cd $SAVE_PWD
umask $SAVE_UMASK
+
+ for num in `seq $MDSCOUNT`; do
+ if [ "${identity_old[$num]}" = 1 ]; then
+ switch_identity $num false || identity_old[$num]=$?
+ fi
+ done
}
run_test 103 "acl test ========================================="
export GSS=false
export GSS_KRB5=false
export GSS_PIPEFS=false
+export IDENTITY_UPCALL=false
#export PDSH="pdsh -S -Rssh -w"
# eg, assert_env LUSTRE MDSNODES OSTNODES CLIENTS
export PATH=:$PATH:$LUSTRE/utils:$LUSTRE/utils/gss:$LUSTRE/tests
export LCTL=${LCTL:-"$LUSTRE/utils/lctl"}
- export LFS=${LFS:-"$LUSTRE/utils/lfs"}
[ ! -f "$LCTL" ] && export LCTL=$(which lctl)
export LFS=${LFS:-"$LUSTRE/utils/lfs"}
[ ! -f "$LFS" ] && export LFS=$(which lfs)
+ export L_GETIDENTITY=${L_GETIDENTITY:-"$LUSTRE/utils/l_getidentity"}
+ if [ ! -f "$L_GETIDENTITY" ]; then
+ if `which l_getidentity > /dev/null 2>&1`; then
+ export L_GETIDENTITY=$(which l_getidentity)
+ else
+ export L_GETIDENTITY=NONE
+ fi
+ fi
export MKFS=${MKFS:-"$LUSTRE/utils/mkfs.lustre"}
[ ! -f "$MKFS" ] && export MKFS=$(which mkfs.lustre)
export TUNEFS=${TUNEFS:-"$LUSTRE/utils/tunefs.lustre"}
export NAME=${NAME:-local}
export LPROC=/proc/fs/lustre
export LGSSD=${LGSSD:-"$LUSTRE/utils/gss/lgssd"}
+ [ "$GSS_PIPEFS" = "true" ] && [ ! -f "$LGSSD" ] && \
+ export LGSSD=$(which lgssd)
export LSVCGSSD=${LSVCGSSD:-"$LUSTRE/utils/gss/lsvcgssd"}
+ [ ! -f "$LSVCGSSD" ] && export LSVCGSSD=$(which lsvcgssd)
export KRB5DIR=${KRB5DIR:-"/usr/kerberos"}
export DIR2
;;
esac
+ case "x$ID" in
+ xtrue)
+ IDENTITY_UPCALL=true
+ ;;
+ xfalse)
+ IDENTITY_UPCALL=false
+ ;;
+ esac
+
# Paths on remote nodes, if different
export RLUSTRE=${RLUSTRE:-$LUSTRE}
export RPWD=${RPWD:-$PWD}
send_sigint client lgssd
}
-init_krb5_env() {
- if [ ! -z $SEC ]; then
- MDS_MOUNT_OPTS=$MDS_MOUNT_OPTS,sec=$SEC
- OST_MOUNT_OPTS=$OST_MOUNT_OPTS,sec=$SEC
- fi
-
+init_gss() {
if $GSS; then
start_gss_daemons
fi
}
-cleanup_krb5_env() {
+cleanup_gss() {
if $GSS; then
stop_gss_daemons
# maybe cleanup credential cache?
cleanupall() {
stopall $*
unload_modules
- cleanup_krb5_env
+ cleanup_gss
}
mdsmkfsopts()
formatall() {
[ "$FSTYPE" ] && FSTYPE_OPT="--backfstype $FSTYPE"
+ if [ ! -z $SEC ]; then
+ MDS_MKFS_OPTS="$MDS_MKFS_OPTS --param srpc.flavor.default=$SEC"
+ OST_MKFS_OPTS="$OST_MKFS_OPTS --param srpc.flavor.default=$SEC"
+ fi
+
stopall
# We need ldiskfs here, may as well load them all
load_modules
grep " $1 " /proc/mounts || zconf_mount `hostname` $*
}
+# return value:
+# 0: success, the old identity set already.
+# 1: success, the old identity does not set.
+# 2: fail.
+switch_identity() {
+ local num=$1
+ local switch=$2
+ local j=`expr $num - 1`
+ local MDT="`do_facet mds$num ls -l $LPROC/mdt/ 2>/dev/null | grep MDT | awk '{print $9}' | grep $j$`"
+
+ if [ -z "$MDT" ]; then
+ return 2
+ fi
+
+ local old="`do_facet mds$num cat $LPROC/mdt/$MDT/identity_upcall`"
+
+ if [ $switch ]; then
+ do_facet mds$num "echo \"$L_GETIDENTITY\" > $LPROC/mdt/$MDT/identity_upcall"
+ else
+ do_facet mds$num "echo \"NONE\" > $LPROC/mdt/$MDT/identity_upcall"
+ fi
+
+ do_facet mds$num "echo \"-1\" > $LPROC/mdt/$MDT/identity_flush"
+
+ if [ $old = "NONE" ]; then
+ return 1
+ else
+ return 0
+ fi
+}
+
setupall() {
load_modules
- init_krb5_env
+ init_gss
if [ -z "$CLIENTONLY" ]; then
echo "Setup mdts, osts"
for num in `seq $MDSCOUNT`; do
echo $REFORMAT | grep -q "reformat" \
|| do_facet mds$num "$TUNEFS --writeconf $DEVNAME"
start mds$num $DEVNAME $MDS_MOUNT_OPTS
+ switch_identity $num $IDENTITY_UPCALL
done
for num in `seq $OSTCOUNT`; do
DEVNAME=$(ostdevname $num)
# mount only finds helpers in /sbin
rootsbin_PROGRAMS = mount.lustre
sbin_PROGRAMS = mkfs.lustre tunefs.lustre lctl \
- l_getidentity l_facl llverfs llverdev \
+ l_getidentity llverfs llverdev \
llog_reader lr_reader
if LIBPTHREAD
sbin_PROGRAMS += loadgen
l_getidentity_LDADD := $(LIBPTLCTL)
l_getidentity_DEPENDENCIES := $(LIBPTLCTL)
-l_facl_SOURCES = l_facl.c
-l_facl_LDADD := liblustreapi.a
-l_facl_DEPENDENCIES := liblustreapi.a
-
EXTRA_DIST = $(sbin_scripts) $(bin_scripts)
# NOTE: this should only be run on i386.
*/
struct lgss_nego_data {
uint32_t lnd_established:1;
+
+ int lnd_secid;
uint32_t lnd_uid;
uint32_t lnd_lsvc;
char *lnd_uuid;
struct keyring_upcall_param {
uint32_t kup_ver;
+ uint32_t kup_secid;
uint32_t kup_uid;
+ uint32_t kup_fsuid;
uint32_t kup_gid;
+ uint32_t kup_fsgid;
uint32_t kup_svc;
uint64_t kup_nid;
char kup_tgt[64];
}
param.version = GSSD_INTERFACE_VERSION;
+ param.secid = lnd->lnd_secid;
param.uuid = lnd->lnd_uuid;
param.lustre_svc = lnd->lnd_lsvc;
param.uid = lnd->lnd_uid;
/*
* if return error, the lnd_rpc_err or lnd_gss_err is set.
*/
-int lgssc_negotiation(struct lgss_nego_data *lnd)
+static int lgssc_negotiation(struct lgss_nego_data *lnd)
{
struct lgss_init_res gr;
gss_buffer_desc *recv_tokenp, send_token;
/*
* if return error, the lnd_rpc_err or lnd_gss_err is set.
*/
-int lgssc_init_nego_data(struct lgss_nego_data *lnd,
- struct keyring_upcall_param *kup,
- lgss_mech_t mech)
+static int lgssc_init_nego_data(struct lgss_nego_data *lnd,
+ struct keyring_upcall_param *kup,
+ lgss_mech_t mech)
{
gss_buffer_desc sname;
OM_uint32 maj_stat, min_stat;
memset(lnd, 0, sizeof(*lnd));
+ lnd->lnd_secid = kup->kup_secid;
lnd->lnd_uid = kup->kup_uid;
lnd->lnd_lsvc = kup->kup_svc;
lnd->lnd_uuid = kup->kup_tgt;
}
/*
- * note we can't assume authority in child process
+ * note we inherited assumed authority from parent process
*/
-int lgssc_kr_negotiate(key_serial_t keyid, struct lgss_cred *cred,
- struct keyring_upcall_param *kup)
+static int lgssc_kr_negotiate(key_serial_t keyid, struct lgss_cred *cred,
+ struct keyring_upcall_param *kup)
{
struct lgss_nego_data lnd;
gss_buffer_desc token = GSS_C_EMPTY_BUFFER;
int rc = -1;
logmsg(LL_TRACE, "child start on behalf of key %08x: "
- "cred %p, uid %u, svc %u, nid %Lx\n", keyid, cred,
- cred->lc_uid, cred->lc_tgt_svc, cred->lc_tgt_nid);
-
- if (kup->kup_gid != 0 && setregid(kup->kup_gid, kup->kup_gid)) {
- logmsg(LL_WARN, "key %08x, failed set gids to %u: %s\n",
- keyid, kup->kup_gid, strerror(errno));
- }
-
- if (kup->kup_uid != 0 && setreuid(kup->kup_uid, kup->kup_uid)) {
- logmsg(LL_WARN, "key %08x, failed set uids to %u: %s\n",
- keyid, kup->kup_uid, strerror(errno));
- }
-
- /*
- * link to session keyring, allow the key to be found.
- */
- if (keyctl_link(keyid, KEY_SPEC_SESSION_KEYRING)) {
- logmsg(LL_ERR, "key %08x, failed to link to session "
- "keyring: %s\n", keyid, strerror(errno));
- error_kernel_key(keyid, -EACCES, 0);
- goto out_cred;
- }
+ "cred %p, uid %u, svc %u, nid %Lx, uids: %u:%u/%u:%u\n",
+ keyid, cred, cred->lc_uid, cred->lc_tgt_svc, cred->lc_tgt_nid,
+ kup->kup_uid, kup->kup_gid, kup->kup_fsuid, kup->kup_fsgid);
if (lgss_get_service_str(&g_service, kup->kup_svc, kup->kup_nid)) {
logmsg(LL_ERR, "key %08x: failed to construct service "
"string\n", keyid);
error_kernel_key(keyid, -EACCES, 0);
- goto out_unlink;
+ goto out_cred;
}
if (lgss_using_cred(cred)) {
logmsg(LL_ERR, "key %08x: can't using cred\n", keyid);
error_kernel_key(keyid, -EACCES, 0);
- goto out_unlink;
+ goto out_cred;
}
if (lgssc_init_nego_data(&lnd, kup, cred->lc_mech->lmt_mech_n)) {
logmsg(LL_ERR, "key %08x: failed to initialize "
"negotiation data\n", keyid);
error_kernel_key(keyid, lnd.lnd_rpc_err, lnd.lnd_gss_err);
- goto out_unlink;
+ goto out_cred;
}
rc = lgssc_negotiation(&lnd);
lgssc_fini_nego_data(&lnd);
-out_unlink:
- if (keyctl_unlink(keyid, KEY_SPEC_SESSION_KEYRING)) {
- logmsg(LL_WARN, "failed to unlink key %08x: %s\n",
- keyid, strerror(errno));
- }
-
out_cred:
lgss_release_cred(cred);
return rc;
/*
* call out info format: s[:s]...
- * [0]: mech_name (string)
- * [1]: flags (chars) FMT: r-root; m-mds
- * [2]: lustre_svc (uint)
- * [3]: target_nid (uint64)
- * [4]: target_uuid (string)
+ * [0]: secid (uint)
+ * [1]: mech_name (string)
+ * [2]: uid (uint)
+ * [3]: gid (uint)
+ * [4]: flags (chars) FMT: r-root; m-mds
+ * [5]: lustre_svc (uint)
+ * [6]: target_nid (uint64)
+ * [7]: target_uuid (string)
*/
-static
-int parse_callout_info(const char *coinfo,
- struct keyring_upcall_param *uparam)
+static int parse_callout_info(const char *coinfo,
+ struct keyring_upcall_param *uparam)
{
- char buf[1024];
- char *string = buf;
- int length, i;
- char *data[5];
- char *pos;
+ const int nargs = 8;
+ char buf[1024];
+ char *string = buf;
+ int length, i;
+ char *data[nargs];
+ char *pos;
length = strlen(coinfo) + 1;
if (length > 1024) {
}
memcpy(buf, coinfo, length);
- for (i = 0; i < 4; i++) {
+ for (i = 0; i < nargs - 1; i++) {
pos = strchr(string, ':');
if (pos == NULL) {
logmsg(LL_ERR, "short of components\n");
}
data[i] = string;
- logmsg(LL_TRACE, "components: %s,%s,%s,%s,%s\n",
- data[0], data[1], data[2], data[3], data[4], data[5]);
+ logmsg(LL_TRACE, "components: %s,%s,%s,%s,%s,%s,%s,%s\n",
+ data[0], data[1], data[2], data[3], data[4], data[5],
+ data[6], data[7]);
- strncpy(uparam->kup_mech, data[0], sizeof(uparam->kup_mech));
- if (strchr(data[1], 'r'))
+ uparam->kup_secid = strtol(data[0], NULL, 0);
+ strncpy(uparam->kup_mech, data[1], sizeof(uparam->kup_mech));
+ uparam->kup_uid = strtol(data[2], NULL, 0);
+ uparam->kup_gid = strtol(data[3], NULL, 0);
+ if (strchr(data[4], 'r'))
uparam->kup_is_root = 1;
- if (strchr(data[1], 'm'))
+ if (strchr(data[4], 'm'))
uparam->kup_is_mds = 1;
- uparam->kup_svc = strtol(data[2], NULL, 0);
- uparam->kup_nid = strtoll(data[3], NULL, 0);
- strncpy(uparam->kup_tgt, data[4], sizeof(uparam->kup_tgt));
-
- logmsg(LL_DEBUG, "parse call out info: mech %s, is_root %d, "
- "is_mds %d, svc %d, nid 0x%Lx, tgt %s\n",
- uparam->kup_mech, uparam->kup_is_root, uparam->kup_is_mds,
- uparam->kup_svc, uparam->kup_nid, uparam->kup_tgt);
+ uparam->kup_svc = strtol(data[5], NULL, 0);
+ uparam->kup_nid = strtoll(data[6], NULL, 0);
+ strncpy(uparam->kup_tgt, data[7], sizeof(uparam->kup_tgt));
+
+ logmsg(LL_DEBUG, "parse call out info: secid %d, mech %s, ugid %u:%u "
+ "is_root %d, is_mds %d, svc %d, nid 0x%Lx, tgt %s\n",
+ uparam->kup_secid, uparam->kup_mech,
+ uparam->kup_uid, uparam->kup_gid,
+ uparam->kup_is_root, uparam->kup_is_mds, uparam->kup_svc,
+ uparam->kup_nid, uparam->kup_tgt);
return 0;
}
return 1;
}
- logmsg(LL_INFO, "key %s, desc %s, uid %s, sring %s, coinfo %s\n",
- argv[2], argv[4], argv[6], argv[10], argv[5]);
+ logmsg(LL_INFO, "key %s, desc %s, ugid %s:%s, sring %s, coinfo %s\n",
+ argv[2], argv[4], argv[6], argv[7], argv[10], argv[5]);
memset(&uparam, 0, sizeof(uparam));
return 1;
}
- if (sscanf(argv[6], "%d", &uparam.kup_uid) != 1) {
+ if (sscanf(argv[6], "%d", &uparam.kup_fsuid) != 1) {
logmsg(LL_ERR, "can't extract UID: %s\n", argv[6]);
return 1;
}
+ if (sscanf(argv[7], "%d", &uparam.kup_fsgid) != 1) {
+ logmsg(LL_ERR, "can't extract GID: %s\n", argv[7]);
+ return 1;
+ }
+
if (sscanf(argv[10], "%d", &sring) != 1) {
logmsg(LL_ERR, "can't extract session keyring: %s\n", argv[10]);
return 1;
return 1;
}
- /*
- * pre initialize the key
+ /* pre initialize the key. note the keyring linked to is actually of the
+ * original requesting process, not _this_ upcall process. if it's for
+ * root user, don't link to any keyrings because we want fully control
+ * on it, and share it among all root sessions; otherswise link to
+ * session keyring.
*/
- inst_keyring = (cred->lc_fl_root || cred->lc_fl_mds) ?
- 0 : KEY_SPEC_SESSION_KEYRING;
+ if (cred->lc_fl_root || cred->lc_fl_mds)
+ inst_keyring = 0;
+ else
+ inst_keyring = KEY_SPEC_SESSION_KEYRING;
if (keyctl_instantiate(keyid, NULL, 0, inst_keyring)) {
logmsg(LL_ERR, "instantiate key %08x: %s\n",
}
static
-int svc_princ_is_local_host(krb5_context ctx,
- krb5_principal princ,
- loglevel_t loglevel)
+int svc_princ_verify_host(krb5_context ctx,
+ krb5_principal princ,
+ loglevel_t loglevel)
{
struct utsname utsbuf;
struct hostent *host;
return -1;
}
- /* if it's mds service principal, check hostname */
+ /* if it's mds service principal, or lustre_root principal
+ * with host part, verify the hostname.
+ * note we allow lustre_root without host part */
if (lgss_krb5_strcmp(krb5_princ_name(ctx, princ),
LGSS_SVC_MDS_STR) == 0) {
- if (svc_princ_is_local_host(ctx, princ, LL_WARN)) {
- logmsg(LL_WARN, "mds service principal not belongs "
+ if (svc_princ_verify_host(ctx, princ, LL_WARN)) {
+ logmsg(LL_WARN, "mds service principal doesn't belong "
"to this node\n");
return -1;
}
} else if (lgss_krb5_strcmp(krb5_princ_name(ctx, princ),
- LGSS_USR_ROOT_STR)) {
- /* do nothing */
+ LGSS_USR_ROOT_STR) == 0) {
+ if (krb5_princ_component(ctx, princ, 1) != NULL &&
+ svc_princ_verify_host(ctx, princ, LL_WARN)) {
+ logmsg(LL_WARN, "lustre_root principal doesn't belong "
+ "to this node\n");
+ return -1;
+ }
} else {
logmsg(LL_WARN, "unexpected krb5 cc principal name %.*s\n",
krb5_princ_name(ctx, princ)->length,
krb5_keytab kt;
krb5_keytab_entry kte;
krb5_kt_cursor cursor;
- krb5_principal princ = NULL;
+ krb5_principal princ = NULL, princ2;
krb5_error_code code;
+ int general_root = 0;
int rc = -1;
/* prepare parsing the keytab file */
if (!princ_is_local_realm(ctx, kte.principal))
continue;
- /* lustre_root@realm */
+ /* lustre_root[/host]@realm */
if (lgss_krb5_strcmp(krb5_princ_name(ctx, kte.principal),
LGSS_USR_ROOT_STR) == 0) {
- if (princ != NULL) {
- logmsg(LL_WARN, "already picked one? "
- "how could it possible???\n");
- continue;
+ int tmp_general_root = 0;
+
+ if (krb5_princ_component(ctx, kte.principal,1) == NULL){
+ if (princ != NULL) {
+ logmsg(LL_TRACE, "lustre_root: "
+ "already picked one, skip\n");
+ continue;
+ }
+
+ tmp_general_root = 1;
+ } else {
+ if (svc_princ_verify_host(ctx, kte.principal,
+ LL_TRACE)) {
+ logmsg(LL_TRACE, "lustre_root: "
+ "doesn't belong to this node\n");
+ continue;
+ }
+
+ if (princ != NULL && !general_root) {
+ logmsg(LL_TRACE, "lustre_root: already "
+ "have a host-specific one, "
+ "skip\n");
+ continue;
+ }
}
- code = krb5_copy_principal(ctx, kte.principal, &princ);
- if (code)
+ code = krb5_copy_principal(ctx, kte.principal, &princ2);
+ if (code) {
logmsg(LL_ERR, "copy lustre_root princ: %s\n",
krb5_err_msg(code));
+ continue;
+ }
+
+ if (princ != NULL) {
+ logmsg(LL_TRACE, "release a lustre_root one\n");
+ krb5_free_principal(ctx, princ);
+ }
+ princ = princ2;
+ general_root = tmp_general_root;
continue;
}
/* lustre_mds/host@realm */
if (lgss_krb5_strcmp(krb5_princ_name(ctx, kte.principal),
LGSS_SVC_MDS_STR) == 0) {
- krb5_principal princ2;
-
- if (svc_princ_is_local_host(ctx, kte.principal,
- LL_TRACE)) {
+ if (svc_princ_verify_host(ctx, kte.principal,
+ LL_TRACE)) {
logmsg(LL_TRACE, "mds service principal: "
- "not belongs to this node\n");
+ "doesn't belong to this node\n");
continue;
}
#define MAX_LINE_LEN 256
struct user_map_item {
- char *principal; /* NULL means match all, will cause multi->single mapped, FORBID */
+ char *principal; /* NULL means match all */
lnet_nid_t nid;
uid_t uid;
};
{
if (mapping.items) {
for (; mapping.nitems > 0; mapping.nitems--)
- free(mapping.items[mapping.nitems - 1].principal);
+ if (mapping.items[mapping.nitems-1].principal)
+ free(mapping.items[mapping.nitems-1].principal);
+
free(mapping.items);
mapping.items = NULL;
}
}
if (mapping.items) {
- memcpy(new, mapping.items, mapping.nitems * sizeof(struct user_map_item));
+ memcpy(new, mapping.items,
+ mapping.nitems * sizeof(struct user_map_item));
free(mapping.items);
}
mapping.items = new;
}
if (!strcmp(princ, "*")) {
- printerr(0, "NOT permit \"*\" princ, it will cause multi->single mapped\n");
- continue;
+ name = NULL;
} else {
name = strdup(princ);
if (!name) {
nid = libcfs_str2nid(nid_str);
if (nid == LNET_NID_ANY) {
printerr(0, "fail to parse nid %s\n", nid_str);
+ if (name)
free(name);
continue;
}
dest_uid = parse_uid(dest);
if (dest_uid == -1) {
printerr(0, "no valid user: %s\n", dest);
+ if (name)
free(name);
continue;
}
if (grow_mapping(mapping.nitems + 1)) {
printerr(0, "fail to grow mapping to %d\n",
mapping.nitems + 1);
+ if (name)
free(name);
fclose(f);
return -1;
if (entry->nid != LNET_NID_ANY && entry->nid != nid)
continue;
- if (!strcasecmp(entry->principal, princ)) {
+ if (!entry->principal || !strcasecmp(entry->principal, princ)) {
printerr(1, "found mapping: %s ==> %d\n",
princ, entry->uid);
*uid = entry->uid;
struct lgssd_ioctl_param {
int version; /* in */
+ int secid; /* in */
char *uuid; /* in */
int lustre_svc; /* in */
uid_t uid; /* in */
-diff -Nrup nfs-utils-1.0.11/configure.in nfs-utils-1.0.11.lustre/configure.in
---- nfs-utils-1.0.11/configure.in 2007-02-21 21:50:03.000000000 -0700
-+++ nfs-utils-1.0.11.lustre/configure.in 2007-06-29 12:29:20.000000000 -0600
+diff -Nrup nfs-utils-1.0.11.lustre/configure.in nfs-utils-1.0.11/configure.in
+--- nfs-utils-1.0.11.lustre/configure.in 2007-02-21 21:50:03.000000000 -0700
++++ nfs-utils-1.0.11/configure.in 2008-01-02 18:10:29.000000000 -0700
@@ -18,61 +18,14 @@ AC_ARG_WITH(release,
RELEASE=$withval,
RELEASE=1)
+ utils/gssd/Makefile])
AC_OUTPUT
-diff -Nrup nfs-utils-1.0.11/Makefile.am nfs-utils-1.0.11.lustre/Makefile.am
---- nfs-utils-1.0.11/Makefile.am 2007-02-21 21:50:03.000000000 -0700
-+++ nfs-utils-1.0.11.lustre/Makefile.am 2007-06-29 12:29:20.000000000 -0600
+diff -Nrup nfs-utils-1.0.11.lustre/Makefile.am nfs-utils-1.0.11/Makefile.am
+--- nfs-utils-1.0.11.lustre/Makefile.am 2007-02-21 21:50:03.000000000 -0700
++++ nfs-utils-1.0.11/Makefile.am 2008-01-02 18:10:29.000000000 -0700
@@ -1,6 +1,6 @@
## Process this file with automake to produce Makefile.in
MAINTAINERCLEANFILES = Makefile.in
-diff -Nrup nfs-utils-1.0.11/utils/gssd/cacheio.c nfs-utils-1.0.11.lustre/utils/gssd/cacheio.c
---- nfs-utils-1.0.11/utils/gssd/cacheio.c 2007-02-21 21:50:03.000000000 -0700
-+++ nfs-utils-1.0.11.lustre/utils/gssd/cacheio.c 2007-06-29 12:32:27.000000000 -0600
+diff -Nrup nfs-utils-1.0.11.lustre/utils/gssd/cacheio.c nfs-utils-1.0.11/utils/gssd/cacheio.c
+--- nfs-utils-1.0.11.lustre/utils/gssd/cacheio.c 2007-02-21 21:50:03.000000000 -0700
++++ nfs-utils-1.0.11/utils/gssd/cacheio.c 2008-01-02 18:11:38.000000000 -0700
@@ -240,7 +240,8 @@ int qword_get(char **bpp, char *dest, in
return -1;
while (*bp == ' ') bp++;
return len;
}
-diff -Nrup nfs-utils-1.0.11/utils/gssd/context.c nfs-utils-1.0.11.lustre/utils/gssd/context.c
---- nfs-utils-1.0.11/utils/gssd/context.c 2007-02-21 21:50:03.000000000 -0700
-+++ nfs-utils-1.0.11.lustre/utils/gssd/context.c 2007-06-29 12:32:28.000000000 -0600
+diff -Nrup nfs-utils-1.0.11.lustre/utils/gssd/context.c nfs-utils-1.0.11/utils/gssd/context.c
+--- nfs-utils-1.0.11.lustre/utils/gssd/context.c 2007-02-21 21:50:03.000000000 -0700
++++ nfs-utils-1.0.11/utils/gssd/context.c 2008-01-02 18:11:38.000000000 -0700
@@ -33,11 +33,14 @@
#include <syslog.h>
#include <string.h>
#include "context.h"
int
-diff -Nrup nfs-utils-1.0.11/utils/gssd/context.h nfs-utils-1.0.11.lustre/utils/gssd/context.h
---- nfs-utils-1.0.11/utils/gssd/context.h 2007-06-29 12:28:01.000000000 -0600
-+++ nfs-utils-1.0.11.lustre/utils/gssd/context.h 2007-06-29 12:32:29.000000000 -0600
+diff -Nrup nfs-utils-1.0.11.lustre/utils/gssd/context.h nfs-utils-1.0.11/utils/gssd/context.h
+--- nfs-utils-1.0.11.lustre/utils/gssd/context.h 2008-01-02 17:22:48.000000000 -0700
++++ nfs-utils-1.0.11/utils/gssd/context.h 2008-01-02 18:11:38.000000000 -0700
@@ -31,8 +31,6 @@
#ifndef _CONTEXT_H_
#define _CONTEXT_H_
/* Hopefully big enough to hold any serialized context */
#define MAX_CTX_LEN 4096
-diff -Nrup nfs-utils-1.0.11/utils/gssd/context_heimdal.c nfs-utils-1.0.11.lustre/utils/gssd/context_heimdal.c
---- nfs-utils-1.0.11/utils/gssd/context_heimdal.c 2007-02-21 21:50:03.000000000 -0700
-+++ nfs-utils-1.0.11.lustre/utils/gssd/context_heimdal.c 2007-06-29 12:32:29.000000000 -0600
+diff -Nrup nfs-utils-1.0.11.lustre/utils/gssd/context_heimdal.c nfs-utils-1.0.11/utils/gssd/context_heimdal.c
+--- nfs-utils-1.0.11.lustre/utils/gssd/context_heimdal.c 2007-02-21 21:50:03.000000000 -0700
++++ nfs-utils-1.0.11/utils/gssd/context_heimdal.c 2008-01-02 18:11:38.000000000 -0700
@@ -43,8 +43,13 @@
#ifdef HAVE_COM_ERR_H
#include <com_err.h>
#include "write_bytes.h"
int write_heimdal_keyblock(char **p, char *end, krb5_keyblock *key)
-diff -Nrup nfs-utils-1.0.11/utils/gssd/context_lucid.c nfs-utils-1.0.11.lustre/utils/gssd/context_lucid.c
---- nfs-utils-1.0.11/utils/gssd/context_lucid.c 2007-06-29 12:28:01.000000000 -0600
-+++ nfs-utils-1.0.11.lustre/utils/gssd/context_lucid.c 2007-06-29 12:32:30.000000000 -0600
+diff -Nrup nfs-utils-1.0.11.lustre/utils/gssd/context_lucid.c nfs-utils-1.0.11/utils/gssd/context_lucid.c
+--- nfs-utils-1.0.11.lustre/utils/gssd/context_lucid.c 2008-01-02 17:22:48.000000000 -0700
++++ nfs-utils-1.0.11/utils/gssd/context_lucid.c 2008-01-02 18:11:38.000000000 -0700
@@ -41,11 +41,7 @@
#include <syslog.h>
#include <string.h>
maj_stat = gss_export_lucid_sec_context(&min_stat, &ctx,
1, &return_ctx);
if (maj_stat != GSS_S_COMPLETE) {
-diff -Nrup nfs-utils-1.0.11/utils/gssd/context_mit.c nfs-utils-1.0.11.lustre/utils/gssd/context_mit.c
---- nfs-utils-1.0.11/utils/gssd/context_mit.c 2007-06-29 12:28:01.000000000 -0600
-+++ nfs-utils-1.0.11.lustre/utils/gssd/context_mit.c 2007-06-29 12:32:30.000000000 -0600
-@@ -39,10 +39,14 @@
+diff -Nrup nfs-utils-1.0.11.lustre/utils/gssd/context_mit.c nfs-utils-1.0.11/utils/gssd/context_mit.c
+--- nfs-utils-1.0.11.lustre/utils/gssd/context_mit.c 2008-01-02 17:22:48.000000000 -0700
++++ nfs-utils-1.0.11/utils/gssd/context_mit.c 2008-01-02 18:11:38.000000000 -0700
+@@ -39,10 +39,15 @@
#include <errno.h>
#include <gssapi/gssapi.h>
#include <rpc/rpc.h>
+
+#ifdef _NEW_BUILD_
+# include "lgss_utils.h"
++# include "write_bytes.h"
+#else
+# include "gss_util.h"
+# include "gss_oids.h"
#include "context.h"
#include <krb5.h>
-@@ -333,12 +337,7 @@ serialize_krb5_ctx(gss_ctx_id_t ctx, gss
+@@ -333,12 +338,7 @@ serialize_krb5_ctx(gss_ctx_id_t ctx, gss
* keydata-2; ( Ki (Kseq for DES3) )
* keydata-3; ( Kc (derived checksum key) )
*/
if (WRITE_BYTES(&p, end, kctx->endtime)) goto out_err;
/* Only applicable flag for this is initiator */
-diff -Nrup nfs-utils-1.0.11/utils/gssd/context_spkm3.c nfs-utils-1.0.11.lustre/utils/gssd/context_spkm3.c
---- nfs-utils-1.0.11/utils/gssd/context_spkm3.c 2007-02-21 21:50:03.000000000 -0700
-+++ nfs-utils-1.0.11.lustre/utils/gssd/context_spkm3.c 2007-06-29 12:32:31.000000000 -0600
+diff -Nrup nfs-utils-1.0.11.lustre/utils/gssd/context_spkm3.c nfs-utils-1.0.11/utils/gssd/context_spkm3.c
+--- nfs-utils-1.0.11.lustre/utils/gssd/context_spkm3.c 2007-02-21 21:50:03.000000000 -0700
++++ nfs-utils-1.0.11/utils/gssd/context_spkm3.c 2008-01-02 18:11:38.000000000 -0700
@@ -33,8 +33,6 @@
#include <syslog.h>
#include <string.h>
#include "gss_util.h"
#include "gss_oids.h"
#include "err_util.h"
-diff -Nrup nfs-utils-1.0.11/utils/gssd/err_util.c nfs-utils-1.0.11.lustre/utils/gssd/err_util.c
---- nfs-utils-1.0.11/utils/gssd/err_util.c 2007-02-21 21:50:03.000000000 -0700
-+++ nfs-utils-1.0.11.lustre/utils/gssd/err_util.c 2007-06-29 12:32:31.000000000 -0600
+diff -Nrup nfs-utils-1.0.11.lustre/utils/gssd/err_util.c nfs-utils-1.0.11/utils/gssd/err_util.c
+--- nfs-utils-1.0.11.lustre/utils/gssd/err_util.c 2007-02-21 21:50:03.000000000 -0700
++++ nfs-utils-1.0.11/utils/gssd/err_util.c 2008-01-02 18:11:38.000000000 -0700
@@ -32,6 +32,8 @@
#include <stdarg.h>
#include <syslog.h>
+ }
+}
+
-diff -Nrup nfs-utils-1.0.11/utils/gssd/err_util.h nfs-utils-1.0.11.lustre/utils/gssd/err_util.h
---- nfs-utils-1.0.11/utils/gssd/err_util.h 2007-02-21 21:50:03.000000000 -0700
-+++ nfs-utils-1.0.11.lustre/utils/gssd/err_util.h 2007-06-29 12:32:32.000000000 -0600
+diff -Nrup nfs-utils-1.0.11.lustre/utils/gssd/err_util.h nfs-utils-1.0.11/utils/gssd/err_util.h
+--- nfs-utils-1.0.11.lustre/utils/gssd/err_util.h 2007-02-21 21:50:03.000000000 -0700
++++ nfs-utils-1.0.11/utils/gssd/err_util.h 2008-01-02 18:11:38.000000000 -0700
@@ -33,5 +33,6 @@
void initerr(char *progname, int verbosity, int fg);
+void print_hexl(int pri, unsigned char *cp, int length);
#endif /* _ERR_UTIL_H_ */
-diff -Nrup nfs-utils-1.0.11/utils/gssd/gss_clnt_send_err.c nfs-utils-1.0.11.lustre/utils/gssd/gss_clnt_send_err.c
---- nfs-utils-1.0.11/utils/gssd/gss_clnt_send_err.c 2007-02-21 21:50:03.000000000 -0700
-+++ nfs-utils-1.0.11.lustre/utils/gssd/gss_clnt_send_err.c 2007-06-29 12:29:20.000000000 -0600
+diff -Nrup nfs-utils-1.0.11.lustre/utils/gssd/gss_clnt_send_err.c nfs-utils-1.0.11/utils/gssd/gss_clnt_send_err.c
+--- nfs-utils-1.0.11.lustre/utils/gssd/gss_clnt_send_err.c 2007-02-21 21:50:03.000000000 -0700
++++ nfs-utils-1.0.11/utils/gssd/gss_clnt_send_err.c 2008-01-02 18:10:29.000000000 -0700
@@ -47,6 +47,7 @@
#include "gssd.h"
#include "write_bytes.h"
exit(0);
}
+#endif
-diff -Nrup nfs-utils-1.0.11/utils/gssd/gssd.c nfs-utils-1.0.11.lustre/utils/gssd/gssd.c
---- nfs-utils-1.0.11/utils/gssd/gssd.c 2007-06-29 12:28:01.000000000 -0600
-+++ nfs-utils-1.0.11.lustre/utils/gssd/gssd.c 2007-06-29 12:32:36.000000000 -0600
+diff -Nrup nfs-utils-1.0.11.lustre/utils/gssd/gssd.c nfs-utils-1.0.11/utils/gssd/gssd.c
+--- nfs-utils-1.0.11.lustre/utils/gssd/gssd.c 2008-01-02 17:22:48.000000000 -0700
++++ nfs-utils-1.0.11/utils/gssd/gssd.c 2008-01-02 18:11:38.000000000 -0700
@@ -38,9 +38,12 @@
#include "config.h"
+ printerr(0, "lgssd exiting\n");
+ return 0;
}
-diff -Nrup nfs-utils-1.0.11/utils/gssd/gssd.h nfs-utils-1.0.11.lustre/utils/gssd/gssd.h
---- nfs-utils-1.0.11/utils/gssd/gssd.h 2007-06-29 12:28:01.000000000 -0600
-+++ nfs-utils-1.0.11.lustre/utils/gssd/gssd.h 2007-06-29 12:32:37.000000000 -0600
+diff -Nrup nfs-utils-1.0.11.lustre/utils/gssd/gssd.h nfs-utils-1.0.11/utils/gssd/gssd.h
+--- nfs-utils-1.0.11.lustre/utils/gssd/gssd.h 2008-01-02 17:22:48.000000000 -0700
++++ nfs-utils-1.0.11/utils/gssd/gssd.h 2008-01-02 18:11:38.000000000 -0700
@@ -48,8 +48,13 @@
#define GSSD_DEFAULT_CRED_PREFIX "krb5cc_"
#define GSSD_DEFAULT_MACHINE_CRED_SUFFIX "machine"
+void lgssd_mutex_put(int semid);
#endif /* _RPC_GSSD_H_ */
-diff -Nrup nfs-utils-1.0.11/utils/gssd/gssd_main_loop.c nfs-utils-1.0.11.lustre/utils/gssd/gssd_main_loop.c
---- nfs-utils-1.0.11/utils/gssd/gssd_main_loop.c 2007-06-29 12:28:01.000000000 -0600
-+++ nfs-utils-1.0.11.lustre/utils/gssd/gssd_main_loop.c 2007-06-29 12:32:38.000000000 -0600
-@@ -94,11 +94,13 @@ scan_poll_results(int ret)
+diff -Nrup nfs-utils-1.0.11.lustre/utils/gssd/gssd_main_loop.c nfs-utils-1.0.11/utils/gssd/gssd_main_loop.c
+--- nfs-utils-1.0.11.lustre/utils/gssd/gssd_main_loop.c 2008-01-02 17:22:48.000000000 -0700
++++ nfs-utils-1.0.11/utils/gssd/gssd_main_loop.c 2008-01-02 18:11:38.000000000 -0700
+@@ -44,6 +44,10 @@
+ #include <fcntl.h>
+ #include <signal.h>
+ #include <unistd.h>
++/* For time() */
++#include <time.h>
++/* For waitpid() */
++#include <wait.h>
+
+ #include "gssd.h"
+ #include "err_util.h"
+@@ -94,11 +98,13 @@ scan_poll_results(int ret)
};
void
/* Taken from linux/Documentation/dnotify.txt: */
dn_act.sa_sigaction = dir_notify_handler;
-@@ -106,10 +108,10 @@ gssd_run()
+@@ -106,10 +112,10 @@ gssd_run()
dn_act.sa_flags = SA_SIGINFO;
sigaction(DNOTIFY_SIGNAL, &dn_act, NULL);
}
fcntl(fd, F_SETSIG, DNOTIFY_SIGNAL);
fcntl(fd, F_NOTIFY, DN_CREATE|DN_DELETE|DN_MODIFY|DN_MULTISHOT);
-@@ -119,12 +121,30 @@ gssd_run()
+@@ -119,12 +125,30 @@ gssd_run()
while (1) {
while (dir_changed) {
dir_changed = 0;
/* race condition here: dir_changed could be set before we
* enter the poll, and we'd never notice if it weren't for the
* timeout. */
-@@ -139,6 +159,7 @@ gssd_run()
+@@ -139,6 +163,7 @@ gssd_run()
scan_poll_results(ret);
}
}
close(fd);
return;
}
-diff -Nrup nfs-utils-1.0.11/utils/gssd/gssd_proc.c nfs-utils-1.0.11.lustre/utils/gssd/gssd_proc.c
---- nfs-utils-1.0.11/utils/gssd/gssd_proc.c 2007-06-29 12:28:01.000000000 -0600
-+++ nfs-utils-1.0.11.lustre/utils/gssd/gssd_proc.c 2007-06-29 12:32:38.000000000 -0600
+diff -Nrup nfs-utils-1.0.11.lustre/utils/gssd/gssd_proc.c nfs-utils-1.0.11/utils/gssd/gssd_proc.c
+--- nfs-utils-1.0.11.lustre/utils/gssd/gssd_proc.c 2008-01-02 17:22:48.000000000 -0700
++++ nfs-utils-1.0.11/utils/gssd/gssd_proc.c 2008-01-02 18:11:38.000000000 -0700
@@ -43,7 +43,6 @@
#endif
#include "config.h"
goto out;
+#endif
}
-diff -Nrup nfs-utils-1.0.11/utils/gssd/gss_util.c nfs-utils-1.0.11.lustre/utils/gssd/gss_util.c
---- nfs-utils-1.0.11/utils/gssd/gss_util.c 2007-02-21 21:50:03.000000000 -0700
-+++ nfs-utils-1.0.11.lustre/utils/gssd/gss_util.c 2007-06-29 12:32:40.000000000 -0600
+diff -Nrup nfs-utils-1.0.11.lustre/utils/gssd/gss_util.c nfs-utils-1.0.11/utils/gssd/gss_util.c
+--- nfs-utils-1.0.11.lustre/utils/gssd/gss_util.c 2007-02-21 21:50:03.000000000 -0700
++++ nfs-utils-1.0.11/utils/gssd/gss_util.c 2008-01-02 18:11:38.000000000 -0700
@@ -87,9 +87,16 @@
#ifdef HAVE_COM_ERR_H
#include <com_err.h>
+ return retval;
+}
+
-diff -Nrup nfs-utils-1.0.11/utils/gssd/gss_util.h nfs-utils-1.0.11.lustre/utils/gssd/gss_util.h
---- nfs-utils-1.0.11/utils/gssd/gss_util.h 2007-02-21 21:50:03.000000000 -0700
-+++ nfs-utils-1.0.11.lustre/utils/gssd/gss_util.h 2007-06-29 12:32:41.000000000 -0600
+diff -Nrup nfs-utils-1.0.11.lustre/utils/gssd/gss_util.h nfs-utils-1.0.11/utils/gssd/gss_util.h
+--- nfs-utils-1.0.11.lustre/utils/gssd/gss_util.h 2007-02-21 21:50:03.000000000 -0700
++++ nfs-utils-1.0.11/utils/gssd/gss_util.h 2008-01-02 18:11:38.000000000 -0700
@@ -32,14 +32,14 @@
#define _GSS_UTIL_H_
+int gssd_get_local_realm(void);
#endif /* _GSS_UTIL_H_ */
-diff -Nrup nfs-utils-1.0.11/utils/gssd/krb5_util.c nfs-utils-1.0.11.lustre/utils/gssd/krb5_util.c
---- nfs-utils-1.0.11/utils/gssd/krb5_util.c 2007-06-29 12:28:01.000000000 -0600
-+++ nfs-utils-1.0.11.lustre/utils/gssd/krb5_util.c 2007-06-29 12:32:42.000000000 -0600
+diff -Nrup nfs-utils-1.0.11.lustre/utils/gssd/krb5_util.c nfs-utils-1.0.11/utils/gssd/krb5_util.c
+--- nfs-utils-1.0.11.lustre/utils/gssd/krb5_util.c 2008-01-02 17:22:48.000000000 -0700
++++ nfs-utils-1.0.11/utils/gssd/krb5_util.c 2008-01-02 18:11:38.000000000 -0700
@@ -99,12 +99,15 @@
#include <rpc/rpc.h>
#include <sys/types.h>
}
}
+#endif
-diff -Nrup nfs-utils-1.0.11/utils/gssd/krb5_util.h nfs-utils-1.0.11.lustre/utils/gssd/krb5_util.h
---- nfs-utils-1.0.11/utils/gssd/krb5_util.h 2007-06-29 12:28:01.000000000 -0600
-+++ nfs-utils-1.0.11.lustre/utils/gssd/krb5_util.h 2007-06-29 12:32:42.000000000 -0600
+diff -Nrup nfs-utils-1.0.11.lustre/utils/gssd/krb5_util.h nfs-utils-1.0.11/utils/gssd/krb5_util.h
+--- nfs-utils-1.0.11.lustre/utils/gssd/krb5_util.h 2008-01-02 17:22:48.000000000 -0700
++++ nfs-utils-1.0.11/utils/gssd/krb5_util.h 2008-01-02 18:11:38.000000000 -0700
@@ -10,6 +10,8 @@
struct gssd_k5_kt_princ {
struct gssd_k5_kt_princ *next;
-#endif
-
#endif /* KRB5_UTIL_H */
-diff -Nrup nfs-utils-1.0.11/utils/gssd/lsupport.c nfs-utils-1.0.11.lustre/utils/gssd/lsupport.c
---- nfs-utils-1.0.11/utils/gssd/lsupport.c 1969-12-31 17:00:00.000000000 -0700
-+++ nfs-utils-1.0.11.lustre/utils/gssd/lsupport.c 2007-06-29 12:32:43.000000000 -0600
-@@ -0,0 +1,787 @@
-+/* -*- 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.
-+ */
-+
-+#ifndef _GNU_SOURCE
-+#define _GNU_SOURCE
-+#endif
-+#include "config.h"
-+#include <sys/param.h>
-+#include <sys/utsname.h>
-+#include <sys/stat.h>
-+#include <sys/socket.h>
-+#include <arpa/inet.h>
-+#include <sys/types.h>
-+#include <sys/ipc.h>
-+#include <sys/sem.h>
-+
-+#include <stdio.h>
-+#include <stdlib.h>
-+#include <pwd.h>
-+#include <grp.h>
-+#include <string.h>
-+#include <dirent.h>
-+#include <poll.h>
-+#include <fcntl.h>
-+#include <signal.h>
-+#include <unistd.h>
-+#include <errno.h>
-+#include <assert.h>
-+#ifdef HAVE_GETHOSTBYNAME
-+# include <netdb.h>
-+#endif
-+
-+#ifdef _NEW_BUILD_
-+# include "lgss_utils.h"
-+#else
-+# include "err_util.h"
-+# include "gssd.h"
-+#endif
-+#include "lsupport.h"
-+
-+/****************************************
-+ * exclusive startup *
-+ ****************************************/
-+
-+static struct __sem_s {
-+ char *name;
-+ key_t sem_key;
-+ int sem_id;
-+} sems[2] = {
-+ [GSSD_CLI] = { "client", 0x3a92d473, 0 },
-+ [GSSD_SVC] = { "server", 0x3b92d473, 0 },
-+};
-+
-+void gssd_init_unique(int type)
-+{
-+ struct __sem_s *sem = &sems[type];
-+ struct sembuf sembuf;
-+
-+ assert(type == GSSD_CLI || type == GSSD_SVC);
-+
-+again:
-+ sem->sem_id = semget(sem->sem_key, 1, IPC_CREAT | IPC_EXCL | 0700);
-+ if (sem->sem_id == -1) {
-+ if (errno != EEXIST) {
-+ printerr(0, "Create sem: %s\n", strerror(errno));
-+ exit(-1);
-+ }
-+
-+ /* already exist. Note there's still a small window racing
-+ * with other processes, due to the stupid semaphore semantics.
-+ */
-+ sem->sem_id = semget(sem->sem_key, 0, 0700);
-+ if (sem->sem_id == -1) {
-+ if (errno == ENOENT) {
-+ printerr(0, "another instance just exit, "
-+ "try again\n");
-+ goto again;
-+ }
-+
-+ printerr(0, "Obtain sem: %s\n", strerror(errno));
-+ exit(-1);
-+ }
-+ } else {
-+ int val = 1;
-+
-+ if (semctl(sem->sem_id, 0, SETVAL, val) == -1) {
-+ printerr(0, "Initialize sem: %s\n",
-+ strerror(errno));
-+ exit(-1);
-+ }
-+ }
-+
-+ sembuf.sem_num = 0;
-+ sembuf.sem_op = -1;
-+ sembuf.sem_flg = IPC_NOWAIT | SEM_UNDO;
-+
-+ if (semop(sem->sem_id, &sembuf, 1) != 0) {
-+ if (errno == EAGAIN) {
-+ printerr(0, "Another instance is running, exit\n");
-+ exit(0);
-+ }
-+ printerr(0, "Grab sem: %s\n", strerror(errno));
-+ exit(0);
-+ }
-+
-+ printerr(2, "Successfully created %s global identity\n", sem->name);
-+}
-+
-+void gssd_exit_unique(int type)
-+{
-+ assert(type == GSSD_CLI || type == GSSD_SVC);
-+
-+ /*
-+ * do nothing. we can't remove the sem here, otherwise the race
-+ * window would be much bigger. So it's sad we have to leave the
-+ * sem in the system forever.
-+ */
-+}
-+
-+/****************************************
-+ * client side resolvation: *
-+ * lnd/netid/nid => hostname *
-+ ****************************************/
-+
-+char gethostname_ex[PATH_MAX] = GSSD_DEFAULT_GETHOSTNAME_EX;
-+
-+typedef int lnd_nid2hostname_t(char *lnd, uint32_t net, uint32_t addr,
-+ char *buf, int buflen);
-+
-+/* FIXME what about IPv6? */
-+static
-+int ipv4_nid2hostname(char *lnd, uint32_t net, uint32_t addr,
-+ char *buf, int buflen)
-+{
-+ struct hostent *ent;
-+
-+ addr = htonl(addr);
-+ ent = gethostbyaddr(&addr, sizeof(addr), AF_INET);
-+ if (!ent) {
-+ printerr(0, "%s: can't resolve 0x%x\n", lnd, addr);
-+ return -1;
-+ }
-+ if (strlen(ent->h_name) >= buflen) {
-+ printerr(0, "%s: name too long: %s\n", lnd, ent->h_name);
-+ return -1;
-+ }
-+ strcpy(buf, ent->h_name);
-+
-+ printerr(2, "%s: net 0x%x, addr 0x%x => %s\n",
-+ lnd, net, addr, buf);
-+ return 0;
-+}
-+
-+static
-+int lolnd_nid2hostname(char *lnd, uint32_t net, uint32_t addr,
-+ char *buf, int buflen)
-+{
-+ struct utsname uts;
-+ struct hostent *ent;
-+
-+ if (addr) {
-+ printerr(0, "%s: addr is 0x%x, we expect 0\n", lnd, addr);
-+ return -1;
-+ }
-+
-+ if (uname(&uts)) {
-+ printerr(0, "%s: failed obtain local machine name\n", lnd);
-+ return -1;
-+ }
-+
-+ ent = gethostbyname(uts.nodename);
-+ if (!ent) {
-+ printerr(0, "%s: failed obtain canonical name of %s\n",
-+ lnd, uts.nodename);
-+ return -1;
-+ }
-+
-+ if (strlen(ent->h_name) >= buflen) {
-+ printerr(0, "%s: name too long: %s\n", lnd, ent->h_name);
-+ return -1;
-+ }
-+ strcpy(buf, ent->h_name);
-+
-+ printerr(3, "%s: addr 0x%x => %s\n", lnd, addr, buf);
-+ return 0;
-+}
-+
-+static int is_space(char c)
-+{
-+ return (c == ' ' || c == '\t' || c == '\n');
-+}
-+
-+static
-+int external_nid2hostname(char *lnd, uint32_t net, uint32_t addr,
-+ char *namebuf, int namebuflen)
-+{
-+ const int bufsize = PATH_MAX + 256;
-+ char buf[bufsize], *head, *tail;
-+ FILE *fghn;
-+
-+ sprintf(buf, "%s %s 0x%x 0x%x", gethostname_ex, lnd, net, addr);
-+ printerr(2, "cmd: %s\n", buf);
-+
-+ fghn = popen(buf, "r");
-+ if (fghn == NULL) {
-+ printerr(0, "failed to call %s\n", gethostname_ex);
-+ return -1;
-+ }
-+
-+ head = fgets(buf, bufsize, fghn);
-+ if (head == NULL) {
-+ printerr(0, "can't read from %s\n", gethostname_ex);
-+ return -1;
-+ }
-+ if (pclose(fghn) == -1)
-+ printerr(1, "pclose failed, continue\n");
-+
-+ /* trim head/tail space */
-+ while (is_space(*head))
-+ head++;
-+
-+ tail = head + strlen(head);
-+ if (tail <= head) {
-+ printerr(0, "no output from %s\n", gethostname_ex);
-+ return -1;
-+ }
-+ while (is_space(*(tail - 1)))
-+ tail--;
-+ if (tail <= head) {
-+ printerr(0, "output are all space from %s\n", gethostname_ex);
-+ return -1;
-+ }
-+ *tail = '\0';
-+
-+ /* start with '@' means error msg */
-+ if (head[0] == '@') {
-+ printerr(0, "error from %s: %s\n", gethostname_ex, &head[1]);
-+ return -1;
-+ }
-+
-+ if (tail - head > namebuflen) {
-+ printerr(0, "external hostname too long: %s\n", head);
-+ return -1;
-+ }
-+
-+ printerr(2, "%s: net 0x%x, addr 0x%x => %s\n",
-+ lnd, net, addr, head);
-+ strcpy(namebuf, head);
-+ return 0;
-+}
-+
-+static struct {
-+ char *name;
-+ lnd_nid2hostname_t *nid2name;
-+} converter[LND_ENUM_END_MARKER] = {
-+ {"UNUSED0", NULL},
-+ [QSWLND] = { "QSWLND", external_nid2hostname},
-+ [SOCKLND] = { "SOCKLND", ipv4_nid2hostname },
-+ [GMLND] = { "GMLND", external_nid2hostname},
-+ [PTLLND] = { "PTLLND", external_nid2hostname },
-+ [O2IBLND] = { "O2IBLND", ipv4_nid2hostname },
-+ [CIBLND] = { "CIBLND", external_nid2hostname },
-+ [OPENIBLND] = { "OPENIBLND",external_nid2hostname },
-+ [IIBLND] = { "IIBLND", external_nid2hostname },
-+ [LOLND] = { "LOLND", lolnd_nid2hostname },
-+ [RALND] = { "RALND", external_nid2hostname },
-+ [VIBLND] = { "VIBLND", external_nid2hostname },
-+};
-+
-+int lnet_nid2hostname(lnet_nid_t nid, char *buf, int buflen)
-+{
-+ uint32_t lnd, net, addr;
-+
-+ addr = LNET_NIDADDR(nid);
-+ net = LNET_NIDNET(nid);
-+ lnd = LNET_NETTYP(net);
-+
-+ if (lnd >= LND_ENUM_END_MARKER) {
-+ printerr(0, "ERROR: Unrecognized LND %u\n", lnd);
-+ return -1;
-+ }
-+
-+ if (converter[lnd].nid2name == NULL) {
-+ printerr(0, "ERROR: %s converter not ready\n",
-+ converter[lnd].name);
-+ return -1;
-+ }
-+
-+ return converter[lnd].nid2name(converter[lnd].name, net, addr,
-+ buf, buflen);
-+}
-+
-+
-+/****************************************
-+ * lnet support routine *
-+ * (from lnet/libcfs/nidstrings.c *
-+ ****************************************/
-+
-+#define LNET_NIDSTR_SIZE 32 /* size of each one (see below for usage) */
-+
-+static int libcfs_lo_str2addr(char *str, int nob, uint32_t *addr);
-+static void libcfs_ip_addr2str(uint32_t addr, char *str);
-+static int libcfs_ip_str2addr(char *str, int nob, uint32_t *addr);
-+static void libcfs_decnum_addr2str(uint32_t addr, char *str);
-+static void libcfs_hexnum_addr2str(uint32_t addr, char *str);
-+static int libcfs_num_str2addr(char *str, int nob, uint32_t *addr);
-+
-+struct netstrfns {
-+ int nf_type;
-+ char *nf_name;
-+ char *nf_modname;
-+ void (*nf_addr2str)(uint32_t addr, char *str);
-+ int (*nf_str2addr)(char *str, int nob, uint32_t *addr);
-+};
-+
-+static struct netstrfns libcfs_netstrfns[] = {
-+ {/* .nf_type */ LOLND,
-+ /* .nf_name */ "lo",
-+ /* .nf_modname */ "klolnd",
-+ /* .nf_addr2str */ libcfs_decnum_addr2str,
-+ /* .nf_str2addr */ libcfs_lo_str2addr},
-+ {/* .nf_type */ SOCKLND,
-+ /* .nf_name */ "tcp",
-+ /* .nf_modname */ "ksocklnd",
-+ /* .nf_addr2str */ libcfs_ip_addr2str,
-+ /* .nf_str2addr */ libcfs_ip_str2addr},
-+ {/* .nf_type */ O2IBLND,
-+ /* .nf_name */ "o2ib",
-+ /* .nf_modname */ "ko2iblnd",
-+ /* .nf_addr2str */ libcfs_ip_addr2str,
-+ /* .nf_str2addr */ libcfs_ip_str2addr},
-+ {/* .nf_type */ CIBLND,
-+ /* .nf_name */ "cib",
-+ /* .nf_modname */ "kciblnd",
-+ /* .nf_addr2str */ libcfs_ip_addr2str,
-+ /* .nf_str2addr */ libcfs_ip_str2addr},
-+ {/* .nf_type */ OPENIBLND,
-+ /* .nf_name */ "openib",
-+ /* .nf_modname */ "kopeniblnd",
-+ /* .nf_addr2str */ libcfs_ip_addr2str,
-+ /* .nf_str2addr */ libcfs_ip_str2addr},
-+ {/* .nf_type */ IIBLND,
-+ /* .nf_name */ "iib",
-+ /* .nf_modname */ "kiiblnd",
-+ /* .nf_addr2str */ libcfs_ip_addr2str,
-+ /* .nf_str2addr */ libcfs_ip_str2addr},
-+ {/* .nf_type */ VIBLND,
-+ /* .nf_name */ "vib",
-+ /* .nf_modname */ "kviblnd",
-+ /* .nf_addr2str */ libcfs_ip_addr2str,
-+ /* .nf_str2addr */ libcfs_ip_str2addr},
-+ {/* .nf_type */ RALND,
-+ /* .nf_name */ "ra",
-+ /* .nf_modname */ "kralnd",
-+ /* .nf_addr2str */ libcfs_ip_addr2str,
-+ /* .nf_str2addr */ libcfs_ip_str2addr},
-+ {/* .nf_type */ QSWLND,
-+ /* .nf_name */ "elan",
-+ /* .nf_modname */ "kqswlnd",
-+ /* .nf_addr2str */ libcfs_decnum_addr2str,
-+ /* .nf_str2addr */ libcfs_num_str2addr},
-+ {/* .nf_type */ GMLND,
-+ /* .nf_name */ "gm",
-+ /* .nf_modname */ "kgmlnd",
-+ /* .nf_addr2str */ libcfs_hexnum_addr2str,
-+ /* .nf_str2addr */ libcfs_num_str2addr},
-+ {/* .nf_type */ PTLLND,
-+ /* .nf_name */ "ptl",
-+ /* .nf_modname */ "kptllnd",
-+ /* .nf_addr2str */ libcfs_decnum_addr2str,
-+ /* .nf_str2addr */ libcfs_num_str2addr},
-+ /* placeholder for net0 alias. It MUST BE THE LAST ENTRY */
-+ {/* .nf_type */ -1},
-+};
-+
-+const int libcfs_nnetstrfns = sizeof(libcfs_netstrfns)/sizeof(libcfs_netstrfns[0]);
-+
-+static int
-+libcfs_lo_str2addr(char *str, int nob, uint32_t *addr)
-+{
-+ *addr = 0;
-+ return 1;
-+}
-+
-+static void
-+libcfs_ip_addr2str(uint32_t addr, char *str)
-+{
-+ snprintf(str, LNET_NIDSTR_SIZE, "%u.%u.%u.%u",
-+ (addr >> 24) & 0xff, (addr >> 16) & 0xff,
-+ (addr >> 8) & 0xff, addr & 0xff);
-+}
-+
-+/* CAVEAT EMPTOR XscanfX
-+ * I use "%n" at the end of a sscanf format to detect trailing junk. However
-+ * sscanf may return immediately if it sees the terminating '0' in a string, so
-+ * I initialise the %n variable to the expected length. If sscanf sets it;
-+ * fine, if it doesn't, then the scan ended at the end of the string, which is
-+ * fine too :) */
-+
-+static int
-+libcfs_ip_str2addr(char *str, int nob, uint32_t *addr)
-+{
-+ int a;
-+ int b;
-+ int c;
-+ int d;
-+ int n = nob; /* XscanfX */
-+
-+ /* numeric IP? */
-+ if (sscanf(str, "%u.%u.%u.%u%n", &a, &b, &c, &d, &n) >= 4 &&
-+ n == nob &&
-+ (a & ~0xff) == 0 && (b & ~0xff) == 0 &&
-+ (c & ~0xff) == 0 && (d & ~0xff) == 0) {
-+ *addr = ((a<<24)|(b<<16)|(c<<8)|d);
-+ return 1;
-+ }
-+
-+#ifdef HAVE_GETHOSTBYNAME
-+ /* known hostname? */
-+ if (('a' <= str[0] && str[0] <= 'z') ||
-+ ('A' <= str[0] && str[0] <= 'Z')) {
-+ char *tmp;
-+
-+ tmp = malloc(nob + 1);
-+ if (tmp != NULL) {
-+ struct hostent *he;
-+
-+ memcpy(tmp, str, nob);
-+ tmp[nob] = 0;
-+
-+ he = gethostbyname(tmp);
-+
-+ free(tmp);
-+ tmp = NULL;
-+
-+ if (he != NULL) {
-+ uint32_t ip = *(uint32_t *)he->h_addr;
-+
-+ *addr = ntohl(ip);
-+ return 1;
-+ }
-+ }
-+ }
-+#endif
-+ return 0;
-+}
-+
-+static void
-+libcfs_decnum_addr2str(uint32_t addr, char *str)
-+{
-+ snprintf(str, LNET_NIDSTR_SIZE, "%u", addr);
-+}
-+
-+static void
-+libcfs_hexnum_addr2str(uint32_t addr, char *str)
-+{
-+ snprintf(str, LNET_NIDSTR_SIZE, "0x%x", addr);
-+}
-+
-+static int
-+libcfs_num_str2addr(char *str, int nob, uint32_t *addr)
-+{
-+ int n;
-+
-+ n = nob;
-+ if (sscanf(str, "0x%x%n", addr, &n) >= 1 && n == nob)
-+ return 1;
-+
-+ n = nob;
-+ if (sscanf(str, "0X%x%n", addr, &n) >= 1 && n == nob)
-+ return 1;
-+
-+ n = nob;
-+ if (sscanf(str, "%u%n", addr, &n) >= 1 && n == nob)
-+ return 1;
-+
-+ return 0;
-+}
-+
-+static struct netstrfns *
-+libcfs_lnd2netstrfns(int lnd)
-+{
-+ int i;
-+
-+ if (lnd >= 0)
-+ for (i = 0; i < libcfs_nnetstrfns; i++)
-+ if (lnd == libcfs_netstrfns[i].nf_type)
-+ return &libcfs_netstrfns[i];
-+
-+ return NULL;
-+}
-+
-+static struct netstrfns *
-+libcfs_str2net_internal(char *str, uint32_t *net)
-+{
-+ struct netstrfns *nf;
-+ int nob;
-+ int netnum;
-+ int i;
-+
-+ for (i = 0; i < libcfs_nnetstrfns; i++) {
-+ nf = &libcfs_netstrfns[i];
-+ if (nf->nf_type >= 0 &&
-+ !strncmp(str, nf->nf_name, strlen(nf->nf_name)))
-+ break;
-+ }
-+
-+ if (i == libcfs_nnetstrfns)
-+ return NULL;
-+
-+ nob = strlen(nf->nf_name);
-+
-+ if (strlen(str) == (unsigned int)nob) {
-+ netnum = 0;
-+ } else {
-+ if (nf->nf_type == LOLND) /* net number not allowed */
-+ return NULL;
-+
-+ str += nob;
-+ i = strlen(str);
-+ if (sscanf(str, "%u%n", &netnum, &i) < 1 ||
-+ i != (int)strlen(str))
-+ return NULL;
-+ }
-+
-+ *net = LNET_MKNET(nf->nf_type, netnum);
-+ return nf;
-+}
-+
-+lnet_nid_t
-+libcfs_str2nid(char *str)
-+{
-+ char *sep = strchr(str, '@');
-+ struct netstrfns *nf;
-+ uint32_t net;
-+ uint32_t addr;
-+
-+ if (sep != NULL) {
-+ nf = libcfs_str2net_internal(sep + 1, &net);
-+ if (nf == NULL)
-+ return LNET_NID_ANY;
-+ } else {
-+ sep = str + strlen(str);
-+ net = LNET_MKNET(SOCKLND, 0);
-+ nf = libcfs_lnd2netstrfns(SOCKLND);
-+ if (!nf)
-+ return LNET_NID_ANY;
-+ }
-+
-+ if (!nf->nf_str2addr(str, sep - str, &addr))
-+ return LNET_NID_ANY;
-+
-+ return LNET_MKNID(net, addr);
-+}
-+
-+/****************************************
-+ * user mapping database handling *
-+ * (very rudiment) *
-+ ****************************************/
-+
-+#define MAPPING_GROW_SIZE 512
-+#define MAX_LINE_LEN 256
-+
-+struct user_map_item {
-+ char *principal; /* NULL means match all, will cause multi->single mapped, FORBID */
-+ lnet_nid_t nid;
-+ uid_t uid;
-+};
-+
-+struct user_mapping {
-+ int nitems;
-+ struct user_map_item *items;
-+};
-+
-+static struct user_mapping mapping = {0, NULL};
-+/* FIXME to be finished: monitor change of mapping database */
-+static int mapping_mtime = 0;
-+
-+void cleanup_mapping(void)
-+{
-+ if (mapping.items) {
-+ for (; mapping.nitems > 0; mapping.nitems--)
-+ free(mapping.items[mapping.nitems - 1].principal);
-+ free(mapping.items);
-+ mapping.items = NULL;
-+ }
-+}
-+
-+static int grow_mapping(int nitems)
-+{
-+ struct user_map_item *new;
-+ int oldsize, newsize;
-+
-+ oldsize = (mapping.nitems * sizeof(struct user_map_item) +
-+ MAPPING_GROW_SIZE - 1) / MAPPING_GROW_SIZE;
-+ newsize = (nitems * sizeof(struct user_map_item) +
-+ MAPPING_GROW_SIZE - 1) / MAPPING_GROW_SIZE;
-+ while (newsize <= oldsize)
-+ return 0;
-+
-+ newsize *= MAPPING_GROW_SIZE;
-+ new = malloc(newsize);
-+ if (!new) {
-+ printerr(0, "can't alloc mapping size %d\n", newsize);
-+ return -1;
-+ }
-+
-+ if (mapping.items) {
-+ memcpy(new, mapping.items, mapping.nitems * sizeof(struct user_map_item));
-+ free(mapping.items);
-+ }
-+ mapping.items = new;
-+ return 0;
-+}
-+
-+uid_t parse_uid(char *uidstr)
-+{
-+ struct passwd *pw;
-+ char *p = NULL;
-+ long uid;
-+
-+ pw = getpwnam(uidstr);
-+ if (pw)
-+ return pw->pw_uid;
-+
-+ uid = strtol(uidstr, &p, 0);
-+ if (*p == '\0')
-+ return (uid_t) uid;
-+
-+ return -1;
-+}
-+
-+static int read_mapping_db(void)
-+{
-+ char princ[MAX_LINE_LEN];
-+ char nid_str[MAX_LINE_LEN];
-+ char dest[MAX_LINE_LEN];
-+ char linebuf[MAX_LINE_LEN];
-+ char *line;
-+ lnet_nid_t nid;
-+ uid_t dest_uid;
-+ FILE *f;
-+
-+ /* cleanup old mappings */
-+ cleanup_mapping();
-+
-+ f = fopen(MAPPING_DATABASE_FILE, "r");
-+ if (!f) {
-+ printerr(0, "can't open mapping database: %s\n",
-+ MAPPING_DATABASE_FILE);
-+ return -1;
-+ }
-+
-+ while ((line = fgets(linebuf, MAX_LINE_LEN, f)) != NULL) {
-+ char *name;
-+
-+ if (strlen(line) >= MAX_LINE_LEN) {
-+ printerr(0, "invalid mapping db: line too long (%d)\n",
-+ strlen(line));
-+ continue;
-+ }
-+
-+ if (sscanf(line, "%s %s %s", princ, nid_str, dest) != 3) {
-+ printerr(0, "mapping db: syntax error\n");
-+ continue;
-+ }
-+
-+ if (!strcmp(princ, "*")) {
-+ printerr(0, "NOT permit \"*\" princ, it will cause multi->single mapped\n");
-+ continue;
-+ } else {
-+ name = strdup(princ);
-+ if (!name) {
-+ printerr(0, "fail to dup str %s\n", princ);
-+ continue;
-+ }
-+ }
-+
-+ if (!strcmp(nid_str, "*")) {
-+ nid = LNET_NID_ANY;
-+ } else {
-+ nid = libcfs_str2nid(nid_str);
-+ if (nid == LNET_NID_ANY) {
-+ printerr(0, "fail to parse nid %s\n", nid_str);
-+ free(name);
-+ continue;
-+ }
-+ }
-+
-+ dest_uid = parse_uid(dest);
-+ if (dest_uid == -1) {
-+ printerr(0, "no valid user: %s\n", dest);
-+ free(name);
-+ continue;
-+ }
-+
-+ if (grow_mapping(mapping.nitems + 1)) {
-+ printerr(0, "fail to grow mapping to %d\n",
-+ mapping.nitems + 1);
-+ free(name);
-+ fclose(f);
-+ return -1;
-+ }
-+
-+ mapping.items[mapping.nitems].principal = name;
-+ mapping.items[mapping.nitems].nid = nid;
-+ mapping.items[mapping.nitems].uid = dest_uid;
-+ mapping.nitems++;
-+ printerr(1, "add mapping: %s(%s/0x%llx) ==> %d\n",
-+ name, nid_str, nid, dest_uid);
-+ }
-+
-+ fclose(f);
-+ return 0;
-+}
-+
-+static inline int mapping_changed(void)
-+{
-+ struct stat st;
-+
-+ if (stat(MAPPING_DATABASE_FILE, &st) == -1) {
-+ /* stat failed, treat it like doesn't exist or be removed */
-+ if (mapping_mtime == 0) {
-+ return 0;
-+ } else {
-+ printerr(0, "Warning: stat %s failed: %s\n",
-+ MAPPING_DATABASE_FILE, strerror(errno));
-+
-+ mapping_mtime = 0;
-+ return 1;
-+ }
-+ }
-+
-+ if (st.st_mtime != mapping_mtime) {
-+ mapping_mtime = st.st_mtime;
-+ return 1;
-+ }
-+
-+ return 0;
-+}
-+
-+int lookup_mapping(char *princ, lnet_nid_t nid, uid_t *uid)
-+{
-+ int n;
-+
-+ *uid = -1;
-+
-+ /* FIXME race condition here */
-+ if (mapping_changed()) {
-+ if (read_mapping_db())
-+ printerr(0, "all remote users will be denied\n");
-+ }
-+
-+ for (n = 0; n < mapping.nitems; n++) {
-+ struct user_map_item *entry = &mapping.items[n];
-+
-+ if (entry->nid != LNET_NID_ANY && entry->nid != nid)
-+ continue;
-+ if (!strcasecmp(entry->principal, princ)) {
-+ printerr(1, "found mapping: %s ==> %d\n",
-+ princ, entry->uid);
-+ *uid = entry->uid;
-+ return 0;
-+ }
-+ }
-+
-+ printerr(2, "no mapping for %s/%#Lx\n", princ, nid);
-+ return -1;
-+}
-diff -Nrup nfs-utils-1.0.11/utils/gssd/lsupport.h nfs-utils-1.0.11.lustre/utils/gssd/lsupport.h
---- nfs-utils-1.0.11/utils/gssd/lsupport.h 1969-12-31 17:00:00.000000000 -0700
-+++ nfs-utils-1.0.11.lustre/utils/gssd/lsupport.h 2007-06-29 12:32:43.000000000 -0600
-@@ -0,0 +1,89 @@
-+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
-+ * vim:expandtab:shiftwidth=8:tabstop=8:
-+ */
-+
-+#ifndef __LIBCFS_H__
-+#define __LIBCFS_H__
-+
-+#include <unistd.h>
-+#include <stdint.h>
-+
-+#define GSSD_CLI (0)
-+#define GSSD_SVC (1)
-+
-+void gssd_init_unique(int type);
-+void gssd_exit_unique(int type);
-+
-+/*
-+ * copied from lustre source
-+ */
-+
-+#define LUSTRE_GSS_SVC_MDS 0
-+#define LUSTRE_GSS_SVC_OSS 1
-+
-+struct lgssd_upcall_data {
-+ uint32_t seq;
-+ uint32_t uid;
-+ uint32_t gid;
-+ uint32_t svc;
-+ uint64_t nid;
-+ char obd[64];
-+};
-+
-+#define GSSD_INTERFACE_VERSION (1)
-+
-+struct lgssd_ioctl_param {
-+ int version; /* in */
-+ char *uuid; /* in */
-+ int lustre_svc; /* in */
-+ uid_t uid; /* in */
-+ gid_t gid; /* in */
-+ long send_token_size;/* in */
-+ char *send_token; /* in */
-+ long reply_buf_size; /* in */
-+ char *reply_buf; /* in */
-+ long status; /* out */
-+ long reply_length; /* out */
-+};
-+
-+#define GSSD_DEFAULT_GETHOSTNAME_EX "/etc/lustre/nid2hostname"
-+#define MAPPING_DATABASE_FILE "/etc/lustre/idmap.conf"
-+
-+typedef uint64_t lnet_nid_t;
-+typedef uint32_t lnet_netid_t;
-+
-+#define LNET_NID_ANY ((lnet_nid_t) -1)
-+#define LNET_PID_ANY ((lnet_pid_t) -1)
-+
-+enum {
-+ /* Only add to these values (i.e. don't ever change or redefine them):
-+ * network addresses depend on them... */
-+ QSWLND = 1,
-+ SOCKLND = 2,
-+ GMLND = 3,
-+ PTLLND = 4,
-+ O2IBLND = 5,
-+ CIBLND = 6,
-+ OPENIBLND = 7,
-+ IIBLND = 8,
-+ LOLND = 9,
-+ RALND = 10,
-+ VIBLND = 11,
-+ LND_ENUM_END_MARKER
-+};
-+
-+int lnet_nid2hostname(lnet_nid_t nid, char *buf, int buflen);
-+void cleanup_mapping(void);
-+int lookup_mapping(char *princ, uint64_t nid, uid_t *uid);
-+lnet_nid_t libcfs_str2nid(char *str);
-+
-+/* how an LNET NID encodes net:address */
-+#define LNET_NIDADDR(nid) ((uint32_t)((nid) & 0xffffffff))
-+#define LNET_NIDNET(nid) ((uint32_t)(((nid) >> 32)) & 0xffffffff)
-+#define LNET_MKNID(net,addr) ((((uint64_t)(net))<<32)|((uint64_t)(addr)))
-+/* how net encodes type:number */
-+#define LNET_NETNUM(net) ((net) & 0xffff)
-+#define LNET_NETTYP(net) (((net) >> 16) & 0xffff)
-+#define LNET_MKNET(typ,num) ((((uint32_t)(typ))<<16)|((uint32_t)(num)))
-+
-+#endif /* __LIBCFS_H__ */
-diff -Nrup nfs-utils-1.0.11/utils/gssd/Makefile.am nfs-utils-1.0.11.lustre/utils/gssd/Makefile.am
---- nfs-utils-1.0.11/utils/gssd/Makefile.am 2007-02-21 21:50:03.000000000 -0700
-+++ nfs-utils-1.0.11.lustre/utils/gssd/Makefile.am 2007-06-29 12:29:20.000000000 -0600
+diff -Nrup nfs-utils-1.0.11.lustre/utils/gssd/Makefile.am nfs-utils-1.0.11/utils/gssd/Makefile.am
+--- nfs-utils-1.0.11.lustre/utils/gssd/Makefile.am 2007-02-21 21:50:03.000000000 -0700
++++ nfs-utils-1.0.11/utils/gssd/Makefile.am 2008-01-02 18:10:29.000000000 -0700
@@ -1,17 +1,11 @@
## Process this file with automake to produce Makefile.in
- rm -f $(RPCPREFIX)$$inst ; \
- done)
-
-diff -Nrup nfs-utils-1.0.11/utils/gssd/svcgssd.c nfs-utils-1.0.11.lustre/utils/gssd/svcgssd.c
---- nfs-utils-1.0.11/utils/gssd/svcgssd.c 2007-02-21 21:50:03.000000000 -0700
-+++ nfs-utils-1.0.11.lustre/utils/gssd/svcgssd.c 2007-06-29 12:32:44.000000000 -0600
+diff -Nrup nfs-utils-1.0.11.lustre/utils/gssd/svcgssd.c nfs-utils-1.0.11/utils/gssd/svcgssd.c
+--- nfs-utils-1.0.11.lustre/utils/gssd/svcgssd.c 2007-02-21 21:50:03.000000000 -0700
++++ nfs-utils-1.0.11/utils/gssd/svcgssd.c 2008-01-02 18:11:38.000000000 -0700
@@ -43,7 +43,6 @@
#include <sys/types.h>
#include <sys/stat.h>
printerr(0, "gssd_run returned!\n");
abort();
}
-diff -Nrup nfs-utils-1.0.11/utils/gssd/svcgssd.h nfs-utils-1.0.11.lustre/utils/gssd/svcgssd.h
---- nfs-utils-1.0.11/utils/gssd/svcgssd.h 2007-02-21 21:50:03.000000000 -0700
-+++ nfs-utils-1.0.11.lustre/utils/gssd/svcgssd.h 2007-06-29 12:32:45.000000000 -0600
+diff -Nrup nfs-utils-1.0.11.lustre/utils/gssd/svcgssd.h nfs-utils-1.0.11/utils/gssd/svcgssd.h
+--- nfs-utils-1.0.11.lustre/utils/gssd/svcgssd.h 2007-02-21 21:50:03.000000000 -0700
++++ nfs-utils-1.0.11/utils/gssd/svcgssd.h 2008-01-02 18:11:38.000000000 -0700
@@ -35,9 +35,20 @@
#include <sys/queue.h>
#include <gssapi/gssapi.h>
+#define LUSTRE_ROOT_NAMELEN 11
#endif /* _RPC_SVCGSSD_H_ */
-diff -Nrup nfs-utils-1.0.11/utils/gssd/svcgssd_main_loop.c nfs-utils-1.0.11.lustre/utils/gssd/svcgssd_main_loop.c
---- nfs-utils-1.0.11/utils/gssd/svcgssd_main_loop.c 2007-02-21 21:50:03.000000000 -0700
-+++ nfs-utils-1.0.11.lustre/utils/gssd/svcgssd_main_loop.c 2007-06-29 12:32:45.000000000 -0600
-@@ -46,46 +46,66 @@
+diff -Nrup nfs-utils-1.0.11.lustre/utils/gssd/svcgssd_main_loop.c nfs-utils-1.0.11/utils/gssd/svcgssd_main_loop.c
+--- nfs-utils-1.0.11.lustre/utils/gssd/svcgssd_main_loop.c 2007-02-21 21:50:03.000000000 -0700
++++ nfs-utils-1.0.11/utils/gssd/svcgssd_main_loop.c 2008-01-02 18:11:38.000000000 -0700
+@@ -42,50 +42,72 @@
+ #include <fcntl.h>
+ #include <errno.h>
+ #include <unistd.h>
++/* For nanosleep() */
++#include <time.h>
+
#include "svcgssd.h"
#include "err_util.h"
}
}
}
-diff -Nrup nfs-utils-1.0.11/utils/gssd/svcgssd_proc.c nfs-utils-1.0.11.lustre/utils/gssd/svcgssd_proc.c
---- nfs-utils-1.0.11/utils/gssd/svcgssd_proc.c 2007-02-21 21:50:03.000000000 -0700
-+++ nfs-utils-1.0.11.lustre/utils/gssd/svcgssd_proc.c 2007-06-29 12:32:46.000000000 -0600
+diff -Nrup nfs-utils-1.0.11.lustre/utils/gssd/svcgssd_proc.c nfs-utils-1.0.11/utils/gssd/svcgssd_proc.c
+--- nfs-utils-1.0.11.lustre/utils/gssd/svcgssd_proc.c 2007-02-21 21:50:03.000000000 -0700
++++ nfs-utils-1.0.11/utils/gssd/svcgssd_proc.c 2008-01-02 18:11:38.000000000 -0700
@@ -35,7 +35,6 @@
#include <sys/param.h>
void
print_hexl(int pri, unsigned char *cp, int length)
{
-@@ -286,12 +293,121 @@ print_hexl(int pri, unsigned char *cp, i
+@@ -286,12 +293,149 @@ print_hexl(int pri, unsigned char *cp, i
printerr(pri,"\n");
}
}
+{
+ u_int32_t maj_stat, min_stat;
+ gss_buffer_desc name;
-+ char *sname, *realm, *slash;
++ char *sname, *host, *realm;
++ const int namebuf_size = 512;
++ char namebuf[namebuf_size];
+ int res = -1;
+ gss_OID name_type = GSS_C_NO_OID;
+ struct passwd *pw;
+ return -1;
+ }
+ memcpy(sname, name.value, name.length);
-+ printerr(1, "authenticated %s from %016llx\n", sname, nid);
+ gss_release_buffer(&min_stat, &name);
+
+ if (lustre_svc == LUSTRE_GSS_SVC_MDS)
+ cred->cr_mapped_uid = -1;
+
+ realm = strchr(sname, '@');
-+ if (!realm) {
-+ printerr(0, "WARNNING: principal %s contains no realm name\n",
-+ sname);
-+ cred->cr_remote = (mds_local_realm != NULL);
-+ } else {
++ if (realm)
+ *realm++ = '\0';
-+ if (!mds_local_realm)
-+ cred->cr_remote = 1;
-+ else
-+ cred->cr_remote =
-+ (strcasecmp(mds_local_realm, realm) != 0);
-+ }
+
-+ if (cred->cr_remote) {
-+ if (cred->cr_mapped_uid != -1)
-+ res = 0;
-+ else if (lustre_svc == LUSTRE_GSS_SVC_OSS &&
-+ strcmp(sname, "lustre_root") == 0)
-+ res = 0;
-+ else
-+ printerr(0, "principal %s is remote without mapping\n",
-+ sname);
++ host = strchr(sname, '/');
++ if (host)
++ *host++ = '\0';
++
++ if (strcmp(sname, GSSD_SERVICE_OSS) == 0) {
++ printerr(0, "forbid "GSSD_SERVICE_OSS" as user name\n");
+ goto out_free;
-+ }
++ }
++
++ /* 1. check host part */
++ if (host) {
++ if (lnet_nid2hostname(nid, namebuf, namebuf_size)) {
++ printerr(0, "ERROR: failed to resolve hostname for "
++ "%s/%s@%s from %016llx\n",
++ sname, host, realm, nid);
++ goto out_free;
++ }
++
++ if (strcasecmp(host, namebuf)) {
++ printerr(0, "ERROR: %s/%s@s claimed hostname doesn't "
++ "match %s, nid %016llx\n", sname, host, realm,
++ namebuf, nid);
++ goto out_free;
++ }
++ } else {
++ if (!strcmp(sname, GSSD_SERVICE_MDS)) {
++ printerr(0, "ERROR: "GSSD_SERVICE_MDS"@%s from %016llx "
++ "doesn't bind with hostname\n",
++ realm ? realm : "", nid);
++ goto out_free;
++ }
++ }
++
++ /* 2. check realm */
++ if (!realm) {
++ /* just deny it
++ cred->cr_remote = (mds_local_realm != NULL);
++ */
++ printerr(0, "ERROR: %s%s%s have no realm name\n",
++ sname, host ? "/" : "", host ? "host" : "");
++ goto out_free;
++ }
++
++ if (!mds_local_realm || strcasecmp(mds_local_realm, realm)) {
++ cred->cr_remote = 1;
+
-+ slash = strchr(sname, '/');
-+ if (slash)
-+ *slash = '\0';
++ if (cred->cr_mapped_uid == -1)
++ printerr(0, "ERROR: %s from %016llx is remote but "
++ "without mapping\n", sname, nid);
++ /* mapped, skip user checking */
++ goto out_free;
++ }
+
++ /* 3. check user */
+ if (!(pw = getpwnam(sname))) {
-+ /* If client use machine credential, we map it to root, which
-+ * will subject to further mapping by root-squash in kernel.
-+ *
-+ * MDS service keytab is treated as special user, also mapped
-+ * to root. OSS service keytab can't be used as a user.
-+ */
++ /* map lustre_root/lustre_mds to root user, which is subject
++ * to further mapping by root-squash in kernel. */
+ if (!strcmp(sname, LUSTRE_ROOT_NAME)) {
-+ printerr(2, "lustre_root principal, resolve to uid 0\n");
+ cred->cr_uid = 0;
+ cred->cr_usr_root = 1;
+ } else if (!strcmp(sname, GSSD_SERVICE_MDS)) {
-+ printerr(2, "mds service principal, resolve to uid 0\n");
+ cred->cr_uid = 0;
+ cred->cr_usr_mds = 1;
+ } else {
-+ cred->cr_uid = -1;
+ if (cred->cr_mapped_uid == -1) {
-+ printerr(0, "invalid user %s\n", sname);
++ printerr(0, "ERROR: invalid user, %s/%s@%s "
++ "from %016llx\n", sname, host,
++ realm, nid);
+ goto out_free;
+ }
-+ printerr(2, "user %s mapped to %u\n",
-+ sname, cred->cr_mapped_uid);
+ }
++ printerr(2, "user %s from %016llx is mapped to %u\n",
++ sname, nid, cred->cr_mapped_uid);
+ } else {
++ /* note: a mapped local user will go to here too */
+ cred->cr_uid = pw->pw_uid;
+ printerr(2, "%s resolve to uid %u\n", sname, cred->cr_uid);
+ }
+
++ printerr(1, "%s: authenticated %s%s%s@%s from %016llx\n",
++ lustre_svc_name[lustre_svc], sname,
++ host ? "/" : "", host ? host : "", realm, nid);
+ res = 0;
+out_free:
+ free(sname);
char in_tok_buf[TOKEN_BUF_SIZE];
char in_handle_buf[15];
char out_handle_buf[15];
-@@ -303,10 +419,13 @@ handle_nullreq(FILE *f) {
+@@ -303,10 +447,13 @@ handle_nullreq(FILE *f) {
ignore_out_tok = {.value = NULL},
/* XXX isn't there a define for this?: */
null_token = {.value = NULL};
u_int32_t maj_stat = GSS_S_FAILURE, min_stat = 0;
u_int32_t ignore_min_stat;
struct svc_cred cred;
-@@ -314,25 +433,31 @@ handle_nullreq(FILE *f) {
+@@ -314,25 +461,31 @@ handle_nullreq(FILE *f) {
static int lbuflen = 0;
static char *cp;
+ qword_get(&cp, (char *) &lustre_svc, sizeof(lustre_svc));
+ qword_get(&cp, (char *) &nid, sizeof(nid));
+ qword_get(&cp, (char *) &handle_seq, sizeof(handle_seq));
-+ printerr(1, "handling req: svc %u, nid %016llx, idx %llx\n",
++ printerr(2, "handling req: svc %u, nid %016llx, idx %llx\n",
+ lustre_svc, nid, handle_seq);
+
in_handle.length = (size_t) qword_get(&cp, in_handle.value,
if (in_tok.length < 0) {
printerr(0, "WARNING: handle_nullreq: "
-@@ -352,7 +477,13 @@ handle_nullreq(FILE *f) {
+@@ -352,7 +505,13 @@ handle_nullreq(FILE *f) {
memcpy(&ctx, in_handle.value, in_handle.length);
}
&in_tok, GSS_C_NO_CHANNEL_BINDINGS, &client_name,
&mech, &out_tok, &ret_flags, NULL, NULL);
-@@ -370,7 +501,8 @@ handle_nullreq(FILE *f) {
+@@ -370,7 +529,8 @@ handle_nullreq(FILE *f) {
maj_stat, min_stat, mech);
goto out_err;
}
/* get_ids() prints error msg */
maj_stat = GSS_S_BAD_NAME; /* XXX ? */
gss_release_name(&ignore_min_stat, &client_name);
-@@ -378,10 +510,8 @@ handle_nullreq(FILE *f) {
+@@ -378,10 +538,8 @@ handle_nullreq(FILE *f) {
}
gss_release_name(&ignore_min_stat, &client_name);
out_handle.length = sizeof(handle_seq);
memcpy(out_handle.value, &handle_seq, sizeof(handle_seq));
-@@ -405,8 +535,7 @@ out:
+@@ -405,8 +563,7 @@ out:
free(ctx_token.value);
if (out_tok.value != NULL)
gss_release_buffer(&ignore_min_stat, &out_tok);
out_err:
if (ctx != GSS_C_NO_CONTEXT)
-diff -Nrup nfs-utils-1.0.11/utils/Makefile.am nfs-utils-1.0.11.lustre/utils/Makefile.am
---- nfs-utils-1.0.11/utils/Makefile.am 2007-02-21 21:50:03.000000000 -0700
-+++ nfs-utils-1.0.11.lustre/utils/Makefile.am 2007-06-29 12:29:20.000000000 -0600
+diff -Nrup nfs-utils-1.0.11.lustre/utils/Makefile.am nfs-utils-1.0.11/utils/Makefile.am
+--- nfs-utils-1.0.11.lustre/utils/Makefile.am 2007-02-21 21:50:03.000000000 -0700
++++ nfs-utils-1.0.11/utils/Makefile.am 2008-01-02 18:10:29.000000000 -0700
@@ -2,30 +2,6 @@
OPTDIRS =
{
u_int32_t maj_stat, min_stat;
gss_buffer_desc name;
- char *sname, *realm, *slash;
+ char *sname, *host, *realm;
+ const int namebuf_size = 512;
+ char namebuf[namebuf_size];
int res = -1;
gss_OID name_type = GSS_C_NO_OID;
struct passwd *pw;
return -1;
}
memcpy(sname, name.value, name.length);
- printerr(1, "%s: authenticated %s from %016llx\n",
- lustre_svc_name[lustre_svc], sname, nid);
gss_release_buffer(&min_stat, &name);
if (lustre_svc == LUSTRE_GSS_SVC_MDS)
cred->cr_mapped_uid = -1;
realm = strchr(sname, '@');
- if (!realm) {
- printerr(0, "WARNNING: principal %s contains no realm name\n",
- sname);
- cred->cr_remote = (mds_local_realm != NULL);
- } else {
+ if (realm)
*realm++ = '\0';
- if (!mds_local_realm)
- cred->cr_remote = 1;
- else
- cred->cr_remote =
- (strcasecmp(mds_local_realm, realm) != 0);
- }
- if (cred->cr_remote) {
- if (cred->cr_mapped_uid != -1)
- res = 0;
- else if (lustre_svc == LUSTRE_GSS_SVC_OSS &&
- strcmp(sname, "lustre_root") == 0)
- res = 0;
- else
- printerr(0, "principal %s is remote without mapping\n",
- sname);
+ host = strchr(sname, '/');
+ if (host)
+ *host++ = '\0';
+
+ if (strcmp(sname, GSSD_SERVICE_OSS) == 0) {
+ printerr(0, "forbid "GSSD_SERVICE_OSS" as user name\n");
goto out_free;
- }
+ }
+
+ /* 1. check host part */
+ if (host) {
+ if (lnet_nid2hostname(nid, namebuf, namebuf_size)) {
+ printerr(0, "ERROR: failed to resolve hostname for "
+ "%s/%s@%s from %016llx\n",
+ sname, host, realm, nid);
+ goto out_free;
+ }
+
+ if (strcasecmp(host, namebuf)) {
+ printerr(0, "ERROR: %s/%s@s claimed hostname doesn't "
+ "match %s, nid %016llx\n", sname, host, realm,
+ namebuf, nid);
+ goto out_free;
+ }
+ } else {
+ if (!strcmp(sname, GSSD_SERVICE_MDS)) {
+ printerr(0, "ERROR: "GSSD_SERVICE_MDS"@%s from %016llx "
+ "doesn't bind with hostname\n",
+ realm ? realm : "", nid);
+ goto out_free;
+ }
+ }
- slash = strchr(sname, '/');
- if (slash)
- *slash = '\0';
+ /* 2. check realm */
+ if (!realm) {
+ /* just deny it
+ cred->cr_remote = (mds_local_realm != NULL);
+ */
+ printerr(0, "ERROR: %s%s%s have no realm name\n",
+ sname, host ? "/" : "", host ? "host" : "");
+ goto out_free;
+ }
+
+ if (!mds_local_realm || strcasecmp(mds_local_realm, realm)) {
+ cred->cr_remote = 1;
+
+ if (cred->cr_mapped_uid == -1)
+ printerr(0, "ERROR: %s from %016llx is remote but "
+ "without mapping\n", sname, nid);
+ /* mapped, skip user checking */
+ goto out_free;
+ }
+ /* 3. check user */
if (!(pw = getpwnam(sname))) {
- /* If client use machine credential, we map it to root, which
- * will subject to further mapping by root-squash in kernel.
- *
- * MDS service keytab is treated as special user, also mapped
- * to root. OSS service keytab can't be used as a user.
- */
+ /* map lustre_root/lustre_mds to root user, which is subject
+ * to further mapping by root-squash in kernel. */
if (!strcmp(sname, LUSTRE_ROOT_NAME)) {
- printerr(2, "lustre_root principal, resolve to uid 0\n");
cred->cr_uid = 0;
cred->cr_usr_root = 1;
} else if (!strcmp(sname, GSSD_SERVICE_MDS)) {
- printerr(2, "mds service principal, resolve to uid 0\n");
cred->cr_uid = 0;
cred->cr_usr_mds = 1;
} else {
- cred->cr_uid = -1;
if (cred->cr_mapped_uid == -1) {
- printerr(0, "invalid user %s\n", sname);
+ printerr(0, "ERROR: invalid user, %s/%s@%s "
+ "from %016llx\n", sname, host,
+ realm, nid);
goto out_free;
}
- printerr(2, "user %s mapped to %u\n",
- sname, cred->cr_mapped_uid);
}
+ printerr(2, "user %s from %016llx is mapped to %u\n",
+ sname, nid, cred->cr_mapped_uid);
} else {
+ /* note: a mapped local user will go to here too */
cred->cr_uid = pw->pw_uid;
printerr(2, "%s resolve to uid %u\n", sname, cred->cr_uid);
}
+ printerr(1, "%s: authenticated %s%s%s@%s from %016llx\n",
+ lustre_svc_name[lustre_svc], sname,
+ host ? "/" : "", host ? host : "", realm, nid);
res = 0;
out_free:
free(sname);
+++ /dev/null
-/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
- * vim:expandtab:shiftwidth=8:tabstop=8:
- *
- * Copyright (C) 2004-2006 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 <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 <stdarg.h>
-#include <stddef.h>
-#include <libgen.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <mntent.h>
-
-#include <lustre/liblustreapi.h>
-#include <lustre/lustre_user.h>
-
-#include "obdctl.h"
-
-static char *progname;
-
-static void usage(void)
-{
- fprintf(stderr,
- "\nusage: %s {uid} {gid} {mdtname} {key} {handle} {cmd}\n"
- "Normally invoked as an upcall from Lustre, set via:\n"
- " /proc/fs/lustre/mdt/{mdtname}/rmtacl_upcall\n",
- progname);
-}
-
-static inline void show_result(struct rmtacl_downcall_data *data)
-{
- fprintf(stdout, "buflen %d\n\n%s\n", data->add_buflen, data->add_buf);
-}
-
-#define MDS_ERR "server processing error"
-
-static void errlog(char *buf, const char *fmt, ...)
-{
- va_list args;
-
- va_start(args, fmt);
- vsprintf(buf, fmt, args);
- va_end(args);
-}
-
-static char *get_lustre_mount(void)
-{
- FILE *fp;
- struct mntent *mnt;
- static char mntpath[PATH_MAX] = "";
-
- fp = setmntent(MOUNTED, "r");
- if (fp == NULL) {
- fprintf(stderr, "setmntent %s failed: %s\n",
- MOUNTED, strerror(errno));
- return NULL;
- }
-
- while (1) {
- mnt = getmntent(fp);
- if (!mnt)
- break;
-
- if (!llapi_is_lustre_mnttype(mnt->mnt_type))
- continue;
-
- /*
- * XXX: The fsname can be configed by user, it should pass into as a parameter.
- * Since we only need one client on mdt node for remote set{get}facl, it is
- * unnecessary to do the accurate match for fsname, but match ":/" temporary.
- */
- //if (strstr(mnt->mnt_fsname, ":/lustre")) {
- /* save the mountpoint dir part */
- strncpy(mntpath, mnt->mnt_dir, sizeof(mntpath));
- endmntent(fp);
- return mntpath;
- //}
- }
- endmntent(fp);
-
- return NULL;
-}
-
-int main(int argc, char **argv)
-{
- struct rmtacl_downcall_data *data;
- char procname[1024], *buf, *mntpath;
- int out_pipe[2], err_pipe[2], pid, size, buflen, fd, rc;
-
- progname = basename(argv[0]);
-
- if (argc != 7) {
- usage();
- return 1;
- }
-
- size = offsetof(struct rmtacl_downcall_data, add_buf[RMTACL_SIZE_MAX]);
- data = malloc(size);
- if (!data) {
- fprintf(stderr, "malloc %d failed\n", size);
- return 1;
- }
- memset(data, 0, size);
- data->add_magic = RMTACL_DOWNCALL_MAGIC;
- data->add_key = strtoll(argv[4], NULL, 10);
- data->add_handle = strtoul(argv[5], NULL, 10);
- buf = data->add_buf;
-
- mntpath = get_lustre_mount();
- if (!mntpath) {
- errlog(buf, MDS_ERR"(no lustre mounted on MDS)\n");
- goto downcall;
- }
-
- /* create pipe */
- if (pipe(out_pipe) < 0 || pipe(err_pipe) < 0) {
- errlog(buf, MDS_ERR"(pipe failed): %s\n", strerror(errno));
- goto downcall;
- }
-
- if ((pid = fork()) < 0) {
- errlog(buf, MDS_ERR"(fork failed): %s\n", strerror(errno));
- goto downcall;
- } else if (pid == 0) {
- uid_t uid;
- gid_t gid;
-
- close(out_pipe[0]);
- if (out_pipe[1] != STDOUT_FILENO) {
- dup2(out_pipe[1], STDOUT_FILENO);
- close(out_pipe[1]);
- }
- close(err_pipe[0]);
- if (err_pipe[1] != STDERR_FILENO) {
- dup2(err_pipe[1], STDERR_FILENO);
- close(err_pipe[1]);
- }
- close(STDIN_FILENO);
-
- if (chdir(mntpath) < 0) {
- fprintf(stderr, "chdir %s failed: %s\n",
- mntpath, strerror(errno));
- return 1;
- }
-
- gid = (gid_t)atoi(argv[2]);
- if (gid) {
- if (setgid(gid) == -1) {
- fprintf(stderr, "setgid %u failed: %s\n",
- gid, strerror(errno));
- return 1;
- }
- }
-
- uid = (uid_t)atoi(argv[1]);
- if (uid) {
- if (setuid(uid) == -1) {
- fprintf(stderr, "setuid %u failed: %s\n",
- uid, strerror(errno));
- return 1;
- }
- }
-
- execl("/bin/sh", "sh", "-c", argv[6], NULL);
- fprintf(stderr, "execl %s failed: %s\n",
- argv[6], strerror(errno));
-
- return 1;
- }
-
- /* parent process handling */
- close(out_pipe[1]);
- close(err_pipe[1]);
-
- buflen = 0;
- while (1) {
- rc = read(out_pipe[0], buf + buflen, RMTACL_SIZE_MAX - buflen);
- if (rc < 0) {
- errlog(buf, MDS_ERR"(read failed): %s\n",
- strerror(errno));
- break;
- }
- if (rc == 0)
- break;
- buflen += rc;
- if (buflen >= RMTACL_SIZE_MAX)
- break;
- }
-
- if (buflen != 0) {
- wait(&rc);
- goto downcall;
- }
-
- while (1) {
- rc = read(err_pipe[0], buf + buflen, RMTACL_SIZE_MAX - buflen);
- if (rc < 0) {
- errlog(buf, MDS_ERR"(read failed): %s\n",
- strerror(errno));
- break;
- }
- if (rc == 0)
- break;
- buflen += rc;
- if (buflen >= RMTACL_SIZE_MAX)
- break;
- }
-
- wait(&rc);
-
-downcall:
- buf[RMTACL_SIZE_MAX - 1] = 0;
- data->add_buflen = strlen(buf) + 1;
- if (getenv("L_FACL_TEST")) {
- show_result(data);
- free(data);
- return 0;
- }
-
- snprintf(procname, sizeof(procname),
- "/proc/fs/lustre/mdt/%s/rmtacl_info", argv[3]);
- fd = open(procname, O_WRONLY);
- if (fd < 0) {
- fprintf(stderr, "open %s failed: %s\n",
- procname, strerror(errno));
- free(data);
- return 1;
- }
-
- buflen = offsetof(struct rmtacl_downcall_data,
- add_buf[data->add_buflen]);
- rc = write(fd, data, buflen);
- close(fd);
- if (rc != buflen) {
- fprintf(stderr, "write %s len %d return %d: %s\n",
- procname, buflen, rc, strerror(errno));
- free(data);
- return 1;
- }
-
- free(data);
- return 0;
-}
#include <lustre/lustre_idl.h>
#include <libcfs/kp30.h>
-#define SETXID_PATHNAME "/etc/lustre/setxid.conf"
+#define PERM_PATHNAME "/etc/lustre/perm.conf"
/*
- * setxid permission file format is like this:
+ * permission file format is like this:
* {nid} {uid} {perms}
*
* '*' nid means any nid
* '*' uid means any uid
* the valid values for perms are:
- * setuid/setgid/setgrp -- enable corresponding perm
- * nosetuid/nosetgid/nosetgrp -- disable corresponding perm
+ * setuid/setgid/setgrp/rmtacl -- enable corresponding perm
+ * nosetuid/nosetgid/nosetgrp/normtacl -- disable corresponding perm
* they can be listed together, seperated by ',',
* when perm and noperm are in the same line (item), noperm is preferential,
* when they are in different lines (items), the latter is preferential,
typedef struct {
char *name;
__u32 bit;
-} setxid_perm_type_t;
+} perm_type_t;
-static setxid_perm_type_t setxid_perm_types[] = {
- { "setuid", LUSTRE_SETUID_PERM },
- { "setgid", LUSTRE_SETGID_PERM },
- { "setgrp", LUSTRE_SETGRP_PERM },
+static perm_type_t perm_types[] = {
+ { "setuid", CFS_SETUID_PERM },
+ { "setgid", CFS_SETGID_PERM },
+ { "setgrp", CFS_SETGRP_PERM },
+ { "rmtacl", CFS_RMTACL_PERM },
{ 0 }
};
-static setxid_perm_type_t setxid_noperm_types[] = {
- { "nosetuid", LUSTRE_SETUID_PERM },
- { "nosetgid", LUSTRE_SETGID_PERM },
- { "nosetgrp", LUSTRE_SETGRP_PERM },
+static perm_type_t noperm_types[] = {
+ { "nosetuid", CFS_SETUID_PERM },
+ { "nosetgid", CFS_SETGID_PERM },
+ { "nosetgrp", CFS_SETGRP_PERM },
+ { "normtacl", CFS_RMTACL_PERM },
{ 0 }
};
-int parse_setxid_perm(__u32 *perm, __u32 *noperm, char *str)
+int parse_perm(__u32 *perm, __u32 *noperm, char *str)
{
char *start, *end;
char name[64];
- setxid_perm_type_t *pt;
+ perm_type_t *pt;
*perm = 0;
*noperm = 0;
if (start >= end)
break;
strncpy(name, start, end - start);
- for (pt = setxid_perm_types; pt->name; pt++) {
+ for (pt = perm_types; pt->name; pt++) {
if (!strcasecmp(name, pt->name)) {
*perm |= pt->bit;
break;
}
if (!pt->name) {
- for (pt = setxid_noperm_types; pt->name; pt++) {
+ for (pt = noperm_types; pt->name; pt++) {
if (!strcasecmp(name, pt->name)) {
*noperm |= pt->bit;
break;
return 0;
}
-int parse_setxid_perm_line(struct identity_downcall_data *data, char *line)
+int parse_perm_line(struct identity_downcall_data *data, char *line)
{
char uid_str[256], nid_str[256], perm_str[256];
lnet_nid_t nid;
__u32 perm, noperm;
int rc, i;
- if (data->idd_nperms >= N_SETXID_PERMS_MAX) {
- errlog("setxid permission count %d > max %d\n",
- data->idd_nperms, N_SETXID_PERMS_MAX);
+ if (data->idd_nperms >= N_PERMS_MAX) {
+ errlog("permission count %d > max %d\n",
+ data->idd_nperms, N_PERMS_MAX);
return -1;
}
}
}
- if (parse_setxid_perm(&perm, &noperm, perm_str)) {
+ if (parse_perm(&perm, &noperm, perm_str)) {
errlog("invalid perm %s\n", perm_str);
return -1;
}
return 0;
}
-int get_setxid_perms(FILE *fp, struct identity_downcall_data *data)
+int get_perms(FILE *fp, struct identity_downcall_data *data)
{
char line[1024];
if (comment_line(line))
continue;
- if (parse_setxid_perm_line(data, line)) {
+ if (parse_perm_line(data, line)) {
errlog("parse line %s failed!\n", line);
return -1;
}
for (i = 0; i < data->idd_ngroups; i++)
printf("%s%u", i > 0 ? "," : "", data->idd_groups[i]);
printf("\n");
- printf("setxid permissions:\n"
+ printf("permissions:\n"
" nid\t\t\tperm\n");
for (i = 0; i < data->idd_nperms; i++) {
- struct setxid_perm_downcall_data *pdd;
+ struct perm_downcall_data *pdd;
pdd = &data->idd_perms[i];
goto downcall;
/* read permission database */
- perms_fp = fopen(SETXID_PATHNAME, "r");
+ perms_fp = fopen(PERM_PATHNAME, "r");
if (perms_fp) {
- get_setxid_perms(perms_fp, data);
+ get_perms(perms_fp, data);
fclose(perms_fp);
} else if (errno != ENOENT) {
errlog("open %s failed: %s\n",
- SETXID_PATHNAME, strerror(errno));
+ PERM_PATHNAME, strerror(errno));
}
downcall:
#endif
static int lfs_flushctx(int argc, char **argv);
static int lfs_join(int argc, char **argv);
-static int lfs_getfacl(int argc, char **argv);
-static int lfs_setfacl(int argc, char **argv);
+static int lfs_lsetfacl(int argc, char **argv);
+static int lfs_lgetfacl(int argc, char **argv);
+static int lfs_rsetfacl(int argc, char **argv);
+static int lfs_rgetfacl(int argc, char **argv);
+static int lfs_cp(int argc, char **argv);
+static int lfs_ls(int argc, char **argv);
/* all avaialable commands */
command_t cmdlist[] = {
#endif
{"flushctx", lfs_flushctx, 0, "Flush security context for current user.\n"
"usage: flushctx [-k] [mountpoint...]"},
- {"getfacl", lfs_getfacl, 0,
- "Get file access control list in remote client.\n"
- "usage: getfacl [-dRLPvh] file"},
- {"setfacl", lfs_setfacl, 0,
- "Set file access control list in remote client.\n"
- "usage: setfacl [-bkndRLPvh] [{-m|-x} acl_spec] [{-M|-X} acl_file] file"},
+ {"lsetfacl", lfs_lsetfacl, 0,
+ "Remote user setfacl for user/group on the same remote client.\n"
+ "usage: lsetfacl [-bkndRLPvh] [{-m|-x} acl_spec] [{-M|-X} acl_file] file ..."},
+ {"lgetfacl", lfs_lgetfacl, 0,
+ "Remote user getfacl for user/group on the same remote client.\n"
+ "usage: lgetfacl [-dRLPvh] file ..."},
+ {"rsetfacl", lfs_rsetfacl, 0,
+ "Remote user setfacl for user/group on other clients.\n"
+ "usage: rsetfacl [-bkndRLPvh] [{-m|-x} acl_spec] [{-M|-X} acl_file] file ..."},
+ {"rgetfacl", lfs_rgetfacl, 0,
+ "Remote user getfacl for user/group on other clients.\n"
+ "usage: rgetfacl [-dRLPvh] file ..."},
+ {"cp", lfs_cp, 0,
+ "Remote user copy files and directories.\n"
+ "usage: cp [OPTION]... [-T] SOURCE DEST\n\tcp [OPTION]... SOURCE... DIRECTORY\n\tcp [OPTION]... -t DIRECTORY SOURCE..."},
+ {"ls", lfs_ls, 0,
+ "Remote user list directory contents.\n"
+ "usage: ls [OPTION]... [FILE]..."},
{"help", Parser_help, 0, "help"},
{"exit", Parser_quit, 0, "quit"},
{"quit", 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 *fname, char *cmd)
+static int lfs_lsetfacl(int argc, char **argv)
{
- char *dname, *rpath = NULL;
- char path[PATH_MAX], cwd[PATH_MAX];
- FILE *fp;
- struct mntent *mnt;
- int i;
-
- if (argc < 2)
- return -1;
-
- /* FIXME the premise is there is no sub-mounted filesystems under this
- * mounted lustre tree. */
- strncpy(fname, argv[argc - 1], PATH_MAX);
-
- /* get path prefix */
- dname = dirname(fname);
-
- /* try to resolve the pathname into relative to the root of the mounted
- * lustre filesystem.
- */
- if (getcwd(cwd, sizeof(cwd)) == NULL) {
- fprintf(stderr, "getcwd %s failed: %s\n", cwd, strerror(errno));
- return -1;
- }
-
- if (chdir(dname) == -1) {
- fprintf(stderr, "chdir to %s failed: %s\n",
- dname, strerror(errno));
- return -1;
- }
-
- if (getcwd(path, sizeof(path)) == NULL) {
- fprintf(stderr, "getcwd %s: %s\n", path, strerror(errno));
- return -1;
- }
-
- if (chdir(cwd) == -1) {
- fprintf(stderr, "chdir back to %s: %s\n",
- cwd, strerror(errno));
- return -1;
- }
-
- strncat(path, "/", PATH_MAX);
- strncpy(fname, argv[argc - 1], PATH_MAX);
- strncat(path, basename(fname), PATH_MAX);
-
- fp = setmntent(MOUNTED, "r");
- if (fp == NULL) {
- fprintf(stderr, "setmntent %s failed: %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))) {
- rpath = path + strlen(mnt->mnt_dir);
- break;
- }
- }
- endmntent(fp);
-
- /* remove char '/' from rpath to be a relative path */
- while (rpath && *rpath == '/') rpath++;
-
- if (!rpath) {
- fprintf(stderr,
- "%s: file %s doesn't belong to a lustre file system!\n",
- argv[0], argv[argc - 1]);
- return -1;
- }
-
- for (i = 0; i < argc - 1; i++) {
- strncat(cmd, argv[i], PATH_MAX);
- strncat(cmd, " ", PATH_MAX);
- }
- strncat(cmd, *rpath ? rpath : ".", PATH_MAX);
- strncpy(fname, argv[argc - 1], sizeof(fname));
-
- return 0;
+ argv[0]++;
+ return(llapi_lsetfacl(argc, argv));
}
-static int lfs_getfacl(int argc, char **argv)
+static int lfs_lgetfacl(int argc, char **argv)
{
- char fname[PATH_MAX] = "", cmd[PATH_MAX] = "";
-
- if (acl_cmd_parse(argc, argv, fname, cmd))
- return CMD_HELP;
+ argv[0]++;
+ return(llapi_lgetfacl(argc, argv));
+}
- return llapi_getfacl(fname, cmd);
+static int lfs_rsetfacl(int argc, char **argv)
+{
+ argv[0]++;
+ return(llapi_rsetfacl(argc, argv));
}
-static int lfs_setfacl(int argc, char **argv)
+static int lfs_rgetfacl(int argc, char **argv)
{
- char fname[PATH_MAX] = "", cmd[PATH_MAX] = "";
+ argv[0]++;
+ return(llapi_rgetfacl(argc, argv));
+}
- if (acl_cmd_parse(argc, argv, fname, cmd))
- return CMD_HELP;
+static int lfs_cp(int argc, char **argv)
+{
+ return(llapi_cp(argc, argv));
+}
- return llapi_setfacl(fname, cmd);
+static int lfs_ls(int argc, char **argv)
+{
+ return(llapi_ls(argc, argv));
}
int main(int argc, char **argv)
return ret;
}
-int llapi_getfacl(char *fname, char *cmd)
+#include <pwd.h>
+#include <grp.h>
+#include <mntent.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <ctype.h>
+
+static int rmtacl_notify(int ops)
{
- struct rmtacl_ioctl_data data;
- char out[RMTACL_SIZE_MAX] = "";
- int fd, rc;
-
- data.cmd = cmd;
- data.cmd_len = strlen(cmd) + 1;
- data.res = out;
- data.res_len = sizeof(out);
-
- fd = open(fname, 0);
- if (fd == -1) {
- llapi_err(LLAPI_MSG_ERROR,"open %s failed", fname);
+ FILE *fp;
+ struct mntent *mnt;
+ int found = 0, fd, rc;
+
+ fp = setmntent(MOUNTED, "r");
+ if (fp == NULL) {
+ perror("setmntent");
return -1;
}
- rc = ioctl(fd, LL_IOC_GETFACL, &data);
- close(fd);
- if (errno == EBADE) {
- llapi_err(LLAPI_MSG_ERROR, "Please use getfacl directly!");
- rc = 1;
- } else if (rc) {
- llapi_err(LLAPI_MSG_ERROR,"getfacl %s failed", fname);
+ while (1) {
+ mnt = getmntent(fp);
+ if (!mnt)
+ break;
+
+ if (!llapi_is_lustre_mnt(mnt))
+ continue;
+
+ fd = open(mnt->mnt_dir, O_RDONLY | O_DIRECTORY);
+ if (fd < 0) {
+ perror("open");
+ return -1;
+ }
+
+ rc = ioctl(fd, LL_IOC_RMTACL, ops);
+ if (rc < 0) {
+ perror("ioctl");
+ return -1;
+ }
+
+ found++;
+ }
+ endmntent(fp);
+ return found;
+}
+
+static char *next_token(char *p, int div)
+{
+ if (p == NULL)
+ return NULL;
+
+ if (div)
+ while (*p && *p != ':' && !isspace(*p))
+ p++;
+ else
+ while (*p == ':' || isspace(*p))
+ p++;
+
+ return *p ? p : NULL;
+}
+
+static int rmtacl_name2id(char *name, int is_user)
+{
+ if (is_user) {
+ struct passwd *pw;
+
+ if ((pw = getpwnam(name)) == NULL)
+ return INVALID_ID;
+ else
+ return (int)(pw->pw_uid);
} else {
- llapi_printf(LLAPI_MSG_NORMAL, "%s", out);
+ struct group *gr;
+
+ if ((gr = getgrnam(name)) == NULL)
+ return INVALID_ID;
+ else
+ return (int)(gr->gr_gid);
}
+}
- return rc;
+static int isodigit(int c)
+{
+ return (c >= '0' && c <= '7') ? 1 : 0;
+}
+
+/*
+ * Whether the name is just digits string (uid/gid) already or not.
+ * Return value:
+ * 1: str is id
+ * 0: str is not id
+ */
+static int str_is_id(char *str)
+{
+ if (str == NULL)
+ return 0;
+
+ if (*str == '0') {
+ str++;
+ if (*str == 'x' || *str == 'X') { /* for Hex. */
+ if (!isxdigit(*(++str)))
+ return 0;
+
+ while (isxdigit(*(++str)));
+ } else if (isodigit(*str)) { /* for Oct. */
+ while (isodigit(*(++str)));
+ }
+ } else if (isdigit(*str)) { /* for Dec. */
+ while (isdigit(*(++str)));
+ }
+
+ return (*str == 0) ? 1 : 0;
}
-int llapi_setfacl(char *fname, char *cmd)
+typedef struct {
+ char *name;
+ int length;
+ int is_user;
+ int next_token;
+} rmtacl_name_t;
+
+#define RMTACL_OPTNAME(name) name, sizeof(name) - 1
+
+static rmtacl_name_t rmtacl_namelist[] = {
+ { RMTACL_OPTNAME("user:"), 1, 0 },
+ { RMTACL_OPTNAME("group:"), 0, 0 },
+ { RMTACL_OPTNAME("default:user:"), 1, 0 },
+ { RMTACL_OPTNAME("default:group:"), 0, 0 },
+ /* for --tabular option */
+ { RMTACL_OPTNAME("user"), 1, 1 },
+ { RMTACL_OPTNAME("group"), 0, 1 },
+ { 0 }
+};
+
+static int rgetfacl_output(char *str)
{
- struct rmtacl_ioctl_data data;
- char out[RMTACL_SIZE_MAX] = "";
- int fd, rc;
-
- data.cmd = cmd;
- data.cmd_len = strlen(cmd) + 1;
- data.res = out;
- data.res_len = sizeof(out);
-
- fd = open(fname, 0);
- if (fd == -1) {
- llapi_err(LLAPI_MSG_ERROR,"open %s failed", fname);
+ char *start = NULL, *end = NULL;
+ int is_user = 0, n, id;
+ char c;
+ rmtacl_name_t *rn;
+
+ if (str == NULL)
return -1;
+
+ for (rn = rmtacl_namelist; rn->name; rn++) {
+ if(strncmp(str, rn->name, rn->length) == 0) {
+ if (!rn->next_token)
+ start = str + rn->length;
+ else
+ start = next_token(str + rn->length, 0);
+ is_user = rn->is_user;
+ break;
+ }
}
- rc = ioctl(fd, LL_IOC_SETFACL, &data);
- close(fd);
- if (errno == EBADE) {
- llapi_err(LLAPI_MSG_ERROR, "Please use setfacl directly!");
- rc = 1;
- } else if (errno == EOPNOTSUPP) {
- llapi_err(LLAPI_MSG_ERROR, "setfacl: %s: %s", fname);
- rc = 1;
- } else if (rc) {
- llapi_err(LLAPI_MSG_ERROR,"setfacl %s failed", fname);
+ end = next_token(start, 1);
+ if (end == NULL || start == end) {
+ n = printf("%s", str);
+ return n;
+ }
+
+ c = *end;
+ *end = 0;
+ id = rmtacl_name2id(start, is_user);
+ if (id == INVALID_ID) {
+ if (str_is_id(start)) {
+ *end = c;
+ n = printf("%s", str);
+ } else
+ return -1;
+ } else if ((id == NOBODY_UID && is_user) ||
+ (id == NOBODY_GID && !is_user)) {
+ *end = c;
+ n = printf("%s", str);
} else {
- llapi_printf(LLAPI_MSG_NORMAL, "%s", out);
+ *end = c;
+ *start = 0;
+ n = printf("%s%d%s", str, id, end);
}
+ return n;
+}
- return rc;
+static int child_status(int status)
+{
+ return WIFEXITED(status) ? WEXITSTATUS(status) : -1;
+}
+
+static int do_rmtacl(int argc, char *argv[], int ops, int (output_func)(char *))
+{
+ pid_t pid = 0;
+ int fd[2], status;
+ FILE *fp;
+ char buf[PIPE_BUF];
+
+ if (output_func) {
+ if (pipe(fd) < 0) {
+ perror("pipe");
+ return -1;
+ }
+
+ if ((pid = fork()) < 0) {
+ perror("pipe");
+ close(fd[0]);
+ close(fd[1]);
+ return -1;
+ } else if (!pid) {
+ /* child process redirects its output. */
+ close(fd[0]);
+ close(1);
+ if (dup2(fd[1], 1) < 0) {
+ perror("dup2");
+ close(fd[1]);
+ return -1;
+ }
+ } else {
+ close(fd[1]);
+ }
+ }
+
+ if (!pid) {
+ status = rmtacl_notify(ops);
+ if (status < 0)
+ return -1;
+
+ exit(execvp(argv[0], argv));
+ }
+
+ /* the following is parent process */
+ if ((fp = fdopen(fd[0], "r")) == NULL) {
+ perror("fdopen");
+ kill(pid, SIGKILL);
+ close(fd[0]);
+ return -1;
+ }
+
+ while (fgets(buf, PIPE_BUF, fp) != NULL) {
+ if (output_func(buf) < 0)
+ fprintf(stderr, "WARNING: unexpected error!\n[%s]\n",
+ buf);
+ }
+ fclose(fp);
+ close(fd[0]);
+
+ if (waitpid(pid, &status, 0) < 0) {
+ perror("waitpid");
+ return -1;
+ }
+
+ return child_status(status);
+}
+
+int llapi_lsetfacl(int argc, char *argv[])
+{
+ return do_rmtacl(argc, argv, RMT_LSETFACL, NULL);
+}
+
+int llapi_lgetfacl(int argc, char *argv[])
+{
+ return do_rmtacl(argc, argv, RMT_LGETFACL, NULL);
+}
+
+int llapi_rsetfacl(int argc, char *argv[])
+{
+ return do_rmtacl(argc, argv, RMT_RSETFACL, NULL);
+}
+
+int llapi_rgetfacl(int argc, char *argv[])
+{
+ return do_rmtacl(argc, argv, RMT_RGETFACL, rgetfacl_output);
+}
+
+int llapi_cp(int argc, char *argv[])
+{
+ int rc;
+
+ rc = rmtacl_notify(RMT_RSETFACL);
+ if (rc < 0)
+ return -1;
+
+ exit(execvp(argv[0], argv));
+}
+
+int llapi_ls(int argc, char *argv[])
+{
+ int rc;
+
+ rc = rmtacl_notify(RMT_LGETFACL);
+ if (rc < 0)
+ return -1;
+
+ exit(execvp(argv[0], argv));
}
echo "Copying mount from local build dir to "$MDIR
cp -u ../utils/mount.lustre /sbin/.
cp -u ../utils/l_getidentity /usr/sbin/.
-cp -u ../utils/l_facl /usr/sbin/.
+cp -u ../utils/lfs /usr/sbin/.
MP="/sbin/modprobe"
MPI="$MP --ignore-install"