Whamcloud - gitweb
LU-1778 llite: fix inconsistencies of root squash feature 44/10744/4
authorGregoire Pichon <gregoire.pichon@bull.net>
Wed, 18 Jun 2014 09:18:00 +0000 (11:18 +0200)
committerOleg Drokin <oleg.drokin@intel.com>
Mon, 1 Dec 2014 04:16:00 +0000 (04:16 +0000)
Root squash exhibits inconsistent behaviour on a client when
enabled. If a file is not cached on the client, then root will get
a permission denied error when accessing the file. When
the file has recently been accessed by a regular user and is
still in cache, root will be able to access the file without error
because the permission check is only done by the client that
isn't aware of root squash.

While the only real security benefit from root squash is to deny
clients access to files owned by root itself, it also makes sense
to treat file access on the client in a consistent manner
regardless of whether the file is in cache or not.

This patch adds root squash settings to llite so that client is able
to apply root squashing when it is relevant.

Configuration of MDT root squash settings will automatically be
applied to llite config log as well.

Update cfs_str2num_check() routine by removing any modification
of the specified string parameter. Since string can come from ls_str
field of a lstr structure, this avoids inconsistent ls_len field.

Lustre-change: http://review.whamcloud.com/5700
Lustre-commit: 3064318df90ce7019b83c8a7f80e93a9634c00fa

Signed-off-by: Gregoire Pichon <gregoire.pichon@bull.net>
Change-Id: Ib94a1a4a63c62c434a76bb935faad0fbdfddfec3
Reviewed-on: http://review.whamcloud.com/10744
Tested-by: Jenkins
Tested-by: Maloo <hpdd-maloo@intel.com>
Reviewed-by: Andreas Dilger <andreas.dilger@intel.com>
14 files changed:
libcfs/libcfs/libcfs_string.c
lustre/include/lprocfs_status.h
lustre/include/obd_class.h
lustre/llite/file.c
lustre/llite/llite_internal.h
lustre/llite/llite_lib.c
lustre/llite/lproc_llite.c
lustre/mdt/mdt_handler.c
lustre/mdt/mdt_internal.h
lustre/mdt/mdt_lib.c
lustre/mdt/mdt_lproc.c
lustre/mgs/mgs_llog.c
lustre/obdclass/lprocfs_status.c
lustre/tests/conf-sanity.sh

