return 0;
}
+/**
+ * Finds a parameter in \a params and copies it to \a copy.
+ *
+ * Leading spaces are skipped. Next space or end of string is the
+ * parameter terminator with the exception that spaces inside single or double
+ * quotes get included into a parameter. The parameter is copied into \a copy
+ * which has to be allocated big enough by a caller, quotes are stripped in
+ * the copy and the copy is terminated by 0.
+ *
+ * On return \a params is set to next parameter or to NULL if last
+ * parameter is returned.
+ *
+ * \retval 0 if parameter is returned in \a copy
+ * \retval 1 otherwise
+ * \retval -EINVAL if unbalanced quota is found
+ */
+int class_get_next_param(char **params, char *copy)
+{
+ char *q1, *q2, *str;
+ int len;
+
+ str = *params;
+ while (*str == ' ')
+ str++;
+
+ if (*str == '\0') {
+ *params = NULL;
+ return 1;
+ }
+
+ while (1) {
+ q1 = strpbrk(str, " '\"");
+ if (q1 == NULL) {
+ len = strlen(str);
+ memcpy(copy, str, len);
+ copy[len] = '\0';
+ *params = NULL;
+ return 0;
+ }
+ len = q1 - str;
+ if (*q1 == ' ') {
+ memcpy(copy, str, len);
+ copy[len] = '\0';
+ *params = str + len;
+ return 0;
+ }
+
+ memcpy(copy, str, len);
+ copy += len;
+
+ /* search for the matching closing quote */
+ str = q1 + 1;
+ q2 = strchr(str, *q1);
+ if (q2 == NULL) {
+ CERROR("Unbalanced quota in parameters: \"%s\"\n",
+ *params);
+ return -EINVAL;
+ }
+ len = q2 - str;
+ memcpy(copy, str, len);
+ copy += len;
+ str = q2 + 1;
+ }
+ return 1;
+}
+
/* returns 0 if this is the first key in the buffer, else 1.
valp points to first char after key. */
int class_match_param(char *buf, char *key, char **valp)
}
EXPORT_SYMBOL(class_find_param);
+EXPORT_SYMBOL(class_get_next_param);
EXPORT_SYMBOL(class_match_param);
EXPORT_SYMBOL(class_parse_nid);
LASSERTF(obd->obd_magic == OBD_DEVICE_MAGIC,
"obd %p obd_magic %08X != %08X\n",
obd, obd->obd_magic, OBD_DEVICE_MAGIC);
- LASSERTF(strncmp(obd->obd_name, name, strlen(name)) == 0, "%p obd_name %s != %s\n",
- obd, obd->obd_name, name);
+ LASSERTF(strncmp(obd->obd_name, name, strlen(name)) == 0,
+ "%p obd_name %s != %s\n", obd, obd->obd_name, name);
rwlock_init(&obd->obd_pool_lock);
obd->obd_pool_limit = 0;
obd->obd_pool_slv = 0;
CFS_INIT_LIST_HEAD(&obd->obd_exports);
+ CFS_INIT_LIST_HEAD(&obd->obd_delayed_exports);
CFS_INIT_LIST_HEAD(&obd->obd_exports_timed);
CFS_INIT_LIST_HEAD(&obd->obd_nid_stats);
spin_lock_init(&obd->obd_nid_lock);
llog_group_init(&obd->obd_olg, FILTER_GROUP_LLOG);
- spin_lock_init(&obd->obd_uncommitted_replies_lock);
- CFS_INIT_LIST_HEAD(&obd->obd_uncommitted_replies);
-
len = strlen(uuid);
if (len >= sizeof(obd->obd_uuid)) {
CERROR("uuid must be < %d bytes long\n",
spin_unlock(&obd->obd_dev_lock);
/* create an uuid-export lustre hash */
- obd->obd_uuid_hash = lustre_hash_init("UUID_HASH", 7, 7,
+ obd->obd_uuid_hash = lustre_hash_init("UUID_HASH",
+ HASH_UUID_CUR_BITS,
+ HASH_UUID_MAX_BITS,
&uuid_hash_ops, 0);
if (!obd->obd_uuid_hash)
GOTO(err_hash, err = -ENOMEM);
-
+
/* create a nid-export lustre hash */
- obd->obd_nid_hash = lustre_hash_init("NID_HASH", 7, 7,
+ obd->obd_nid_hash = lustre_hash_init("NID_HASH",
+ HASH_NID_CUR_BITS,
+ HASH_NID_MAX_BITS,
&nid_hash_ops, 0);
if (!obd->obd_nid_hash)
GOTO(err_hash, err = -ENOMEM);
-
+
/* create a nid-stats lustre hash */
- obd->obd_nid_stats_hash = lustre_hash_init("NID_STATS", 7, 7,
+ obd->obd_nid_stats_hash = lustre_hash_init("NID_STATS",
+ HASH_NID_STATS_CUR_BITS,
+ HASH_NID_STATS_MAX_BITS,
&nid_stat_hash_ops, 0);
if (!obd->obd_nid_stats_hash)
GOTO(err_hash, err = -ENOMEM);
RETURN(0);
err_exp:
- class_unlink_export(obd->obd_self_export);
- obd->obd_self_export = NULL;
+ if (obd->obd_self_export) {
+ class_unlink_export(obd->obd_self_export);
+ obd->obd_self_export = NULL;
+ }
err_hash:
if (obd->obd_uuid_hash) {
lustre_hash_exit(obd->obd_uuid_hash);
static void dump_exports(struct obd_device *obd)
{
- struct obd_export *exp, *n;
+ struct obd_export *exp;
- list_for_each_entry_safe(exp, n, &obd->obd_exports, exp_obd_chain) {
+ spin_lock(&obd->obd_dev_lock);
+ list_for_each_entry(exp, &obd->obd_exports, exp_obd_chain) {
struct ptlrpc_reply_state *rs;
struct ptlrpc_reply_state *first_reply = NULL;
int nreplies = 0;
+ spin_lock(&exp->exp_lock);
list_for_each_entry (rs, &exp->exp_outstanding_replies,
rs_exp_list) {
if (nreplies == 0)
first_reply = rs;
nreplies++;
}
+ spin_unlock(&exp->exp_lock);
CDEBUG(D_IOCTL, "%s: %p %s %s %d %d %d: %p %s\n",
obd->obd_name, exp, exp->exp_client_uuid.uuid,
exp->exp_failed, nreplies, first_reply,
nreplies > 3 ? "..." : "");
}
+ spin_unlock(&obd->obd_dev_lock);
}
int class_cleanup(struct obd_device *obd, struct lustre_cfg *lcfg)
obd_iocontrol(OBD_IOC_SYNC,
obd->obd_self_export,
0, NULL, NULL);
- /* Set the obd readonly if we can */
+ /* Set the obd readonly if we can */
obd_iocontrol(OBD_IOC_SET_READONLY,
obd->obd_self_export,
0, NULL, NULL);
}
break;
default:
- CERROR("unrecognised flag '%c'\n",
- *flag);
+ CERROR("Unrecognised flag '%c'\n", *flag);
}
}
+ LASSERT(obd->obd_self_export);
+
/* The three references that should be remaining are the
* obd_self_export and the attach and setup references. */
if (atomic_read(&obd->obd_refcount) > 3) {
-#if 0 /* We should never fail to cleanup with mountconf */
- if (!(obd->obd_fail || obd->obd_force)) {
- CERROR("OBD %s is still busy with %d references\n"
- "You should stop active file system users,"
- " or use the --force option to cleanup.\n",
- obd->obd_name, atomic_read(&obd->obd_refcount));
- dump_exports(obd);
- /* Allow a failed cleanup to try again. */
- obd->obd_stopping = 0;
- }
-#endif
/* refcounf - 3 might be the number of real exports
(excluding self export). But class_incref is called
by other things as well, so don't count on it. */
dump_exports(obd);
class_disconnect_exports(obd);
}
- LASSERT(obd->obd_self_export);
/* destroy an uuid-export hash body */
- lustre_hash_exit(obd->obd_uuid_hash);
+ if (obd->obd_uuid_hash) {
+ lustre_hash_exit(obd->obd_uuid_hash);
+ obd->obd_uuid_hash = NULL;
+ }
/* destroy a nid-export hash body */
- lustre_hash_exit(obd->obd_nid_hash);
+ if (obd->obd_nid_hash) {
+ lustre_hash_exit(obd->obd_nid_hash);
+ obd->obd_nid_hash = NULL;
+ }
/* destroy a nid-stats hash body */
- lustre_hash_exit(obd->obd_nid_stats_hash);
+ if (obd->obd_nid_stats_hash) {
+ lustre_hash_exit(obd->obd_nid_stats_hash);
+ obd->obd_nid_stats_hash = NULL;
+ }
/* Precleanup, we must make sure all exports get destroyed. */
err = obd_precleanup(obd, OBD_CLEANUP_EXPORTS);
struct obd_device *class_incref(struct obd_device *obd,
const char *scope, const void *source)
{
+ LASSERT(!obd->obd_stopping);
lu_ref_add_atomic(&obd->obd_reference, scope, source);
atomic_inc(&obd->obd_refcount);
CDEBUG(D_INFO, "incref %s (%p) now %d\n", obd->obd_name, obd,
be no more in-progress ops by this point.*/
spin_lock(&obd->obd_self_export->exp_lock);
- obd->obd_self_export->exp_flags |=
- (obd->obd_fail ? OBD_OPT_FAILOVER : 0) |
- (obd->obd_force ? OBD_OPT_FORCE : 0);
+ obd->obd_self_export->exp_flags |= exp_flags_from_obd(obd);
spin_unlock(&obd->obd_self_export->exp_lock);
/* note that we'll recurse into class_decref again */
obd->obd_name, err);
}
if (OBP(obd, detach)) {
- err = OBP(obd,detach)(obd);
+ err = OBP(obd, detach)(obd);
if (err)
CERROR("Detach returned %d\n", err);
}
EXIT;
}
+static int class_set_global(char *ptr, int val) {
+ ENTRY;
+
+ if (class_match_param(ptr, PARAM_AT_MIN, NULL) == 0)
+ at_min = val;
+ else if (class_match_param(ptr, PARAM_AT_MAX, NULL) == 0)
+ at_max = val;
+ else if (class_match_param(ptr, PARAM_AT_EXTRA, NULL) == 0)
+ at_extra = val;
+ else if (class_match_param(ptr, PARAM_AT_EARLY_MARGIN, NULL) == 0)
+ at_early_margin = val;
+ else if (class_match_param(ptr, PARAM_AT_HISTORY, NULL) == 0)
+ at_history = val;
+ else
+ RETURN(-EINVAL);
+
+ CDEBUG(D_IOCTL, "global %s = %d\n", ptr, val);
+
+ RETURN(0);
+}
+
+
/* We can't call ll_process_config directly because it lives in a module that
must be loaded after this one. */
static int (*client_process_config)(struct lustre_cfg *lcfg) = NULL;
obd_timeout = max(lcfg->lcfg_num, 1U);
GOTO(out, err = 0);
}
+ case LCFG_SET_LDLM_TIMEOUT: {
+ CDEBUG(D_IOCTL, "changing lustre ldlm_timeout from %d to %d\n",
+ ldlm_timeout, lcfg->lcfg_num);
+ ldlm_timeout = max(lcfg->lcfg_num, 1U);
+ if (ldlm_timeout >= obd_timeout)
+ ldlm_timeout = max(obd_timeout / 3, 1U);
+
+ GOTO(out, err = 0);
+ }
case LCFG_SET_UPCALL: {
LCONSOLE_ERROR_MSG(0x15a, "recovery upcall is deprecated\n");
/* COMPAT_146 Don't fail on old configs */
GOTO(out, err = 0);
}
case LCFG_PARAM: {
+ char *tmp;
/* llite has no obd */
if ((class_match_param(lustre_cfg_string(lcfg, 1),
PARAM_LLITE, 0) == 0) &&
client_process_config) {
err = (*client_process_config)(lcfg);
GOTO(out, err);
+ } else if ((class_match_param(lustre_cfg_string(lcfg, 1),
+ PARAM_SYS, &tmp) == 0)) {
+ /* Global param settings */
+ err = class_set_global(tmp, lcfg->lcfg_num);
+ /* Note that since LCFG_PARAM is LCFG_REQUIRED, new
+ unknown globals would cause config to fail */
+ if (err)
+ CWARN("Ignoring unknown param %s\n", tmp);
+ GOTO(out, 0);
}
+
/* Fall through */
break;
}
sval = strchr(key, '=');
if (!sval || (*(sval + 1) == 0)) {
CERROR("Can't parse param %s (missing '=')\n", key);
- /* rc = -EINVAL; continue parsing other params */
+ /* rc = -EINVAL; continue parsing other params */
continue;
}
keylen = sval - key;
vallen, data);
set_fs(oldfs);
}
- if (rc < 0)
- CERROR("writing proc entry %s err %d\n",
- var->name, rc);
break;
}
j++;
RETURN(-ENOSYS);
CERROR("%s: unknown param %s\n",
(char *)lustre_cfg_string(lcfg, 0), key);
- /* rc = -EINVAL; continue parsing other params */
+ /* rc = -EINVAL; continue parsing other params */
skip++;
+ } else if (rc < 0) {
+ CERROR("writing proc entry %s err %d\n",
+ var->name, rc);
+ rc = 0;
} else {
LCONSOLE_INFO("%s.%.*s: set parameter %.*s=%s\n",
lustre_cfg_string(lcfg, 0),
CDEBUG(D_CONFIG, "SKIP #%d\n",
marker->cm_step);
} else if ((marker->cm_flags & CM_EXCLUDE) ||
- lustre_check_exclusion(clli->cfg_sb,
- marker->cm_tgtname)) {
+ (clli->cfg_sb &&
+ lustre_check_exclusion(clli->cfg_sb,
+ marker->cm_tgtname))) {
clli->cfg_flags |= CFG_F_EXCLUDE;
CDEBUG(D_CONFIG, "EXCLUDE %d\n",
marker->cm_step);
{
char *typename = lustre_cfg_string(lcfg, 1);
char *index = lustre_cfg_string(lcfg, 2);
-
+
if ((lcfg->lcfg_command == LCFG_ATTACH && typename &&
strcmp(typename, "mds") == 0)) {
CWARN("For 1.8 interoperability, rename obd "
}
if ((lcfg->lcfg_command == LCFG_SETUP && index &&
strcmp(index, "type") == 0)) {
- CWARN("For 1.8 interoperability, set this"
- " index to '0'\n");
+ CDEBUG(D_INFO, "For 1.8 interoperability, "
+ "set this index to '0'\n");
index[0] = '0';
index[1] = 0;
}
lustre_cfg_bufs_set_string(&bufs, 2,
clli->cfg_uuid.uuid);
}
+ /*
+ * sptlrpc config record, we expect 2 data segments:
+ * [0]: fs_name/target_name,
+ * [1]: rule string
+ * moving them to index [1] and [2], and insert MGC's
+ * obdname at index [0].
+ */
+ if (clli && clli->cfg_instance == NULL &&
+ lcfg->lcfg_command == LCFG_SPTLRPC_CONF) {
+ lustre_cfg_bufs_set(&bufs, 2, bufs.lcfg_buf[1],
+ bufs.lcfg_buflen[1]);
+ lustre_cfg_bufs_set(&bufs, 1, bufs.lcfg_buf[0],
+ bufs.lcfg_buflen[0]);
+ lustre_cfg_bufs_set_string(&bufs, 0,
+ clli->cfg_obdname);
+ }
lcfg_new = lustre_cfg_new(lcfg->lcfg_command, &bufs);
/* Cleanup and detach */
int class_manual_cleanup(struct obd_device *obd)
{
- struct lustre_cfg *lcfg;
- struct lustre_cfg_bufs bufs;
- int rc;
- char flags[3]="";
+ char flags[3] = "";
+ struct lustre_cfg *lcfg;
+ struct lustre_cfg_bufs bufs;
+ int rc;
ENTRY;
if (!obd) {
lustre_cfg_bufs_reset(&bufs, obd->obd_name);
lustre_cfg_bufs_set_string(&bufs, 1, flags);
lcfg = lustre_cfg_new(LCFG_CLEANUP, &bufs);
+ if (!lcfg)
+ RETURN(-ENOMEM);
rc = class_process_config(lcfg);
if (rc) {
struct nid_stat *ns;
ns = hlist_entry(hnode, struct nid_stat, nid_hash);
- ns->nid_exp_ref_count++;
+ nidstat_getref(ns);
RETURN(ns);
}
struct nid_stat *ns;
ns = hlist_entry(hnode, struct nid_stat, nid_hash);
- ns->nid_exp_ref_count--;
+ nidstat_putref(ns);
RETURN(ns);
}