Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add manual scsi probe of a Lun #84

Merged
merged 1 commit into from
Apr 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 23 additions & 2 deletions config-parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ static inline int conf_construct(conf* c) {
c->fs.scoped = (str*)calloc(1, sizeof(str));
c->fstype.val = (str*)calloc(1, sizeof(str));
c->fstype.scoped = (str*)calloc(1, sizeof(str));
#ifdef SCSI_PROBE
c->scsi_dev.val = (str*)calloc(1, sizeof(str));
c->scsi_dev.scoped = (str*)calloc(1, sizeof(str));
#endif
return !c->bootfs.val || !c->bootfs.scoped || !c->bootfs_hint.val ||
!c->bootfs_hint.scoped || !c->bootfstype.val ||
!c->bootfstype.scoped || !c->fs.val || !c->fs.scoped ||
Expand Down Expand Up @@ -41,6 +45,9 @@ static inline void conf_set_pick(conf* c, str** line) {
.len = sizeof("bootfstype") - 1};
const str fs_str = {.c_str = "fs", .len = sizeof("fs") - 1};
const str fstype_str = {.c_str = "fstype", .len = sizeof("fstype") - 1};
#ifdef SCSI_PROBE
const str devtoscan_str = {.c_str = SCSI_ADDR_BOOT_ARG, .len = sizeof(SCSI_ADDR_BOOT_ARG) - 1};
#endif

if (is_line_key(*line, &bootfs_str))
set_conf(&c->bootfs, line, bootfs_str.len);
Expand All @@ -52,18 +59,32 @@ static inline void conf_set_pick(conf* c, str** line) {
set_conf(&c->fs, line, fs_str.len);
else if (is_line_key(*line, &fstype_str))
set_conf(&c->fstype, line, fstype_str.len);
#ifdef SCSI_PROBE
else if (is_line_key(*line, &devtoscan_str)){
(*line)->c_str[devtoscan_str.len]='=';
set_conf(&c->scsi_dev, line, devtoscan_str.len);
}
#endif
}

static inline conf* conf_print(conf* c) {
#ifdef DEBUG
printd(
"bootfs: {\"%s\", \"%s\"}, bootfs_hint: {\"%s\", \"%s\"}, bootfstype: "
"{\"%s\", \"%s\"}, fs: {\"%s\", "
"\"%s\"}, fstype: {\"%s\", \"%s\"}\n",
"\"%s\"}, fstype: {\"%s\", \"%s\"}"
#ifdef SCSI_PROBE
", scsi_dev: {\"%s\", \"%s\"}"
#endif
"\n",
c->bootfs.val->c_str, c->bootfs.scoped->c_str, c->bootfs_hint.val->c_str,
c->bootfs_hint.scoped->c_str, c->bootfstype.val->c_str,
c->bootfstype.scoped->c_str, c->fs.val->c_str, c->fs.scoped->c_str,
c->fstype.val->c_str, c->fstype.scoped->c_str);
c->fstype.val->c_str, c->fstype.scoped->c_str
#ifdef SCSI_PROBE
, c->scsi_dev.val->c_str, c->scsi_dev.scoped->c_str
#endif
);
#endif
return c;
}
Expand Down
28 changes: 27 additions & 1 deletion initoverlayfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,14 @@
#include <sys/utsname.h>
#include <sys/vfs.h>
#include <sys/wait.h>

#ifdef SCSI_PROBE
#define CMDLINE "/proc/cmdline"
#define SCSI_SYS_TMPL "/sys/class/scsi_host/host%d/scan"
#define SCSI_SYS_TMPL_SZ 40
#include "scsi_probe/scsi_probe.h"
#include <errno.h>
#endif
#include "config-parser.h"

#define fork_execl_no_wait(pid, exe, ...) \
Expand Down Expand Up @@ -518,7 +526,7 @@ static int switchroot(const char* newroot) {
}

