glusterfs
1#define _GNU_SOURCE2
3#include <stdio.h>4#include <stdlib.h>5#include <string.h>6#include <limits.h>7#include <unistd.h>8#include <fcntl.h>9#include <stdint.h>10#include <sys/types.h>11#include <sys/xattr.h>12#include <errno.h>13
14#include "bit-rot-object-version.h"15
16/* NOTE: no size discovery */
17int
18brstub_validate_version(char *bpath, unsigned long version)19{
20int ret = 0;21int match = 0;22size_t xsize = 0;23br_version_t *xv = NULL;24
25xsize = sizeof(br_version_t);26
27xv = calloc(1, xsize);28if (!xv) {29match = -1;30goto err;31}32
33ret = getxattr(bpath, "trusted.bit-rot.version", xv, xsize);34if (ret < 0) {35if (errno == ENODATA)36match = -2;37goto err;38}39
40if (xv->ongoingversion != version) {41match = -3;42fprintf(stderr, "ongoingversion: %lu\n", xv->ongoingversion);43}44free(xv);45
46err:47return match;48}
49
50int
51brstub_write_validation(char *filp, char *bpath, unsigned long startversion)52{
53int fd1 = 0;54int fd2 = 0;55int ret = 0;56char *string = "string\n";57
58/* read only check */59fd1 = open(filp, O_RDONLY);60if (fd1 < 0)61goto err;62close(fd1);63
64ret = brstub_validate_version(bpath, startversion);65if (ret != -2)66goto err;67
68/* single open (write/) check */69fd1 = open(filp, O_RDWR);70if (fd1 < 0)71goto err;72
73ret = write(fd1, string, strlen(string));74if (ret <= 0)75goto err;76/**77* Fsync is done so that the write call has properly reached the
78* disk. For fuse mounts write-behind xlator would have held the
79* writes with itself and for nfs, client would have held the
80* write in its cache. So write fop would not have triggered the
81* versioning as it would have not reached the bit-rot-stub.
82*/
83fsync(fd1);84ret = brstub_validate_version(bpath, startversion);85if (ret != 0)86goto err;87ret = write(fd1, string, strlen(string));88if (ret <= 0)89goto err;90fsync(fd1); /* let it reach the disk */91
92ret = brstub_validate_version(bpath, startversion);93if (ret != 0)94goto err;95
96close(fd1);97
98/**99* Well, this is not a _real_ test per se . For this test to pass
100* the inode should not get a forget() in the interim. Therefore,
101* perform this test asap.
102*/
103
104/* multi open (write/) check */105fd1 = open(filp, O_RDWR);106if (fd1 < 0)107goto err;108fd2 = open(filp, O_WRONLY);109if (fd1 < 0)110goto err;111
112ret = write(fd1, string, strlen(string));113if (ret <= 0)114goto err;115
116ret = write(fd2, string, strlen(string));117if (ret <= 0)118goto err;119
120/* probably do a syncfs() */121fsync(fd1);122fsync(fd2);123
124close(fd1);125close(fd2);126
127/**128* incremented once per write()/write().../close()/close() sequence
129*/
130ret = brstub_validate_version(bpath, startversion);131if (ret != 0)132goto err;133
134return 0;135
136err:137return -1;138}
139
140int
141brstub_new_object_validate(char *filp, char *brick)142{
143int ret = 0;144char *fname = NULL;145char bpath[PATH_MAX] = {1460,147};148
149fname = basename(filp);150if (!fname)151goto err;152
153(void)snprintf(bpath, PATH_MAX, "%s/%s", brick, fname);154
155printf("Validating initial version..\n");156ret = brstub_validate_version(bpath, 2);157if (ret != -2) /* version _should_ be missing */158goto err;159
160printf("Validating version on modifications..\n");161ret = brstub_write_validation(filp, bpath, 2);162if (ret < 0)163goto err;164
165return 0;166
167err:168return -1;169}
170
171int
172main(int argc, char **argv)173{
174int ret = 0;175char *filp = NULL;176char *brick = NULL;177
178if (argc != 3) {179printf("Usage: %s <path> <brick>\n", argv[0]);180goto err;181}182
183filp = argv[1];184brick = argv[2];185
186printf("Validating object version [%s]\n", filp);187ret = brstub_new_object_validate(filp, brick);188if (ret < 0)189goto err;190
191return 0;192
193err:194return -1;195}
196