index 8449065..15ba7da 100644 (file)
@@ -299,7 +299,6 @@ cfs_str2num_check(char *str, int nob, unsigned *num,
 {
        char    *endp;
 
-       str = cfs_trimwhite(str);
        *num = strtoul(str, &endp, 0);
        if (endp == str)
                return 0;
index 6156c08..d017696 100644 (file)
@@ -797,6 +797,12 @@ int lprocfs_obd_wr_max_pages_per_rpc(struct file *file, const char *buffer,
                                      unsigned long count, void *data);
 int lprocfs_target_rd_instance(char *page, char **start, off_t off,
                                int count, int *eof, void *data);
+struct root_squash_info;
+int lprocfs_wr_root_squash(const char *buffer, unsigned long count,
+                          struct root_squash_info *squash, char *name);
+int lprocfs_wr_nosquash_nids(const char *buffer, unsigned long count,
+                            struct root_squash_info *squash, char *name);
+
 
 /* all quota proc functions */
 extern int lprocfs_quota_rd_bunit(char *page, char **start,
index 91c83a5..2989db3 100644 (file)
@@ -2286,4 +2286,13 @@ int raw_name2idx(int hashtype, int count, const char *name, int namelen);
 /* prng.c */
 #define ll_generate_random_uuid(uuid_out) cfs_get_random_bytes(uuid_out, sizeof(class_uuid_t))
 
+/* root squash info */
+struct rw_semaphore;
+struct root_squash_info {
+       uid_t                   rsi_uid;
+       gid_t                   rsi_gid;
+       cfs_list_t              rsi_nosquash_nids;
+       struct rw_semaphore     rsi_sem;
+};
+
 #endif /* __LINUX_OBD_CLASS_H */
index e1b8620..46db441 100644 (file)
@@ -45,6 +45,7 @@
 #include <lustre_lite.h>
 #include <linux/pagemap.h>
 #include <linux/file.h>
+#include <linux/sched.h>
 #include "llite_internal.h"
 #include <lustre/ll_fiemap.h>
 
@@ -3340,8 +3341,14 @@ int ll_inode_permission(struct inode *inode, int mask, struct nameidata *nd)
 # endif
 #endif
 {
-        int rc = 0;
-        ENTRY;
+       int rc = 0;
+       struct ll_sb_info *sbi;
+       struct root_squash_info *squash;
+       struct cred *cred = NULL;
+       const struct cred *old_cred = NULL;
+       cfs_cap_t cap;
+       bool squash_id = false;
+       ENTRY;
 
 #ifdef MAY_NOT_BLOCK
        if (mask & MAY_NOT_BLOCK)
@@ -3366,11 +3373,46 @@ int ll_inode_permission(struct inode *inode, int mask, struct nameidata *nd)
        CDEBUG(D_VFSTRACE, "VFS Op:inode=%lu/%u(%p), inode mode %x mask %o\n",
               inode->i_ino, inode->i_generation, inode, inode->i_mode, mask);
 
-       if (ll_i2sbi(inode)->ll_flags & LL_SBI_RMT_CLIENT)
-               return lustre_check_remote_perm(inode, mask);
+       /* squash fsuid/fsgid if needed */
+       sbi = ll_i2sbi(inode);
+       squash = &sbi->ll_squash;
+       if (unlikely(squash->rsi_uid != 0 &&
+                    current_fsuid() == 0 &&
+                    !(sbi->ll_flags & LL_SBI_NOROOTSQUASH))) {
+                       squash_id = true;
+       }
+       if (squash_id) {
+               CDEBUG(D_OTHER, "squash creds (%d:%d)=>(%d:%d)\n",
+                      current_fsuid(), current_fsgid(),
+                      squash->rsi_uid, squash->rsi_gid);
+
+               /* update current process's credentials
+                * and FS capability */
+               cred = prepare_creds();
+               if (cred == NULL)
+                       RETURN(-ENOMEM);
+
+               cred->fsuid = squash->rsi_uid;
+               cred->fsgid = squash->rsi_gid;
+               for (cap = 0; cap < sizeof(cfs_cap_t) * 8; cap++) {
+                       if ((1 << cap) & CFS_CAP_FS_MASK)
+                               cap_lower(cred->cap_effective, cap);
+               }
+               old_cred = override_creds(cred);
+       }
+
+       ll_stats_ops_tally(sbi, LPROC_LL_INODE_PERM, 1);
 
-       ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_INODE_PERM, 1);
-       rc = ll_generic_permission(inode, mask, flags, ll_check_acl);
+       if (sbi->ll_flags & LL_SBI_RMT_CLIENT)
+               rc = lustre_check_remote_perm(inode, mask);
+       else
+               rc = ll_generic_permission(inode, mask, flags, ll_check_acl);
+
+       /* restore current process's credentials and FS capability */
+       if (squash_id) {
+               revert_creds(old_cred);
+               put_cred(cred);
+       }
 
        RETURN(rc);
 }
index 3cb7447..94b545f 100644 (file)
@@ -433,6 +433,7 @@ enum stats_track_type {
 #define LL_SBI_LAYOUT_LOCK    0x20000 /* layout lock support */
 #define LL_SBI_USER_FID2PATH  0x40000 /* allow fid2path by unprivileged users */
 #define LL_SBI_XATTR_CACHE    0x80000 /* support for xattr cache */
+#define LL_SBI_NOROOTSQUASH  0x100000 /* do not apply root squash */
 
 #define LL_SBI_FLAGS {         \
        "nolck",        \
@@ -455,6 +456,7 @@ enum stats_track_type {
        "layout",       \
        "user_fid2path",\
        "xattr",        \
+       "norootsquash", \
 }
 
 /* default value for ll_sb_info->contention_time */
@@ -551,6 +553,9 @@ struct ll_sb_info {
                                                  * clustred nfs */
         struct rmtacl_ctl_table   ll_rct;
         struct eacl_table         ll_et;
+
+       /* root squash */
+       struct root_squash_info   ll_squash;
 };
 
 #define LL_DEFAULT_MAX_RW_CHUNK      (32 * 1024 * 1024)
@@ -921,6 +926,7 @@ struct md_op_data *ll_prep_md_op_data(struct md_op_data *op_data,
 void ll_finish_md_op_data(struct md_op_data *op_data);
 int ll_get_obd_name(struct inode *inode, unsigned int cmd, unsigned long arg);
 char *ll_get_fsname(struct super_block *sb, char *buf, int buflen);
+void ll_compute_rootsquash_state(struct ll_sb_info *sbi);
 
 /* llite/llite_nfs.c */
 extern struct export_operations lustre_export_operations;
index c8fc0cc..0285f19 100644 (file)
@@ -76,14 +76,14 @@ static struct ll_sb_info *ll_init_sbi(void)
        struct ll_sb_info *sbi = NULL;
        unsigned long pages;
        unsigned long lru_page_max;
-        struct sysinfo si;
-        class_uuid_t uuid;
-        int i;
-        ENTRY;
+       struct sysinfo si;
+       class_uuid_t uuid;
+       int i;
+       ENTRY;
 
-        OBD_ALLOC(sbi, sizeof(*sbi));
-        if (!sbi)
-                RETURN(NULL);
+       OBD_ALLOC_PTR(sbi);
+       if (sbi == NULL)
+               RETURN(NULL);
 
        spin_lock_init(&sbi->ll_lock);
        mutex_init(&sbi->ll_lco.lco_lock);
@@ -145,6 +145,12 @@ static struct ll_sb_info *ll_init_sbi(void)
         cfs_atomic_set(&sbi->ll_agl_total, 0);
         sbi->ll_flags |= LL_SBI_AGL_ENABLED;
 
+       /* root squash */
+       sbi->ll_squash.rsi_uid = 0;
+       sbi->ll_squash.rsi_gid = 0;
+       CFS_INIT_LIST_HEAD(&sbi->ll_squash.rsi_nosquash_nids);
+       init_rwsem(&sbi->ll_squash.rsi_sem);
+
         RETURN(sbi);
 }
 
@@ -157,6 +163,8 @@ void ll_free_sbi(struct super_block *sb)
                spin_lock(&ll_sb_lock);
                cfs_list_del(&sbi->ll_list);
                spin_unlock(&ll_sb_lock);
+               if (!cfs_list_empty(&sbi->ll_squash.rsi_nosquash_nids))
+                       cfs_free_nidlist(&sbi->ll_squash.rsi_nosquash_nids);
                OBD_FREE(sbi, sizeof(*sbi));
        }
        EXIT;
@@ -2489,3 +2497,41 @@ void ll_dirty_page_discard_warn(struct page *page, int ioret)
        if (buf != NULL)
                free_page((unsigned long)buf);
 }
+
+/*
+ * Compute llite root squash state after a change of root squash
+ * configuration setting or add/remove of a lnet nid
+ */
+void ll_compute_rootsquash_state(struct ll_sb_info *sbi)
+{
+       struct root_squash_info *squash = &sbi->ll_squash;
+       int i;
+       bool matched;
+       lnet_process_id_t id;
+
+       /* Update norootsquash flag */
+       down_write(&squash->rsi_sem);
+       if (cfs_list_empty(&squash->rsi_nosquash_nids))
+               sbi->ll_flags &= ~LL_SBI_NOROOTSQUASH;
+       else {
+               /* Do not apply root squash as soon as one of our NIDs is
+                * in the nosquash_nids list */
+               matched = false;
+               i = 0;
+               while (LNetGetId(i++, &id) != -ENOENT) {
+                       if (LNET_NETTYP(LNET_NIDNET(id.nid)) == LOLND)
+                               continue;
+                       if (cfs_match_nid(id.nid, &squash->rsi_nosquash_nids)) {
+                               matched = true;
+                               break;
+                       }
+               }
+               if (matched)
+                       sbi->ll_flags |= LL_SBI_NOROOTSQUASH;
+               else
+                       sbi->ll_flags &= ~LL_SBI_NOROOTSQUASH;
+       }
+       up_write(&squash->rsi_sem);
+}
+
+
index 3c1489f..86d8119 100644 (file)
@@ -778,6 +778,67 @@ static int ll_rd_sbi_flags(char *page, char **start, off_t off,
        return rc;
 }
 
+static int ll_rd_root_squash(char *page, char **start, off_t off,
+                            int count, int *eof, void *data)
+{
+       struct super_block *sb = data;
+       struct ll_sb_info *sbi = ll_s2sbi(sb);
+       struct root_squash_info *squash = &sbi->ll_squash;
+
+       return snprintf(page, count, "%u:%u\n",
+                       squash->rsi_uid, squash->rsi_gid);
+}
+
+static int ll_wr_root_squash(struct file *file, const char *buffer,
+                            unsigned long count, void *data)
+{
+       struct super_block *sb = data;
+       struct ll_sb_info *sbi = ll_s2sbi(sb);
+       struct root_squash_info *squash = &sbi->ll_squash;
+
+       return lprocfs_wr_root_squash(buffer, count, squash,
+                                     ll_get_fsname(sb, NULL, 0));
+}
+
+static int ll_rd_nosquash_nids(char *page, char **start, off_t off,
+                              int count, int *eof, void *data)
+{
+       struct super_block *sb = data;
+       struct ll_sb_info *sbi = ll_s2sbi(sb);
+       struct root_squash_info *squash = &sbi->ll_squash;
+       int rc;
+
+       down_read(&squash->rsi_sem);
+       if (!cfs_list_empty(&squash->rsi_nosquash_nids)) {
+               rc = cfs_print_nidlist(page, count,
+                                       &squash->rsi_nosquash_nids);
+               rc += snprintf(page + rc, count - rc, "\n");
+       } else {
+               rc = snprintf(page, count, "NONE\n");
+       }
+       up_read(&squash->rsi_sem);
+
+       return rc;
+}
+
+static int ll_wr_nosquash_nids(struct file *file, const char *buffer,
+                              unsigned long count, void *data)
+{
+       struct super_block *sb = data;
+       struct ll_sb_info *sbi = ll_s2sbi(sb);
+       struct root_squash_info *squash = &sbi->ll_squash;
+       int rc;
+
+       rc = lprocfs_wr_nosquash_nids(buffer, count, squash,
+                                     ll_get_fsname(sb, NULL, 0));
+       if (rc < 0)
+               return rc;
+
+       ll_compute_rootsquash_state(sbi);
+
+       return rc;
+}
+
 static struct lprocfs_vars lprocfs_llite_obd_vars[] = {
         { "uuid",         ll_rd_sb_uuid,          0, 0 },
         //{ "mntpt_path",   ll_rd_path,             0, 0 },
@@ -810,6 +871,8 @@ static struct lprocfs_vars lprocfs_llite_obd_vars[] = {
         { "max_easize",       ll_rd_maxea_size, 0, 0 },
        { "sbi_flags",        ll_rd_sbi_flags, 0, 0 },
        { "xattr_cache",      ll_rd_xattr_cache, ll_wr_xattr_cache, 0 },
+       { "root_squash",      ll_rd_root_squash, ll_wr_root_squash, 0 },
+       { "nosquash_nids",    ll_rd_nosquash_nids, ll_wr_nosquash_nids, 0 },
         { 0 }
 };
 
index 45b174e..7a77d22 100644 (file)
@@ -4878,12 +4878,7 @@ static void mdt_fini(const struct lu_env *env, struct mdt_device *m)
 
        mdt_quota_fini(env, m);
 
-        cfs_free_nidlist(&m->mdt_nosquash_nids);
-        if (m->mdt_nosquash_str) {
-                OBD_FREE(m->mdt_nosquash_str, m->mdt_nosquash_strlen);
-                m->mdt_nosquash_str = NULL;
-                m->mdt_nosquash_strlen = 0;
-        }
+       cfs_free_nidlist(&m->mdt_squash.rsi_nosquash_nids);
 
        next->md_ops->mdo_iocontrol(env, next, OBD_IOC_PAUSE_LFSCK, 0, NULL);
 
@@ -5002,12 +4997,10 @@ static int mdt_init0(const struct lu_env *env, struct mdt_device *m,
         m->mdt_capa_timeout = CAPA_TIMEOUT;
         m->mdt_capa_alg = CAPA_HMAC_ALG_SHA1;
         m->mdt_ck_timeout = CAPA_KEY_TIMEOUT;
-        m->mdt_squash_uid = 0;
-        m->mdt_squash_gid = 0;
-        CFS_INIT_LIST_HEAD(&m->mdt_nosquash_nids);
-        m->mdt_nosquash_str = NULL;
-        m->mdt_nosquash_strlen = 0;
-       init_rwsem(&m->mdt_squash_sem);
+       m->mdt_squash.rsi_uid = 0;
+       m->mdt_squash.rsi_gid = 0;
+       CFS_INIT_LIST_HEAD(&m->mdt_squash.rsi_nosquash_nids);
+       init_rwsem(&m->mdt_squash.rsi_sem);
        spin_lock_init(&m->mdt_osfs_lock);
        m->mdt_osfs_age = cfs_time_shift_64(-1000);
        m->mdt_enable_remote_dir = 0;
index a82526d..a9f0c07 100644 (file)
@@ -224,12 +224,7 @@ struct mdt_device {
        spinlock_t                 mdt_osfs_lock;
 
         /* root squash */
-        uid_t                      mdt_squash_uid;
-        gid_t                      mdt_squash_gid;
-        cfs_list_t                 mdt_nosquash_nids;
-        char                      *mdt_nosquash_str;
-        int                        mdt_nosquash_strlen;
-       struct rw_semaphore        mdt_squash_sem;
+       struct root_squash_info    mdt_squash;
 
         int                        mdt_sec_level;
         struct rename_stats        mdt_rename_stats;
index 09cee2c..703564b 100644 (file)
@@ -95,28 +95,28 @@ static int match_nosquash_list(struct rw_semaphore *sem,
 static int mdt_root_squash(struct mdt_thread_info *info, lnet_nid_t peernid)
 {
        struct lu_ucred *ucred = mdt_ucred(info);
+       struct root_squash_info *squash = &info->mti_mdt->mdt_squash;
        ENTRY;
 
        LASSERT(ucred != NULL);
-       if (!info->mti_mdt->mdt_squash_uid || ucred->uc_fsuid)
+       if (!squash->rsi_uid || ucred->uc_fsuid)
                RETURN(0);
 
-        if (match_nosquash_list(&info->mti_mdt->mdt_squash_sem,
-                                &info->mti_mdt->mdt_nosquash_nids,
-                                peernid)) {
-                CDEBUG(D_OTHER, "%s is in nosquash_nids list\n",
-                       libcfs_nid2str(peernid));
-                RETURN(0);
-        }
+       if (match_nosquash_list(&squash->rsi_sem,
+                               &squash->rsi_nosquash_nids,
+                               peernid)) {
+               CDEBUG(D_OTHER, "%s is in nosquash_nids list\n",
+                      libcfs_nid2str(peernid));
+               RETURN(0);
+       }
 
        CDEBUG(D_OTHER, "squash req from %s, (%d:%d/%x)=>(%d:%d/%x)\n",
               libcfs_nid2str(peernid),
               ucred->uc_fsuid, ucred->uc_fsgid, ucred->uc_cap,
-              info->mti_mdt->mdt_squash_uid, info->mti_mdt->mdt_squash_gid,
-              0);
+              squash->rsi_uid, squash->rsi_gid, 0);
 
-       ucred->uc_fsuid = info->mti_mdt->mdt_squash_uid;
-       ucred->uc_fsgid = info->mti_mdt->mdt_squash_gid;
+       ucred->uc_fsuid = squash->rsi_uid;
+       ucred->uc_fsgid = squash->rsi_gid;
        ucred->uc_cap = 0;
        ucred->uc_suppgids[0] = -1;
        ucred->uc_suppgids[1] = -1;
index 755c63d..b1315d0 100644 (file)
@@ -681,164 +681,58 @@ static int lprocfs_wr_cos(struct file *file, const char *buffer,
         return count;
 }
 
-static int lprocfs_rd_root_squash(char *page, char **start, off_t off,
-                                  int count, int *eof, void *data)
+static int lprocfs_rd_mdt_root_squash(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 obd_device *obd = data;
+       struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
+       struct root_squash_info *squash = &mdt->mdt_squash;
 
-        return snprintf(page, count, "%u:%u\n", mdt->mdt_squash_uid,
-                        mdt->mdt_squash_gid);
+       return snprintf(page, count, "%u:%u\n", squash->rsi_uid,
+                       squash->rsi_gid);
 }
 
-static int safe_strtoul(const char *str, char **endp, unsigned long *res)
+static int lprocfs_wr_mdt_root_squash(struct file *file, const char *buffer,
+                                     unsigned long count, void *data)
 {
-        char n[24];
-
-        *res = simple_strtoul(str, endp, 0);
-        if (str == *endp)
-                return 1;
+       struct obd_device *obd = data;
+       struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
+       struct root_squash_info *squash = &mdt->mdt_squash;
 
-        sprintf(n, "%lu", *res);
-        if (strncmp(n, str, *endp - str))
-                /* overflow */
-                return 1;
-        return 0;
+       return lprocfs_wr_root_squash(buffer, count, squash,
+                                     mdt_obd_name(mdt));
 }
 
-static int lprocfs_wr_root_squash(struct file *file, const char *buffer,
-                                 unsigned long count, void *data)
+static int lprocfs_rd_mdt_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 root_squash_info *squash = &mdt->mdt_squash;
        int rc;
-       char kernbuf[50], *tmp, *end, *errmsg;
-       unsigned long uid, gid;
-       int nouid, nogid;
-       ENTRY;
 
-       if (count >= sizeof(kernbuf)) {
-               errmsg = "string too long";
-               GOTO(failed, rc = -EINVAL);
-       }
-       if (copy_from_user(kernbuf, buffer, count)) {
-               errmsg = "bad address";
-               GOTO(failed, rc = -EFAULT);
-       }
-       kernbuf[count] = '\0';
-
-       nouid = nogid = 0;
-       if (safe_strtoul(buffer, &tmp, &uid)) {
-               uid = mdt->mdt_squash_uid;
-               nouid = 1;
-       }
-
-       /* skip ':' */
-       if (*tmp == ':') {
-               tmp++;
-               if (safe_strtoul(tmp, &end, &gid)) {
-                       gid = mdt->mdt_squash_gid;
-                       nogid = 1;
-               }
+       down_read(&squash->rsi_sem);
+       if (!cfs_list_empty(&squash->rsi_nosquash_nids)) {
+               rc = cfs_print_nidlist(page, count,
+                                      &squash->rsi_nosquash_nids);
+               rc += snprintf(page + rc, count - rc, "\n");
        } else {
-               gid = mdt->mdt_squash_gid;
-               nogid = 1;
-       }
-
-       mdt->mdt_squash_uid = uid;
-       mdt->mdt_squash_gid = gid;
-
-       if (nouid && nogid) {
-               errmsg = "needs uid:gid format";
-               GOTO(failed, rc = -EINVAL);
+               rc = snprintf(page, count, "NONE\n");
        }
+       up_read(&squash->rsi_sem);
 
-       LCONSOLE_INFO("%s: root_squash is set to %u:%u\n",
-                     mdt_obd_name(mdt),
-                     mdt->mdt_squash_uid,  mdt->mdt_squash_gid);
-       RETURN(count);
-
-failed:
-       CWARN("%s: failed to set root_squash to \"%s\", %s: rc %d\n",
-             mdt_obd_name(mdt), buffer, errmsg, rc);
-       RETURN(rc);
+       return rc;
 }
 
-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);
-
-        if (mdt->mdt_nosquash_str)
-                return snprintf(page, count, "%s\n", mdt->mdt_nosquash_str);
-        return snprintf(page, count, "NONE\n");
-}
-
-static int lprocfs_wr_nosquash_nids(struct file *file, const char *buffer,
-                                   unsigned long count, void *data)
+static int lprocfs_wr_mdt_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);
-       int rc;
-       char *kernbuf, *errmsg;
-       cfs_list_t tmp;
-       ENTRY;
-
-       OBD_ALLOC(kernbuf, count + 1);
-       if (kernbuf == NULL) {
-               errmsg = "no memory";
-               GOTO(failed, rc = -ENOMEM);
-       }
-       if (copy_from_user(kernbuf, buffer, count)) {
-               errmsg = "bad address";
-               GOTO(failed, rc = -EFAULT);
-       }
-       kernbuf[count] = '\0';
-
-       if (!strcmp(kernbuf, "NONE") || !strcmp(kernbuf, "clear")) {
-               /* empty string is special case */
-               down_write(&mdt->mdt_squash_sem);
-               if (!cfs_list_empty(&mdt->mdt_nosquash_nids)) {
-                       cfs_free_nidlist(&mdt->mdt_nosquash_nids);
-                       OBD_FREE(mdt->mdt_nosquash_str,
-                                mdt->mdt_nosquash_strlen);
-                       mdt->mdt_nosquash_str = NULL;
-                       mdt->mdt_nosquash_strlen = 0;
-               }
-               up_write(&mdt->mdt_squash_sem);
-               LCONSOLE_INFO("%s: nosquash_nids is cleared\n",
-                             mdt_obd_name(mdt));
-               OBD_FREE(kernbuf, count + 1);
-               RETURN(count);
-       }
+       struct root_squash_info *squash = &mdt->mdt_squash;
 
-       CFS_INIT_LIST_HEAD(&tmp);
-       if (cfs_parse_nidlist(kernbuf, count, &tmp) <= 0) {
-               errmsg = "can't parse";
-               GOTO(failed, rc = -EINVAL);
-       }
-
-       down_write(&mdt->mdt_squash_sem);
-       if (!cfs_list_empty(&mdt->mdt_nosquash_nids)) {
-               cfs_free_nidlist(&mdt->mdt_nosquash_nids);
-               OBD_FREE(mdt->mdt_nosquash_str, mdt->mdt_nosquash_strlen);
-       }
-       mdt->mdt_nosquash_str = kernbuf;
-       mdt->mdt_nosquash_strlen = count + 1;
-       cfs_list_splice(&tmp, &mdt->mdt_nosquash_nids);
-
-       LCONSOLE_INFO("%s: nosquash_nids is set to %s\n",
-                     mdt_obd_name(mdt), kernbuf);
-       up_write(&mdt->mdt_squash_sem);
-       RETURN(count);
-
-failed:
-       CWARN("%s: failed to set nosquash_nids to \"%s\", %s: rc %d\n",
-             mdt_obd_name(mdt), kernbuf, errmsg, rc);
-       if (kernbuf)
-               OBD_FREE(kernbuf, count + 1);
-       RETURN(rc);
+       return lprocfs_wr_nosquash_nids(buffer, count, squash,
+                                       mdt_obd_name(mdt));
 }
 
 static int lprocfs_rd_mdt_som(char *page, char **start, off_t off,
@@ -998,11 +892,11 @@ static struct lprocfs_vars lprocfs_mdt_obd_vars[] = {
                                        NULL, NULL, 0 },
        { "commit_on_sharing",          lprocfs_rd_cos, lprocfs_wr_cos,
                                        NULL, NULL, 0 },
-       { "root_squash",                lprocfs_rd_root_squash,
-                                       lprocfs_wr_root_squash,
+       { "root_squash",                lprocfs_rd_mdt_root_squash,
+                                       lprocfs_wr_mdt_root_squash,
                                        NULL, NULL, 0 },
-       { "nosquash_nids",              lprocfs_rd_nosquash_nids,
-                                       lprocfs_wr_nosquash_nids,
+       { "nosquash_nids",              lprocfs_rd_mdt_nosquash_nids,
+                                       lprocfs_wr_mdt_nosquash_nids,
                                        NULL, NULL, 0 },
        { "som",                        lprocfs_rd_mdt_som,
                                        lprocfs_wr_mdt_som,
index 02b6d90..0c49f67 100644 (file)
@@ -3402,9 +3402,22 @@ static int mgs_write_log_param(const struct lu_env *env,
                if (rc)
                        GOTO(end, rc);
 
-                CDEBUG(D_MGS, "%.3s param %s\n", ptr, ptr + 4);
+               /* Forbid direct update of llite root squash parameters.
+                * These parameters are indirectly set via the MDT settings.
+                * See (LU-1778) */
+               if ((class_match_param(ptr, PARAM_LLITE, &tmp) == 0) &&
+                   ((memcmp(tmp, "root_squash=", 12) == 0) ||
+                    (memcmp(tmp, "nosquash_nids=", 14) == 0))) {
+                       LCONSOLE_ERROR("%s: root squash parameters can only "
+                               "be updated through MDT component\n",
+                               mti->mti_fsname);
+                       name_destroy(&cname);
+                       GOTO(end, rc = -EINVAL);
+               }
+
+               CDEBUG(D_MGS, "%.3s param %s\n", ptr, ptr + 4);
 
-                /* Modify client */
+               /* Modify client */
                rc = name_create(&logname, mti->mti_fsname, "-client");
                if (rc) {
                        name_destroy(&cname);
@@ -3440,13 +3453,13 @@ static int mgs_write_log_param(const struct lu_env *env,
                                }
                        }
                }
-                name_destroy(&logname);
-                name_destroy(&cname);
-                GOTO(end, rc);
-        }
+               name_destroy(&logname);
+               name_destroy(&cname);
+               GOTO(end, rc);
+       }
 
-        /* All mdt. params in proc */
-        if (class_match_param(ptr, PARAM_MDT, NULL) == 0) {
+       /* All mdt. params in proc */
+       if (class_match_param(ptr, PARAM_MDT, &tmp) == 0) {
                 int i;
                 __u32 idx;
 
@@ -3472,20 +3485,56 @@ static int mgs_write_log_param(const struct lu_env *env,
                                        goto active_err;
                                rc = mgs_wlp_lcfg(env, mgs, fsdb, mti,
                                                  logname, &mgi->mgi_bufs,
-                                                  logname, ptr);
-                                name_destroy(&logname);
-                                if (rc)
-                                        goto active_err;
-                        }
-                } else {
+                                                 logname, ptr);
+                               name_destroy(&logname);
+                               if (rc)
+                                       goto active_err;
+                       }
+               } else {
+                       if ((memcmp(tmp, "root_squash=", 12) == 0) ||
+                           (memcmp(tmp, "nosquash_nids=", 14) == 0)) {
+                               LCONSOLE_ERROR("%s: root squash parameters "
+                                       "cannot be applied to a single MDT\n",
+                                       mti->mti_fsname);
+                               GOTO(end, rc = -EINVAL);
+                       }
                        rc = mgs_wlp_lcfg(env, mgs, fsdb, mti,
                                          mti->mti_svname, &mgi->mgi_bufs,
-                                          mti->mti_svname, ptr);
-                        if (rc)
-                                goto active_err;
-                }
-                GOTO(end, rc);
-        }
+                                         mti->mti_svname, ptr);
+                       if (rc)
+                               goto active_err;
+               }
+
+               /* root squash settings are also applied to llite
+                * config log (see LU-1778) */
+               if (rc == 0 &&
+                   ((memcmp(tmp, "root_squash=", 12) == 0) ||
+                    (memcmp(tmp, "nosquash_nids=", 14) == 0))) {
+                       char *cname;
+                       char *ptr2;
+
+                       rc = name_create(&cname, mti->mti_fsname, "-client");
+                       if (rc)
+                               GOTO(end, rc);
+                       rc = name_create(&logname, mti->mti_fsname, "-client");
+                       if (rc) {
+                               name_destroy(&cname);
+                               GOTO(end, rc);
+                       }
+                       rc = name_create(&ptr2, PARAM_LLITE, tmp);
+                       if (rc) {
+                               name_destroy(&cname);
+                               name_destroy(&logname);
+                               GOTO(end, rc);
+                       }
+                       rc = mgs_wlp_lcfg(env, mgs, fsdb, mti, logname,
+                                         &mgi->mgi_bufs, cname, ptr2);
+                       name_destroy(&ptr2);
+                       name_destroy(&logname);
+                       name_destroy(&cname);
+               }
+               GOTO(end, rc);
+       }
 
        /* All mdd., ost. and osd. params in proc */
        if ((class_match_param(ptr, PARAM_MDD, NULL) == 0) ||
index a352c55..04d978b 100644 (file)
@@ -2699,6 +2699,138 @@ int lprocfs_obd_rd_max_pages_per_rpc(char *page, char **start, off_t off,
 }
 EXPORT_SYMBOL(lprocfs_obd_rd_max_pages_per_rpc);
 
+int lprocfs_wr_root_squash(const char __user *buffer, unsigned long count,
+                          struct root_squash_info *squash, char *name)
+{
+       int rc;
+       char kernbuf[64], *tmp, *errmsg;
+       unsigned long uid, gid;
+       ENTRY;
+
+       if (count >= sizeof(kernbuf)) {
+               errmsg = "string too long";
+               GOTO(failed_noprint, rc = -EINVAL);
+       }
+       if (copy_from_user(kernbuf, buffer, count)) {
+               errmsg = "bad address";
+               GOTO(failed_noprint, rc = -EFAULT);
+       }
+       kernbuf[count] = '\0';
+
+       /* look for uid gid separator */
+       tmp = strchr(kernbuf, ':');
+       if (tmp == NULL) {
+               errmsg = "needs uid:gid format";
+               GOTO(failed, rc = -EINVAL);
+       }
+       *tmp = '\0';
+       tmp++;
+
+       /* parse uid */
+       if (kstrtoul(kernbuf, 0, &uid) != 0) {
+               errmsg = "bad uid";
+               GOTO(failed, rc = -EINVAL);
+       }
+
+       /* parse gid */
+       if (kstrtoul(tmp, 0, &gid) != 0) {
+               errmsg = "bad gid";
+               GOTO(failed, rc = -EINVAL);
+       }
+
+       squash->rsi_uid = uid;
+       squash->rsi_gid = gid;
+
+       LCONSOLE_INFO("%s: root_squash is set to %u:%u\n",
+                     name, squash->rsi_uid, squash->rsi_gid);
+       RETURN(count);
+
+failed:
+       if (tmp != NULL) {
+               tmp--;
+               *tmp = ':';
+       }
+       CWARN("%s: failed to set root_squash to \"%s\", %s, rc = %d\n",
+             name, kernbuf, errmsg, rc);
+       RETURN(rc);
+failed_noprint:
+       CWARN("%s: failed to set root_squash due to %s, rc = %d\n",
+             name, errmsg, rc);
+       RETURN(rc);
+}
+EXPORT_SYMBOL(lprocfs_wr_root_squash);
+
+
+int lprocfs_wr_nosquash_nids(const char __user *buffer, unsigned long count,
+                            struct root_squash_info *squash, char *name)
+{
+       int rc;
+       char *kernbuf = NULL;
+       char *errmsg;
+       cfs_list_t tmp;
+       ENTRY;
+
+       if (count > 4096) {
+               errmsg = "string too long";
+               GOTO(failed, rc = -EINVAL);
+       }
+
+       OBD_ALLOC(kernbuf, count + 1);
+       if (kernbuf == NULL) {
+               errmsg = "no memory";
+               GOTO(failed, rc = -ENOMEM);
+       }
+       if (copy_from_user(kernbuf, buffer, count)) {
+               errmsg = "bad address";
+               GOTO(failed, rc = -EFAULT);
+       }
+       kernbuf[count] = '\0';
+
+       if (count > 0 && kernbuf[count - 1] == '\n')
+               kernbuf[count - 1] = '\0';
+
+       if (strcmp(kernbuf, "NONE") == 0 || strcmp(kernbuf, "clear") == 0) {
+               /* empty string is special case */
+               down_write(&squash->rsi_sem);
+               if (!cfs_list_empty(&squash->rsi_nosquash_nids))
+                       cfs_free_nidlist(&squash->rsi_nosquash_nids);
+               up_write(&squash->rsi_sem);
+               LCONSOLE_INFO("%s: nosquash_nids is cleared\n", name);
+               OBD_FREE(kernbuf, count + 1);
+               RETURN(count);
+       }
+
+       CFS_INIT_LIST_HEAD(&tmp);
+       if (cfs_parse_nidlist(kernbuf, count, &tmp) <= 0) {
+               errmsg = "can't parse";
+               GOTO(failed, rc = -EINVAL);
+       }
+       LCONSOLE_INFO("%s: nosquash_nids set to %s\n",
+                     name, kernbuf);
+       OBD_FREE(kernbuf, count + 1);
+       kernbuf = NULL;
+
+       down_write(&squash->rsi_sem);
+       if (!cfs_list_empty(&squash->rsi_nosquash_nids))
+               cfs_free_nidlist(&squash->rsi_nosquash_nids);
+       cfs_list_splice(&tmp, &squash->rsi_nosquash_nids);
+       up_write(&squash->rsi_sem);
+
+       RETURN(count);
+
+failed:
+       if (kernbuf) {
+               CWARN("%s: failed to set nosquash_nids to \"%s\", %s rc = %d\n",
+                     name, kernbuf, errmsg, rc);
+               OBD_FREE(kernbuf, count + 1);
+       } else {
+               CWARN("%s: failed to set nosquash_nids due to %s rc = %d\n",
+                     name, errmsg, rc);
+       }
+       RETURN(rc);
+}
+EXPORT_SYMBOL(lprocfs_wr_nosquash_nids);
+
 #ifdef HAVE_SERVER_SUPPORT
 int lprocfs_target_rd_instance(char *page, char **start, off_t off,
                                int count, int *eof, void *data)
index a4bf2a1..6a65d34 100644 (file)
@@ -2662,16 +2662,30 @@ run_test 42 "allow client/server mount/unmount with invalid config param"
 
 test_43() {
        [ $UID -ne 0 -o $RUNAS_ID -eq 0 ] && skip_env "run as root"
+
+       ID1=${ID1:-501}
+       USER1=$(cat /etc/passwd | grep :$ID1:$ID1: | cut -d: -f1)
+       [ -z "$USER1" ] && skip_env "missing user with uid=$ID1 gid=$ID1" &&
+               return
+
        setup
        chmod ugo+x $DIR || error "chmod 0 failed"
        set_conf_param_and_check mds                                    \
                "lctl get_param -n mdt.$FSNAME-MDT0000.root_squash"     \
                "$FSNAME.mdt.root_squash"                               \
                "0:0"
+       wait_update $HOSTNAME                                           \
+               "lctl get_param -n llite.${FSNAME}*.root_squash"        \
+               "0:0" ||
+               error "check llite root_squash failed!"
        set_conf_param_and_check mds                                    \
                "lctl get_param -n mdt.$FSNAME-MDT0000.nosquash_nids"   \
                "$FSNAME.mdt.nosquash_nids"                             \
                "NONE"
+       wait_update $HOSTNAME                                           \
+               "lctl get_param -n llite.${FSNAME}*.nosquash_nids"      \
+               "NONE" ||
+               error "check llite nosquash_nids failed!"
 
     #
     # create set of test files
@@ -2687,6 +2701,10 @@ test_43() {
     chmod go-rwx $DIR/$tdir-rootdir   || error "chmod 3 failed"
     touch $DIR/$tdir-rootdir/tfile-1  || error "touch failed"
 
+       echo "777" > $DIR/$tfile-user1file || error "write 7 failed"
+       chmod go-rw $DIR/$tfile-user1file  || error "chmod 7 failed"
+       chown $ID1.$ID1 $DIR/$tfile-user1file || error "chown failed"
+
        #
        # check root_squash:
        #   set root squash UID:GID to RUNAS_ID
@@ -2696,6 +2714,10 @@ test_43() {
                "lctl get_param -n mdt.$FSNAME-MDT0000.root_squash"     \
                "$FSNAME.mdt.root_squash"                               \
                "$RUNAS_ID:$RUNAS_ID"
+       wait_update $HOSTNAME                                           \
+               "lctl get_param -n llite.${FSNAME}*.root_squash"        \
+               "$RUNAS_ID:$RUNAS_ID" ||
+               error "check llite root_squash failed!"
 
     ST=$(stat -c "%n: owner uid %u (%A)" $DIR/$tfile-userfile)
     dd if=$DIR/$tfile-userfile 1>/dev/null 2>/dev/null || \
@@ -2703,7 +2725,7 @@ test_43() {
     echo "$ST: root read permission is granted - ok"
 
     echo "444" | \
-    dd conv=notrunc if=$DIR/$tfile-userfile 1>/dev/null 2>/dev/null || \
+    dd conv=notrunc of=$DIR/$tfile-userfile 1>/dev/null 2>/dev/null || \
         error "$ST: root write permission is denied"
     echo "$ST: root write permission is granted - ok"
 
@@ -2726,6 +2748,31 @@ test_43() {
         error "$ST: root create permission is granted"
     echo "$ST: root create permission is denied - ok"
 
+
+       # LU-1778
+       # check root_squash is enforced independently
+       # of client cache content
+       #
+       # access file by USER1, keep access open
+       # root should be denied access to user file
+
+       runas -u $ID1 tail -f $DIR/$tfile-user1file 1>/dev/null 2>&1 &
+       pid=$!
+       sleep 1
+
+       ST=$(stat -c "%n: owner uid %u (%A)" $DIR/$tfile-user1file)
+       dd if=$DIR/$tfile-user1file 1>/dev/null 2>&1 &&
+           { kill $pid; error "$ST: root read permission is granted"; }
+       echo "$ST: root read permission is denied - ok"
+
+       echo "777" | \
+       dd conv=notrunc of=$DIR/$tfile-user1file 1>/dev/null 2>&1 &&
+           { kill $pid; error "$ST: root write permission is granted"; }
+       echo "$ST: root write permission is denied - ok"
+
+       kill $pid
+       wait $pid
+
        #
        # check nosquash_nids:
        #   put client's NID into nosquash_nids list,
@@ -2738,6 +2785,10 @@ test_43() {
                "lctl get_param -n mdt.$FSNAME-MDT0000.nosquash_nids"   \
                "$FSNAME-MDTall.mdt.nosquash_nids"                      \
                "$NIDLIST"
+       wait_update $HOSTNAME                                           \
+               "lctl get_param -n llite.${FSNAME}*.nosquash_nids"      \
+               "$NIDLIST" ||
+               error "check llite nosquash_nids failed!"
 
     ST=$(stat -c "%n: owner uid %u (%A)" $DIR/$tfile-rootfile)
     dd if=$DIR/$tfile-rootfile 1>/dev/null 2>/dev/null || \