static int mount_proc_sys_dev(void) {
if (false) {
if (true) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This statement here is not ifdef'd.
For some reason, I thought it should be enabled, no matter what.
On a second thought, I wonder if you prefer this to be ifdef dependent.

Copy link
Collaborator

@ericcurtin ericcurtin Apr 22, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was false deliberately because in the use case this code was intended for initoverlayfs is the init system, but exec's itself as a systemd process really quickly (and then systemd mounts /proc).

But tbh, it was a micro-optimization, so I don't mind it being true, it was just one less mount call.

Copy link
Collaborator

@ericcurtin ericcurtin Apr 22, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, some things are broken here in general (not in this PR, in initoverlayfs main branch) that I have to fix when I come back.

I think if you run the upstream version of this now on a Fedora Workstation machine, it doesn't boot anymore and they are really trivial silly bugs.

I just got distracted by other things the last week or two.

if (mount("proc", "/proc", "proc", MS_NOSUID | MS_NOEXEC | MS_NODEV,
NULL)) {
print(
Expand Down Expand Up @@ -599,6 +607,24 @@ int main(int argc, char* argv[]) {
return 0;

conf_read(&conf, "/etc/initoverlayfs.conf");
#ifdef SCSI_PROBE
struct args ba;
char cmdline[50];
FILE *file;

file = fopen(CMDLINE, "r");
if (file != NULL) {
if (fgets(cmdline, sizeof(cmdline), file)) {
char *kcmdline = fetch_kernel_cmdline(CMDLINE);
conf_print(&conf);
parse_kernel_cmdline(kcmdline, &ba);
update_scsi_args(conf.scsi_dev.scoped->c_str, &ba);
trigger_scan(&ba, SCSI_SYS_TMPL, SCSI_SYS_TMPL_SZ);
}
fclose(file);
}
#endif

const bool do_bootfs = convert_bootfs(&conf, systemd);
convert_fs(&conf);
if (systemd)
Expand Down
10 changes: 9 additions & 1 deletion initoverlayfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ typedef struct conf {
pair bootfstype;
pair fs;
pair fstype;
#ifdef SCSI_PROBE
pair scsi_dev;
#endif
} conf;

static inline void cleanup_free_conf(conf* p) {
Expand All @@ -77,7 +80,12 @@ static inline void cleanup_free_conf(conf* p) {
free(p->fs.scoped->c_str);
if (p->fstype.scoped)
free(p->fstype.scoped->c_str);

#ifdef SCSI_PROBE
if (p->scsi_dev.scoped)
free(p->scsi_dev.scoped->c_str);
free(p->scsi_dev.scoped);
free(p->scsi_dev.val);
#endif
free(p->bootfs.scoped);
free(p->bootfs_hint.scoped);
free(p->bootfstype.scoped);
Expand Down
2 changes: 1 addition & 1 deletion initoverlayfs.spec.in
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ Requires: dracut

%build
RPM_OPT_FLAGS="${RPM_OPT_FLAGS/-flto=auto /}"
gcc ${RPM_OPT_FLAGS} -lblkid initoverlayfs.c -o initoverlayfs
gcc ${RPM_OPT_FLAGS} -lblkid initoverlayfs.c scsi_probe/scsi_probe.c -o initoverlayfs

%install
install -D -m755 bin/initoverlayfs-install ${RPM_BUILD_ROOT}/%{_bindir}/initoverlayfs-install
Expand Down
54 changes: 54 additions & 0 deletions scsi_probe/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
CC=gcc
CFLAGS= -g
#QUIET = &>/dev/null
VALGRIND_FLAGS= --error-exitcode=1 --leak-check=full -s

tests: tests_res/parse_kernel_cmdline.exec.log tests_res/parse_kernel_cmdline.valgrind.log tests_res/fetch_kernel_cmdline.exec.log tests_res/fetch_kernel_cmdline.valgrind.log tests_res/trigger_scan.valgrind.log tests_res/trigger_scan.exec.log

################################################################
tests_res/parse_kernel_cmdline.exec.log: tests/parse_kernel_cmdline
@echo "======================= Testing... " $< " exec"
@$< > $@

tests_res/parse_kernel_cmdline.valgrind.log: tests/parse_kernel_cmdline
@echo "======================= Testing... " $< "valgrind"
@valgrind $(VALGRIND_FLAGS) $< >$@ 2>&1

tests/parse_kernel_cmdline: tests/parse_kernel_cmdline.c scsi_probe.o
@echo "======================= Build... " $<
@$(CC) $(CFLAGS) $^ -o $@

###########################################################################
tests_res/fetch_kernel_cmdline.exec.log: tests/fetch_kernel_cmdline
@echo "======================= Testing... " $< " exec"
@$< > $@

tests_res/fetch_kernel_cmdline.valgrind.log: tests/fetch_kernel_cmdline
@echo "======================= Testing... " $< "valgrind"
@valgrind $(VALGRIND_FLAGS) $< >$@ 2>&1

tests/fetch_kernel_cmdline: tests/fetch_kernel_cmdline.c scsi_probe.o
@echo "======================= Build... " $<
@$(CC) $(CFLAGS) $^ -o $@

###########################################################################
tests_res/trigger_scan.exec.log: tests/trigger_scan
@echo "======================= Testing... " $< " exec"
@$< > $@

tests_res/trigger_scan.valgrind.log: tests/trigger_scan
@echo "======================= Testing... " $< "valgrind"
@valgrind $(VALGRIND_FLAGS) $< >$@ 2>&1

tests/trigger_scan: tests/trigger_scan.c scsi_probe.o
@echo "======================= Build... " $<
@$(CC) $(CFLAGS) $^ -o $@

###########################################################################
scsi_probe.o: scsi_probe.c scsi_probe.h
@echo "======================= Build... " $<
@$(CC) $(CFLAGS) -c $< -o $@

clean:
@echo "======================= CLEAN... "
@rm -f scsi_probe.o tests/parse_kernel_cmdline tests_res/*.log
76 changes: 76 additions & 0 deletions scsi_probe/scsi_probe.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include "scsi_probe.h"

static int c2i(char *str){
char *endptr;
int num;

errno = 0;
num = strtol(str, &endptr, 10);
if ((errno != 0 && num == 0) || (num > 99)) return -1;
if (endptr == str) return -1;
return num;
}

inline int update_scsi_args(const char *ba_str, struct args *ba){
char *token;
char *ba_str2;
char *tmp1, *tmp2;

if (!ba_str) return 0;
if ((ba_str2 = strdup(ba_str)) == NULL) return 0;
token = strtok(ba_str2, " ");
while (token != NULL) {
if (strncmp(token, SCSI_ADDR_BOOT_ARG, strlen(SCSI_ADDR_BOOT_ARG)) == 0) {
tmp1 = strchr(token, '=');
if (tmp1 != NULL) {
tmp2 = tmp1 + 1;
sscanf(tmp2, "%d:%d:%d:%d", &ba->scsi_host, &ba->scsi_channel, &ba->scsi_id, &ba->scsi_lun);
}
}
token = strtok(NULL, " ");
}
free(ba_str2);
return 1;
}


int parse_kernel_cmdline(const char *ba_str, struct args *ba){
memset(ba, 0, sizeof(struct args));
ba->scsi_manual=strstr(ba_str, "scsi_mod.scan=manual")?1:0;
return update_scsi_args(ba_str, ba);
}

char *fetch_kernel_cmdline(const char *cmdline_fn){
FILE *file;
char *cmdline;

file = fopen(cmdline_fn, "r");
if (file == NULL) return NULL;
cmdline = (char *) malloc(MAX_BUF);
if (! fgets(cmdline, MAX_BUF, file)) {
free(cmdline);
return NULL;
}
fclose(file);
return cmdline;
}


int trigger_scan(struct args *ba, const char *scsi_sys_tmpl, const int scsi_sys_tmpl_sz) {
FILE *file;
char buf[128];
int n;

if (ba->scsi_manual==0) return 0;
snprintf(buf, scsi_sys_tmpl_sz, scsi_sys_tmpl, ba->scsi_host);
file = fopen(buf, "w");
if (file == NULL) return 0;
n = snprintf(buf, MAX_BUF, SCSI_SYS_SCAN_STR, ba->scsi_channel, ba->scsi_id, ba->scsi_lun);
fwrite(buf, n, 1, file);
fclose(file);
return 1;
}
19 changes: 19 additions & 0 deletions scsi_probe/scsi_probe.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#define MAX_ARGS 100
#define MAX_BUF 128

#define SCSI_SYS_SCAN_STR "%d %d %d\n"

#define SCSI_ADDR_BOOT_ARG "scsi.addr"

struct args {
int scsi_manual;
int scsi_host;
int scsi_channel;
int scsi_id;
int scsi_lun;
};

int update_scsi_args(const char *, struct args *);
int parse_kernel_cmdline(const char *, struct args *);
char *fetch_kernel_cmdline(const char *);
int trigger_scan(struct args *, const char *, const int);
1 change: 1 addition & 0 deletions scsi_probe/testfiles/cmd1
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pippo=1 pluto=2 paperino=3
2 changes: 2 additions & 0 deletions scsi_probe/testfiles/cmd2
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pippo=1 pluto=2 paperino=3
pippo=z pluto=x paperino=c
1 change: 1 addition & 0 deletions scsi_probe/testfiles/host0scan
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
1 2 3
1 change: 1 addition & 0 deletions scsi_probe/testfiles/host2scan
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3 4 5
39 changes: 39 additions & 0 deletions scsi_probe/tests/fetch_kernel_cmdline.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "../scsi_probe.h"

#define TEST_BUFF_SIZE 200

char *results[] = {
"pippo=1 pluto=2 paperino=3\n",
"pippo=1 pluto=2 paperino=3\n",
NULL
};

char *test_patterns[] = {
"testfiles/cmd1",
"testfiles/cmd2",
"testfiles/cmd3",
};

int main(){
int i;
char *res;

for (i=0; i< sizeof(test_patterns)/sizeof(char *); i++) {
res = fetch_kernel_cmdline(test_patterns[i]);
printf( "Test pattern='%s', expected result='%s' Actual result ='%s' -> ",
test_patterns[i], results[i], res);
if (res && results[i]) {
if (strcmp(res, results[i])!=0) {
printf("Failed\n");
free(res);
return -1;
}
}
printf("Success\n");
free(res);
}
return 0;
}
40 changes: 40 additions & 0 deletions scsi_probe/tests/parse_kernel_cmdline.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#include <stdio.h>
#include <string.h>
#include "../scsi_probe.h"

#define TEST_BUFF_SIZE 200

char *results[] = {
"has manual=1 host=1 addr=2:3:45",
"has manual=1 host=1 addr=2:3:45",
"has manual=1 host=0 addr=0:0:0",
"has manual=0 host=0 addr=0:0:0"
};

char *test_patterns[] = {
"pippo=1 pluto=2 scsi_mod.scan=manual scsi.addr=1:2:3:45 paperino=peppe",
"pippo=1 pluto=2 scsi_mod.scan=manual posw scsi.addr=1:2:3:45 paperino=peppe",
"pippo=1 pluto=2 scsi_mod.scan=manual paperino=peppe",
"pippo=1 pluto=2 paperino=peppe",

};

int main(){
struct args ba;
int i;
char res[TEST_BUFF_SIZE];

for (i=0; i< sizeof(test_patterns)/sizeof(char *); i++) {
if (!parse_kernel_cmdline(test_patterns[i], &ba)) return -1;
sprintf(res, "has manual=%d host=%d addr=%d:%d:%d", ba.scsi_manual, ba.scsi_host, ba.scsi_channel, ba.scsi_id, ba.scsi_lun);

printf( "Test pattern='%s', expected result='%s' Actual result ='%s' -> ",
test_patterns[i], results[i], res);
if (strcmp(res, results[i])) {
printf("Failed\n");
return -1;
}
printf("Success\n");
}
return 0;
}
Loading
Loading