[LTP] [PATCH v3] Rewrite fcnt14 test
Andrea Cervesato
andrea.cervesato@suse.com
Mon Sep 2 10:30:49 CEST 2024
Hi!
On 8/30/24 15:58, Cyril Hrubis wrote:
> Hi!
>> +fcntl14_01 fcntl14
>> +fcntl14_01_64 fcntl14_64
>> +fcntl14_02 fcntl14 -l
>> +fcntl14_02_64 fcntl14_64 -l
> I would slightly prefer having a .test_variants than adding a command
> line options.
We can make it.
>
>> +#define CHECK_EQ_SILENT_(VAL_A, SVAL_A, VAL_B, SVAL_B, TYPE, PFS, FAILED) do {\
>> + TYPE tst_tmp_a__ = VAL_A; \
>> + TYPE tst_tmp_b__ = VAL_B; \
>> + if (tst_tmp_a__ != tst_tmp_b__) { \
>> + tst_res(TFAIL, \
>> + SVAL_A " == " SVAL_B " (" PFS ")", tst_tmp_a__); \
>> + *FAILED = 1; \
>> + } \
>> +} while (0)
>> +
>> +#define CHECK_EQ_SILENT(VAL_A, VAL_B, FAILED) \
>> + CHECK_EQ_SILENT_(VAL_A, #VAL_A, VAL_B, #VAL_B, long long, "%lli", FAILED)
> Maybe this should go to the tst_test_macros.h?
I don't know, is a silent version of EQ_LI really needed? It's a
particular use case, where also *FAILED is set, so I don't know...
>
>> +struct file_conf {
>> + short type;
>> + short whence;
>> + long start;
>> + long len;
>> };
>>
>> -static testcase *thiscase;
>> +struct testcase {
>> + struct file_conf parent; /* parent parameters for fcntl() */
>> + struct file_conf child; /* child parameters for fcntl() */
>> + short blocking; /* blocking/non-blocking flag */
>> + long pos; /* starting file position */
>> +};
>> +
>> +struct tc_results {
>> + int num_pass;
>> + int last_failed;
>> +};
>> +
>> +static const char filepath[] = "unlocked.txt";
>> +static const char filedata[] = "Here some bytes!";
>> static struct flock flock;
>> -static int parent, child, status, fail = 0;
>> -static int got1 = 0;
>> -static int fd;
>> -static int test;
>> -static char tmpname[40];
>> +static char *str_op_nums;
>> +static char *locking_file;
>> +static int op_nums = 5000;
>> +static int file_mode = 0777;
>> +static struct tc_results *results;
>>
>> -#define FILEDATA "ten bytes!"
>> +static void dochild(struct testcase *tc, const int fd, const pid_t parent_pid)
>> +{
>> + results->last_failed = 0;
>>
>> -void catch1(int sig);
>> -void catch_alarm(int sig);
>> + flock.l_type = tc->child.type;
>> + flock.l_whence = tc->child.whence;
>> + flock.l_start = tc->child.start;
>> + flock.l_len = tc->child.len;
>> + flock.l_pid = 0;
>>
>> -char *TCID = "fcntl14";
>> -int TST_TOTAL = 1;
>> -int NO_NFS = 1;
>> + SAFE_FCNTL(fd, F_GETLK, &flock);
>>
>> -void cleanup(void)
>> -{
>> - tst_rmdir();
>> -}
>> + if (tc->blocking) {
>> + tst_res(TDEBUG, "Child: expecting blocked file by parent");
>>
>> -void setup(void)
>> -{
>> - struct sigaction act;
>> -
>> - tst_sig(FORK, DEF_HANDLER, cleanup);
>> - signal(SIGHUP, SIG_IGN);
>> - umask(0);
>> - TEST_PAUSE;
>> - tst_tmpdir();
>> - parent = getpid();
>> -
>> - sprintf(tmpname, "fcntl2.%d", parent);
>> -
>> - /* setup signal handler for signal from child */
>> - memset(&act, 0, sizeof(act));
>> - act.sa_handler = catch1;
>> - sigemptyset(&act.sa_mask);
>> - sigaddset(&act.sa_mask, SIGUSR1);
>> - if ((sigaction(SIGUSR1, &act, NULL)) < 0) {
>> - tst_resm(TFAIL, "SIGUSR1 signal setup failed, errno = %d",
>> - errno);
>> - cleanup();
>> - }
>> + CHECK_EQ_SILENT(flock.l_pid, parent_pid, &results->last_failed);
>> + if (results->last_failed)
>> + return;
>>
>> - memset(&act, 0, sizeof(act));
>> - act.sa_handler = catch_alarm;
>> - sigemptyset(&act.sa_mask);
>> - sigaddset(&act.sa_mask, SIGALRM);
>> - if ((sigaction(SIGALRM, &act, NULL)) < 0) {
>> - tst_resm(TFAIL, "SIGALRM signal setup failed");
>> - cleanup();
>> - }
>> -}
>> + CHECK_EQ_SILENT(flock.l_type, tc->parent.type, &results->last_failed);
>> + if (results->last_failed)
>> + return;
>>
>> -void wake_parent(void)
>> -{
>> - if ((kill(parent, SIGUSR1)) < 0) {
>> - tst_resm(TFAIL, "Attempt to send signal to parent " "failed");
>> - tst_resm(TFAIL, "Test case %d, errno = %d", test + 1, errno);
>> - fail = 1;
>> + flock.l_type = tc->child.type;
>> + flock.l_whence = tc->child.whence;
>> + flock.l_start = tc->child.start;
>> + flock.l_len = tc->child.len;
>> + flock.l_pid = 0;
>> +
>> + TST_EXP_FAIL_SILENT(fcntl(fd, F_SETLK, &flock), EWOULDBLOCK);
>> + if (TST_RET != -1)
>> + results->last_failed = 1;
>> + } else {
>> + tst_res(TDEBUG, "Child: expecting no blocking errors");
>> +
>> + CHECK_EQ_SILENT(flock.l_type, F_UNLCK, &results->last_failed);
>> + if (results->last_failed)
>> + return;
>> +
>> + CHECK_EQ_SILENT(flock.l_whence, tc->child.whence, &results->last_failed);
>> + if (results->last_failed)
>> + return;
>> +
>> + CHECK_EQ_SILENT(flock.l_start, tc->child.start, &results->last_failed);
>> + if (results->last_failed)
>> + return;
>> +
>> + CHECK_EQ_SILENT(flock.l_len, tc->child.len, &results->last_failed);
>> + if (results->last_failed)
>> + return;
>> +
>> + CHECK_EQ_SILENT(flock.l_pid, 0, &results->last_failed);
>> + if (results->last_failed)
>> + return;
> Why do we have to exit after each failed check here? I would just a
> bunch of the checks here without the returns. All that we need is to
> make sure the last_failed is set if child fails so that parent can
> detect it.
>
>
>> + /* set the initial parent lock on the file */
>> + flock.l_type = tc->parent.type;
>> + flock.l_whence = tc->parent.whence;
>> + flock.l_start = tc->parent.start;
>> + flock.l_len = tc->parent.len;
>> flock.l_pid = 0;
> I wonder if it would be better to use struct flock in the tc directory
> so that we could just assign the structure here. I.e. we would do here
> just:
>
> struct flock flock = tc->flock;
>
> flock.l_pid = 0;
>
>
>> + flock.l_type = F_UNLCK;
>> + flock.l_whence = 0;
>> + flock.l_start = 0;
>> + flock.l_len = 0;
>> flock.l_pid = 0;
>>
>> + SAFE_FCNTL(fd, F_SETLK, &flock);
>> + SAFE_CLOSE(fd);
> Why bother with unlocking? Aren't the locks dropped when we close the fd
> here anyways?
>
>> +}
>> +
>> +static void genconf(struct file_conf *conf, const int size, const long pos)
>> +{
>> + conf->type = rand() % 2 ? F_RDLCK : F_WRLCK;
>> + conf->whence = SEEK_CUR;
>> +
>> + if (pos > 0 && (rand() % 2)) {
>> + conf->start = -(rand() % pos);
>> + conf->len = rand() % (size + conf->start - 1) + 1;
>> } else {
>> - exit(0);
>> + conf->start = rand() % (size - 1);
>> + conf->len = rand() % (size - conf->start - 1) + 1;
>> }
>> }
> We have a file in which we seek at pos offset and then need a start
> relative to that and lenght so that it fits into the file.
>
> The start should be just the whole available range, which is random
> offset moved back by pos. Then we need a size which is limited to
> whatever is left in the file and is not relative. So if I'm not mistaken
> we need what is in the else branch but we have to move the start by pos
> at the end, i.e. the whole start and len generation should look like:
>
> conf->start = rand() % (size - 1);
> conf->len = rand() % (size - conf->start - 1) + 1;
> conf->start -= pos;
>
> That way we generate a valid part of the file and make it realtive to
> the pos at the end.
>
>> -void run_test(int file_flag, int file_mode, int seek, int start, int end)
>> +static short fcntl_overlap(
>> + struct file_conf *parent,
>> + struct file_conf *child,
>> + const long pos)
>> {
>> + long start[2];
>> + long length[2];
>> + short overlap = 0;
>> +
>> + if (parent->start > child->start) {
>> + start[0] = pos + child->start;
>> + start[1] = pos + parent->start;
>> + length[0] = child->len;
>> + length[1] = parent->len;
>> + } else {
>> + start[0] = pos + parent->start;
>> + start[1] = pos + child->start;
>> + length[0] = parent->len;
>> + length[1] = child->len;
>> }
> If you add pos to both of the starts you just move the two ranges by the
> same amount. So the end result is the same regardless of if you add it
> or not.
>
>> +
>> + overlap = start[0] <= start[1] && start[1] < (start[0] + length[0]);
> Isn't the start[0] <= start[1] because we made it so? We set the
> start[0] to the smaller of the two. So all we need to do is to check
> that that start[0] + lenght[0] does not end before the start[1] which is
> the second part of the equation.
>
> And we do not use lenght[1] either. So maybe we just need:
>
> if (child->start < parent->start)
> overlap = parent->start < (child->start + child->len);
> else
> overlap = child->start < (parent->start + parent->len);
>
>> + if (overlap)
>> + tst_res(TDEBUG, "child/parent fcntl() configurations overlap");
>> +
>> + return overlap;
>> }
>>
Andrea
More information about the ltp
mailing list