PageRenderTime 28ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/samba-3.5.6/source3/torture/locktest2.c

https://github.com/theuni/XBMC-deps
C | 571 lines | 448 code | 87 blank | 36 comment | 85 complexity | 15efb78ee47af3e9575412eddea61f18 MD5 | raw file
  1. /*
  2. Unix SMB/CIFS implementation.
  3. byte range lock tester - with local filesystem support
  4. Copyright (C) Andrew Tridgell 1999
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 3 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. */
  16. #include "includes.h"
  17. static fstring password;
  18. static fstring username;
  19. static int got_pass;
  20. static int numops = 1000;
  21. static bool showall;
  22. static bool analyze;
  23. static bool hide_unlock_fails;
  24. static bool use_oplocks;
  25. extern char *optarg;
  26. extern int optind;
  27. #define FILENAME "\\locktest.dat"
  28. #define LOCKRANGE 100
  29. #define LOCKBASE 0
  30. /*
  31. #define LOCKBASE (0x40000000 - 50)
  32. */
  33. #define READ_PCT 50
  34. #define LOCK_PCT 25
  35. #define UNLOCK_PCT 65
  36. #define RANGE_MULTIPLE 1
  37. #define NSERVERS 2
  38. #define NCONNECTIONS 2
  39. #define NUMFSTYPES 2
  40. #define NFILES 2
  41. #define LOCK_TIMEOUT 0
  42. #define FSTYPE_SMB 0
  43. #define FSTYPE_NFS 1
  44. struct record {
  45. char r1, r2;
  46. char conn, f, fstype;
  47. unsigned start, len;
  48. char needed;
  49. };
  50. static struct record *recorded;
  51. static int try_open(struct cli_state *c, char *nfs, int fstype, const char *fname, int flags)
  52. {
  53. char *path;
  54. switch (fstype) {
  55. case FSTYPE_SMB:
  56. {
  57. uint16_t fd;
  58. if (!NT_STATUS_IS_OK(cli_open(c, fname, flags, DENY_NONE, &fd))) {
  59. return -1;
  60. }
  61. return fd;
  62. }
  63. case FSTYPE_NFS:
  64. if (asprintf(&path, "%s%s", nfs, fname) > 0) {
  65. int ret;
  66. string_replace(path,'\\', '/');
  67. ret = open(path, flags, 0666);
  68. SAFE_FREE(path);
  69. return ret;
  70. }
  71. break;
  72. }
  73. return -1;
  74. }
  75. static bool try_close(struct cli_state *c, int fstype, int fd)
  76. {
  77. switch (fstype) {
  78. case FSTYPE_SMB:
  79. return NT_STATUS_IS_OK(cli_close(c, fd));
  80. case FSTYPE_NFS:
  81. return close(fd) == 0;
  82. }
  83. return False;
  84. }
  85. static bool try_lock(struct cli_state *c, int fstype,
  86. int fd, unsigned start, unsigned len,
  87. enum brl_type op)
  88. {
  89. struct flock lock;
  90. switch (fstype) {
  91. case FSTYPE_SMB:
  92. return cli_lock(c, fd, start, len, LOCK_TIMEOUT, op);
  93. case FSTYPE_NFS:
  94. lock.l_type = (op==READ_LOCK) ? F_RDLCK:F_WRLCK;
  95. lock.l_whence = SEEK_SET;
  96. lock.l_start = start;
  97. lock.l_len = len;
  98. lock.l_pid = getpid();
  99. return fcntl(fd,F_SETLK,&lock) == 0;
  100. }
  101. return False;
  102. }
  103. static bool try_unlock(struct cli_state *c, int fstype,
  104. int fd, unsigned start, unsigned len)
  105. {
  106. struct flock lock;
  107. switch (fstype) {
  108. case FSTYPE_SMB:
  109. return NT_STATUS_IS_OK(cli_unlock(c, fd, start, len));
  110. case FSTYPE_NFS:
  111. lock.l_type = F_UNLCK;
  112. lock.l_whence = SEEK_SET;
  113. lock.l_start = start;
  114. lock.l_len = len;
  115. lock.l_pid = getpid();
  116. return fcntl(fd,F_SETLK,&lock) == 0;
  117. }
  118. return False;
  119. }
  120. static void print_brl(struct file_id id, struct server_id pid,
  121. enum brl_type lock_type,
  122. enum brl_flavour lock_flav,
  123. br_off start, br_off size,
  124. void *private_data)
  125. {
  126. printf("%6d %s %s %.0f:%.0f(%.0f)\n",
  127. (int)procid_to_pid(&pid), file_id_string_tos(&id),
  128. lock_type==READ_LOCK?"R":"W",
  129. (double)start, (double)start+size-1,(double)size);
  130. }
  131. /*****************************************************
  132. return a connection to a server
  133. *******************************************************/
  134. static struct cli_state *connect_one(char *share)
  135. {
  136. struct cli_state *c;
  137. char *server_n;
  138. fstring server;
  139. fstring myname;
  140. static int count;
  141. NTSTATUS nt_status;
  142. fstrcpy(server,share+2);
  143. share = strchr_m(server,'\\');
  144. if (!share) return NULL;
  145. *share = 0;
  146. share++;
  147. server_n = server;
  148. if (!got_pass) {
  149. char *pass = getpass("Password: ");
  150. if (pass) {
  151. fstrcpy(password, pass);
  152. }
  153. }
  154. slprintf(myname,sizeof(myname), "lock-%lu-%u", (unsigned long)getpid(), count++);
  155. nt_status = cli_full_connection(&c, myname, server_n, NULL, 0, share, "?????",
  156. username, lp_workgroup(), password, 0,
  157. Undefined, NULL);
  158. if (!NT_STATUS_IS_OK(nt_status)) {
  159. DEBUG(0, ("cli_full_connection failed with error %s\n", nt_errstr(nt_status)));
  160. return NULL;
  161. }
  162. c->use_oplocks = use_oplocks;
  163. return c;
  164. }
  165. static void reconnect(struct cli_state *cli[NSERVERS][NCONNECTIONS],
  166. char *nfs[NSERVERS],
  167. int fnum[NSERVERS][NUMFSTYPES][NCONNECTIONS][NFILES],
  168. char *share1, char *share2)
  169. {
  170. int server, conn, f, fstype;
  171. char *share[2];
  172. share[0] = share1;
  173. share[1] = share2;
  174. fstype = FSTYPE_SMB;
  175. for (server=0;server<NSERVERS;server++)
  176. for (conn=0;conn<NCONNECTIONS;conn++) {
  177. if (cli[server][conn]) {
  178. for (f=0;f<NFILES;f++) {
  179. cli_close(cli[server][conn], fnum[server][fstype][conn][f]);
  180. }
  181. cli_ulogoff(cli[server][conn]);
  182. cli_shutdown(cli[server][conn]);
  183. }
  184. cli[server][conn] = connect_one(share[server]);
  185. if (!cli[server][conn]) {
  186. DEBUG(0,("Failed to connect to %s\n", share[server]));
  187. exit(1);
  188. }
  189. }
  190. }
  191. static bool test_one(struct cli_state *cli[NSERVERS][NCONNECTIONS],
  192. char *nfs[NSERVERS],
  193. int fnum[NSERVERS][NUMFSTYPES][NCONNECTIONS][NFILES],
  194. struct record *rec)
  195. {
  196. unsigned conn = rec->conn;
  197. unsigned f = rec->f;
  198. unsigned fstype = rec->fstype;
  199. unsigned start = rec->start;
  200. unsigned len = rec->len;
  201. unsigned r1 = rec->r1;
  202. unsigned r2 = rec->r2;
  203. enum brl_type op;
  204. int server;
  205. bool ret[NSERVERS];
  206. if (r1 < READ_PCT) {
  207. op = READ_LOCK;
  208. } else {
  209. op = WRITE_LOCK;
  210. }
  211. if (r2 < LOCK_PCT) {
  212. /* set a lock */
  213. for (server=0;server<NSERVERS;server++) {
  214. ret[server] = try_lock(cli[server][conn], fstype,
  215. fnum[server][fstype][conn][f],
  216. start, len, op);
  217. }
  218. if (showall || ret[0] != ret[1]) {
  219. printf("lock conn=%u fstype=%u f=%u range=%u:%u(%u) op=%s -> %u:%u\n",
  220. conn, fstype, f,
  221. start, start+len-1, len,
  222. op==READ_LOCK?"READ_LOCK":"WRITE_LOCK",
  223. ret[0], ret[1]);
  224. }
  225. if (showall) brl_forall(print_brl, NULL);
  226. if (ret[0] != ret[1]) return False;
  227. } else if (r2 < LOCK_PCT+UNLOCK_PCT) {
  228. /* unset a lock */
  229. for (server=0;server<NSERVERS;server++) {
  230. ret[server] = try_unlock(cli[server][conn], fstype,
  231. fnum[server][fstype][conn][f],
  232. start, len);
  233. }
  234. if (showall || (!hide_unlock_fails && (ret[0] != ret[1]))) {
  235. printf("unlock conn=%u fstype=%u f=%u range=%u:%u(%u) -> %u:%u\n",
  236. conn, fstype, f,
  237. start, start+len-1, len,
  238. ret[0], ret[1]);
  239. }
  240. if (showall) brl_forall(print_brl, NULL);
  241. if (!hide_unlock_fails && ret[0] != ret[1]) return False;
  242. } else {
  243. /* reopen the file */
  244. for (server=0;server<NSERVERS;server++) {
  245. try_close(cli[server][conn], fstype, fnum[server][fstype][conn][f]);
  246. fnum[server][fstype][conn][f] = try_open(cli[server][conn], nfs[server], fstype, FILENAME,
  247. O_RDWR|O_CREAT);
  248. if (fnum[server][fstype][conn][f] == -1) {
  249. printf("failed to reopen on share1\n");
  250. return False;
  251. }
  252. }
  253. if (showall) {
  254. printf("reopen conn=%u fstype=%u f=%u\n",
  255. conn, fstype, f);
  256. brl_forall(print_brl, NULL);
  257. }
  258. }
  259. return True;
  260. }
  261. static void close_files(struct cli_state *cli[NSERVERS][NCONNECTIONS],
  262. char *nfs[NSERVERS],
  263. int fnum[NSERVERS][NUMFSTYPES][NCONNECTIONS][NFILES])
  264. {
  265. int server, conn, f, fstype;
  266. for (server=0;server<NSERVERS;server++)
  267. for (fstype=0;fstype<NUMFSTYPES;fstype++)
  268. for (conn=0;conn<NCONNECTIONS;conn++)
  269. for (f=0;f<NFILES;f++) {
  270. if (fnum[server][fstype][conn][f] != -1) {
  271. try_close(cli[server][conn], fstype, fnum[server][fstype][conn][f]);
  272. fnum[server][fstype][conn][f] = -1;
  273. }
  274. }
  275. for (server=0;server<NSERVERS;server++) {
  276. cli_unlink(cli[server][0], FILENAME, aSYSTEM | aHIDDEN);
  277. }
  278. }
  279. static void open_files(struct cli_state *cli[NSERVERS][NCONNECTIONS],
  280. char *nfs[NSERVERS],
  281. int fnum[NSERVERS][NUMFSTYPES][NCONNECTIONS][NFILES])
  282. {
  283. int server, fstype, conn, f;
  284. for (server=0;server<NSERVERS;server++)
  285. for (fstype=0;fstype<NUMFSTYPES;fstype++)
  286. for (conn=0;conn<NCONNECTIONS;conn++)
  287. for (f=0;f<NFILES;f++) {
  288. fnum[server][fstype][conn][f] = try_open(cli[server][conn], nfs[server], fstype, FILENAME,
  289. O_RDWR|O_CREAT);
  290. if (fnum[server][fstype][conn][f] == -1) {
  291. fprintf(stderr,"Failed to open fnum[%u][%u][%u][%u]\n",
  292. server, fstype, conn, f);
  293. exit(1);
  294. }
  295. }
  296. }
  297. static int retest(struct cli_state *cli[NSERVERS][NCONNECTIONS],
  298. char *nfs[NSERVERS],
  299. int fnum[NSERVERS][NUMFSTYPES][NCONNECTIONS][NFILES],
  300. int n)
  301. {
  302. int i;
  303. printf("testing %u ...\n", n);
  304. for (i=0; i<n; i++) {
  305. if (i && i % 100 == 0) {
  306. printf("%u\n", i);
  307. }
  308. if (recorded[i].needed &&
  309. !test_one(cli, nfs, fnum, &recorded[i])) return i;
  310. }
  311. return n;
  312. }
  313. /* each server has two connections open to it. Each connection has two file
  314. descriptors open on the file - 8 file descriptors in total
  315. we then do random locking ops in tamdem on the 4 fnums from each
  316. server and ensure that the results match
  317. */
  318. static void test_locks(char *share1, char *share2, char *nfspath1, char *nfspath2)
  319. {
  320. struct cli_state *cli[NSERVERS][NCONNECTIONS];
  321. char *nfs[NSERVERS];
  322. int fnum[NSERVERS][NUMFSTYPES][NCONNECTIONS][NFILES];
  323. int n, i, n1;
  324. nfs[0] = nfspath1;
  325. nfs[1] = nfspath2;
  326. ZERO_STRUCT(fnum);
  327. ZERO_STRUCT(cli);
  328. recorded = SMB_MALLOC_ARRAY(struct record, numops);
  329. for (n=0; n<numops; n++) {
  330. recorded[n].conn = random() % NCONNECTIONS;
  331. recorded[n].fstype = random() % NUMFSTYPES;
  332. recorded[n].f = random() % NFILES;
  333. recorded[n].start = LOCKBASE + ((unsigned)random() % (LOCKRANGE-1));
  334. recorded[n].len = 1 +
  335. random() % (LOCKRANGE-(recorded[n].start-LOCKBASE));
  336. recorded[n].start *= RANGE_MULTIPLE;
  337. recorded[n].len *= RANGE_MULTIPLE;
  338. recorded[n].r1 = random() % 100;
  339. recorded[n].r2 = random() % 100;
  340. recorded[n].needed = True;
  341. }
  342. reconnect(cli, nfs, fnum, share1, share2);
  343. open_files(cli, nfs, fnum);
  344. n = retest(cli, nfs, fnum, numops);
  345. if (n == numops || !analyze) return;
  346. n++;
  347. while (1) {
  348. n1 = n;
  349. close_files(cli, nfs, fnum);
  350. reconnect(cli, nfs, fnum, share1, share2);
  351. open_files(cli, nfs, fnum);
  352. for (i=0;i<n-1;i++) {
  353. int m;
  354. recorded[i].needed = False;
  355. close_files(cli, nfs, fnum);
  356. open_files(cli, nfs, fnum);
  357. m = retest(cli, nfs, fnum, n);
  358. if (m == n) {
  359. recorded[i].needed = True;
  360. } else {
  361. if (i < m) {
  362. memmove(&recorded[i], &recorded[i+1],
  363. (m-i)*sizeof(recorded[0]));
  364. }
  365. n = m;
  366. i--;
  367. }
  368. }
  369. if (n1 == n) break;
  370. }
  371. close_files(cli, nfs, fnum);
  372. reconnect(cli, nfs, fnum, share1, share2);
  373. open_files(cli, nfs, fnum);
  374. showall = True;
  375. n1 = retest(cli, nfs, fnum, n);
  376. if (n1 != n-1) {
  377. printf("ERROR - inconsistent result (%u %u)\n", n1, n);
  378. }
  379. close_files(cli, nfs, fnum);
  380. for (i=0;i<n;i++) {
  381. printf("{%u, %u, %u, %u, %u, %u, %u, %u},\n",
  382. recorded[i].r1,
  383. recorded[i].r2,
  384. recorded[i].conn,
  385. recorded[i].fstype,
  386. recorded[i].f,
  387. recorded[i].start,
  388. recorded[i].len,
  389. recorded[i].needed);
  390. }
  391. }
  392. static void usage(void)
  393. {
  394. printf(
  395. "Usage:\n\
  396. locktest //server1/share1 //server2/share2 /path1 /path2 [options..]\n\
  397. options:\n\
  398. -U user%%pass\n\
  399. -s seed\n\
  400. -o numops\n\
  401. -u hide unlock fails\n\
  402. -a (show all ops)\n\
  403. -O use oplocks\n\
  404. ");
  405. }
  406. /****************************************************************************
  407. main program
  408. ****************************************************************************/
  409. int main(int argc,char *argv[])
  410. {
  411. char *share1, *share2, *nfspath1, *nfspath2;
  412. int opt;
  413. char *p;
  414. int seed;
  415. setlinebuf(stdout);
  416. dbf = x_stderr;
  417. if (argc < 5 || argv[1][0] == '-') {
  418. usage();
  419. exit(1);
  420. }
  421. share1 = argv[1];
  422. share2 = argv[2];
  423. nfspath1 = argv[3];
  424. nfspath2 = argv[4];
  425. all_string_sub(share1,"/","\\",0);
  426. all_string_sub(share2,"/","\\",0);
  427. setup_logging(argv[0],True);
  428. argc -= 4;
  429. argv += 4;
  430. lp_load(get_dyn_CONFIGFILE(),True,False,False,True);
  431. load_interfaces();
  432. if (getenv("USER")) {
  433. fstrcpy(username,getenv("USER"));
  434. }
  435. seed = time(NULL);
  436. while ((opt = getopt(argc, argv, "U:s:ho:aAW:O")) != EOF) {
  437. switch (opt) {
  438. case 'U':
  439. fstrcpy(username,optarg);
  440. p = strchr_m(username,'%');
  441. if (p) {
  442. *p = 0;
  443. fstrcpy(password, p+1);
  444. got_pass = 1;
  445. }
  446. break;
  447. case 's':
  448. seed = atoi(optarg);
  449. break;
  450. case 'u':
  451. hide_unlock_fails = True;
  452. break;
  453. case 'o':
  454. numops = atoi(optarg);
  455. break;
  456. case 'O':
  457. use_oplocks = True;
  458. break;
  459. case 'a':
  460. showall = True;
  461. break;
  462. case 'A':
  463. analyze = True;
  464. break;
  465. case 'h':
  466. usage();
  467. exit(1);
  468. default:
  469. printf("Unknown option %c (%d)\n", (char)opt, opt);
  470. exit(1);
  471. }
  472. }
  473. argc -= optind;
  474. argv += optind;
  475. DEBUG(0,("seed=%u\n", seed));
  476. srandom(seed);
  477. locking_init_readonly();
  478. test_locks(share1, share2, nfspath1, nfspath2);
  479. return(0);
  480. }