+static int lprocfs_rd_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);
+ ENTRY;
+
+ return snprintf(page, count, "%u:%u\n", mdt->mdt_squash_uid,
+ mdt->mdt_squash_gid);
+}
+
+static int safe_strtoul(const char *str, char **endp, unsigned long *res)
+{
+ char n[24];
+
+ *res = simple_strtoul(str, endp, 0);
+ if (str == *endp)
+ return 1;
+
+ sprintf(n, "%lu", *res);
+ if (strncmp(n, str, *endp - str))
+ /* overflow */
+ return 1;
+ return 0;
+}
+
+static int lprocfs_wr_root_squash(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 kernbuf[50], *tmp, *end;
+ unsigned long uid, gid;
+ int nouid, nogid;
+ ENTRY;
+
+ if (count > (sizeof(kernbuf) - 1) ||
+ copy_from_user(kernbuf, buffer, count)) {
+ CWARN("%s: can't copy string to kernel space, "
+ "uid:gid is expected, "
+ "continue with %u:%u, "
+ "there will be 0:0 on MDS restart\n",
+ obd->obd_name, mdt->mdt_squash_uid,
+ mdt->mdt_squash_gid);
+ RETURN(count);
+ }
+
+ if (copy_from_user(kernbuf, buffer, count))
+ RETURN(-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;
+ }
+ } else {
+ gid = mdt->mdt_squash_gid;
+ nogid = 1;
+ }
+
+ mdt->mdt_squash_uid = uid;
+ mdt->mdt_squash_gid = gid;
+
+ if (nouid || nogid)
+ CWARN("%s: can't parse \"\%s\", uid:gid is expected, "
+ "continue with %u:%u, "
+ "there will be %u:%u on MDS restart\n",
+ obd->obd_name,
+ buffer, mdt->mdt_squash_uid, mdt->mdt_squash_gid,
+ nouid ? 0 : mdt->mdt_squash_uid,
+ nogid ? 0 : mdt->mdt_squash_gid);
+ else
+ LCONSOLE_INFO("%s: root_squash is set to %u:%u\n",
+ obd->obd_name,
+ mdt->mdt_squash_uid, mdt->mdt_squash_gid);
+ 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);
+
+ 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)
+{
+ struct obd_device *obd = data;
+ struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
+ int rc;
+ char *new;
+ struct list_head tmp;
+ ENTRY;
+
+ /* copy to kernel space */
+ OBD_ALLOC(new, count + 1);
+ if (new == 0)
+ GOTO(failed, rc = -ENOMEM);
+
+ if (copy_from_user(new, buffer, count))
+ GOTO(failed, rc = -EFAULT);
+
+ new[count] = 0;
+ if (strlen(new) != count)
+ GOTO(failed, rc = -EINVAL);
+
+ if (!strcmp(new, "NONE") || !strcmp(new, "clear")) {
+ /* empty string is special case */
+ down_write(&mdt->mdt_squash_sem);
+ if (!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",
+ obd->obd_name);
+ OBD_FREE(new, count + 1);
+ RETURN(0);
+ }
+
+ CFS_INIT_LIST_HEAD(&tmp);
+ if (cfs_parse_nidlist(new, count, &tmp) <= 0)
+ GOTO(failed, rc = -EINVAL);
+
+ down_write(&mdt->mdt_squash_sem);
+ if (!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 = new;
+ mdt->mdt_nosquash_strlen = count + 1;
+ list_splice(&tmp, &mdt->mdt_nosquash_nids);
+
+ LCONSOLE_INFO("%s: nosquash_nids is set to %s\n", obd->obd_name, new);
+ up_write(&mdt->mdt_squash_sem);
+ RETURN(count);
+
+ failed:
+ CWARN("%s: failed to set nosquash_nids (rc %d), "
+ "on MDS restart we will try to set it again, "
+ "continue with current nosquash_nids\n",
+ obd->obd_name, rc);
+ if (new)
+ OBD_FREE(new, count + 1);
+ RETURN(count);
+}
+