3
0

unix_io.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703
  1. /* vi: set sw=4 ts=4: */
  2. /*
  3. * unix_io.c --- This is the Unix (well, really POSIX) implementation
  4. * of the I/O manager.
  5. *
  6. * Implements a one-block write-through cache.
  7. *
  8. * Includes support for Windows NT support under Cygwin.
  9. *
  10. * Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
  11. * 2002 by Theodore Ts'o.
  12. *
  13. * %Begin-Header%
  14. * This file may be redistributed under the terms of the GNU Public
  15. * License.
  16. * %End-Header%
  17. */
  18. #include <stdio.h>
  19. #include <string.h>
  20. #if HAVE_UNISTD_H
  21. #include <unistd.h>
  22. #endif
  23. #if HAVE_ERRNO_H
  24. #include <errno.h>
  25. #endif
  26. #include <fcntl.h>
  27. #include <time.h>
  28. #ifdef __linux__
  29. #include <sys/utsname.h>
  30. #endif
  31. #if HAVE_SYS_STAT_H
  32. #include <sys/stat.h>
  33. #endif
  34. #if HAVE_SYS_TYPES_H
  35. #include <sys/types.h>
  36. #endif
  37. #include <sys/resource.h>
  38. #include "ext2_fs.h"
  39. #include "ext2fs.h"
  40. /*
  41. * For checking structure magic numbers...
  42. */
  43. #define EXT2_CHECK_MAGIC(struct, code) \
  44. if ((struct)->magic != (code)) return (code)
  45. struct unix_cache {
  46. char *buf;
  47. unsigned long block;
  48. int access_time;
  49. unsigned dirty:1;
  50. unsigned in_use:1;
  51. };
  52. #define CACHE_SIZE 8
  53. #define WRITE_DIRECT_SIZE 4 /* Must be smaller than CACHE_SIZE */
  54. #define READ_DIRECT_SIZE 4 /* Should be smaller than CACHE_SIZE */
  55. struct unix_private_data {
  56. int magic;
  57. int dev;
  58. int flags;
  59. int access_time;
  60. ext2_loff_t offset;
  61. struct unix_cache cache[CACHE_SIZE];
  62. };
  63. static errcode_t unix_open(const char *name, int flags, io_channel *channel);
  64. static errcode_t unix_close(io_channel channel);
  65. static errcode_t unix_set_blksize(io_channel channel, int blksize);
  66. static errcode_t unix_read_blk(io_channel channel, unsigned long block,
  67. int count, void *data);
  68. static errcode_t unix_write_blk(io_channel channel, unsigned long block,
  69. int count, const void *data);
  70. static errcode_t unix_flush(io_channel channel);
  71. static errcode_t unix_write_byte(io_channel channel, unsigned long offset,
  72. int size, const void *data);
  73. static errcode_t unix_set_option(io_channel channel, const char *option,
  74. const char *arg);
  75. static void reuse_cache(io_channel channel, struct unix_private_data *data,
  76. struct unix_cache *cache, unsigned long block);
  77. /* __FreeBSD_kernel__ is defined by GNU/kFreeBSD - the FreeBSD kernel
  78. * does not know buffered block devices - everything is raw. */
  79. #if defined(__CYGWIN__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
  80. #define NEED_BOUNCE_BUFFER
  81. #else
  82. #undef NEED_BOUNCE_BUFFER
  83. #endif
  84. static struct struct_io_manager struct_unix_manager = {
  85. EXT2_ET_MAGIC_IO_MANAGER,
  86. "Unix I/O Manager",
  87. unix_open,
  88. unix_close,
  89. unix_set_blksize,
  90. unix_read_blk,
  91. unix_write_blk,
  92. unix_flush,
  93. #ifdef NEED_BOUNCE_BUFFER
  94. 0,
  95. #else
  96. unix_write_byte,
  97. #endif
  98. unix_set_option
  99. };
  100. io_manager unix_io_manager = &struct_unix_manager;
  101. /*
  102. * Here are the raw I/O functions
  103. */
  104. #ifndef NEED_BOUNCE_BUFFER
  105. static errcode_t raw_read_blk(io_channel channel,
  106. struct unix_private_data *data,
  107. unsigned long block,
  108. int count, void *buf)
  109. {
  110. errcode_t retval;
  111. ssize_t size;
  112. ext2_loff_t location;
  113. int actual = 0;
  114. size = (count < 0) ? -count : count * channel->block_size;
  115. location = ((ext2_loff_t) block * channel->block_size) + data->offset;
  116. if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) {
  117. retval = errno ? errno : EXT2_ET_LLSEEK_FAILED;
  118. goto error_out;
  119. }
  120. actual = read(data->dev, buf, size);
  121. if (actual != size) {
  122. if (actual < 0)
  123. actual = 0;
  124. retval = EXT2_ET_SHORT_READ;
  125. goto error_out;
  126. }
  127. return 0;
  128. error_out:
  129. memset((char *) buf+actual, 0, size-actual);
  130. if (channel->read_error)
  131. retval = (channel->read_error)(channel, block, count, buf,
  132. size, actual, retval);
  133. return retval;
  134. }
  135. #else /* NEED_BOUNCE_BUFFER */
  136. /*
  137. * Windows and FreeBSD block devices only allow sector alignment IO in offset and size
  138. */
  139. static errcode_t raw_read_blk(io_channel channel,
  140. struct unix_private_data *data,
  141. unsigned long block,
  142. int count, void *buf)
  143. {
  144. errcode_t retval;
  145. size_t size, alignsize, fragment;
  146. ext2_loff_t location;
  147. int total = 0, actual;
  148. #define BLOCKALIGN 512
  149. char sector[BLOCKALIGN];
  150. size = (count < 0) ? -count : count * channel->block_size;
  151. location = ((ext2_loff_t) block * channel->block_size) + data->offset;
  152. #ifdef DEBUG
  153. printf("count=%d, size=%d, block=%d, blk_size=%d, location=%lx\n",
  154. count, size, block, channel->block_size, location);
  155. #endif
  156. if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) {
  157. retval = errno ? errno : EXT2_ET_LLSEEK_FAILED;
  158. goto error_out;
  159. }
  160. fragment = size % BLOCKALIGN;
  161. alignsize = size - fragment;
  162. if (alignsize) {
  163. actual = read(data->dev, buf, alignsize);
  164. if (actual != alignsize)
  165. goto short_read;
  166. }
  167. if (fragment) {
  168. actual = read(data->dev, sector, BLOCKALIGN);
  169. if (actual != BLOCKALIGN)
  170. goto short_read;
  171. memcpy(buf+alignsize, sector, fragment);
  172. }
  173. return 0;
  174. short_read:
  175. if (actual>0)
  176. total += actual;
  177. retval = EXT2_ET_SHORT_READ;
  178. error_out:
  179. memset((char *) buf+total, 0, size-actual);
  180. if (channel->read_error)
  181. retval = (channel->read_error)(channel, block, count, buf,
  182. size, actual, retval);
  183. return retval;
  184. }
  185. #endif
  186. static errcode_t raw_write_blk(io_channel channel,
  187. struct unix_private_data *data,
  188. unsigned long block,
  189. int count, const void *buf)
  190. {
  191. ssize_t size;
  192. ext2_loff_t location;
  193. int actual = 0;
  194. errcode_t retval;
  195. if (count == 1)
  196. size = channel->block_size;
  197. else {
  198. if (count < 0)
  199. size = -count;
  200. else
  201. size = count * channel->block_size;
  202. }
  203. location = ((ext2_loff_t) block * channel->block_size) + data->offset;
  204. if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) {
  205. retval = errno ? errno : EXT2_ET_LLSEEK_FAILED;
  206. goto error_out;
  207. }
  208. actual = write(data->dev, buf, size);
  209. if (actual != size) {
  210. retval = EXT2_ET_SHORT_WRITE;
  211. goto error_out;
  212. }
  213. return 0;
  214. error_out:
  215. if (channel->write_error)
  216. retval = (channel->write_error)(channel, block, count, buf,
  217. size, actual, retval);
  218. return retval;
  219. }
  220. /*
  221. * Here we implement the cache functions
  222. */
  223. /* Allocate the cache buffers */
  224. static errcode_t alloc_cache(io_channel channel,
  225. struct unix_private_data *data)
  226. {
  227. errcode_t retval;
  228. struct unix_cache *cache;
  229. int i;
  230. data->access_time = 0;
  231. for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
  232. cache->block = 0;
  233. cache->access_time = 0;
  234. cache->dirty = 0;
  235. cache->in_use = 0;
  236. if ((retval = ext2fs_get_mem(channel->block_size,
  237. &cache->buf)))
  238. return retval;
  239. }
  240. return 0;
  241. }
  242. /* Free the cache buffers */
  243. static void free_cache(struct unix_private_data *data)
  244. {
  245. struct unix_cache *cache;
  246. int i;
  247. data->access_time = 0;
  248. for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
  249. cache->block = 0;
  250. cache->access_time = 0;
  251. cache->dirty = 0;
  252. cache->in_use = 0;
  253. ext2fs_free_mem(&cache->buf);
  254. cache->buf = 0;
  255. }
  256. }
  257. #ifndef NO_IO_CACHE
  258. /*
  259. * Try to find a block in the cache. If the block is not found, and
  260. * eldest is a non-zero pointer, then fill in eldest with the cache
  261. * entry to that should be reused.
  262. */
  263. static struct unix_cache *find_cached_block(struct unix_private_data *data,
  264. unsigned long block,
  265. struct unix_cache **eldest)
  266. {
  267. struct unix_cache *cache, *unused_cache, *oldest_cache;
  268. int i;
  269. unused_cache = oldest_cache = 0;
  270. for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
  271. if (!cache->in_use) {
  272. if (!unused_cache)
  273. unused_cache = cache;
  274. continue;
  275. }
  276. if (cache->block == block) {
  277. cache->access_time = ++data->access_time;
  278. return cache;
  279. }
  280. if (!oldest_cache ||
  281. (cache->access_time < oldest_cache->access_time))
  282. oldest_cache = cache;
  283. }
  284. if (eldest)
  285. *eldest = (unused_cache) ? unused_cache : oldest_cache;
  286. return 0;
  287. }
  288. /*
  289. * Reuse a particular cache entry for another block.
  290. */
  291. static void reuse_cache(io_channel channel, struct unix_private_data *data,
  292. struct unix_cache *cache, unsigned long block)
  293. {
  294. if (cache->dirty && cache->in_use)
  295. raw_write_blk(channel, data, cache->block, 1, cache->buf);
  296. cache->in_use = 1;
  297. cache->dirty = 0;
  298. cache->block = block;
  299. cache->access_time = ++data->access_time;
  300. }
  301. /*
  302. * Flush all of the blocks in the cache
  303. */
  304. static errcode_t flush_cached_blocks(io_channel channel,
  305. struct unix_private_data *data,
  306. int invalidate)
  307. {
  308. struct unix_cache *cache;
  309. errcode_t retval, retval2;
  310. int i;
  311. retval2 = 0;
  312. for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
  313. if (!cache->in_use)
  314. continue;
  315. if (invalidate)
  316. cache->in_use = 0;
  317. if (!cache->dirty)
  318. continue;
  319. retval = raw_write_blk(channel, data,
  320. cache->block, 1, cache->buf);
  321. if (retval)
  322. retval2 = retval;
  323. else
  324. cache->dirty = 0;
  325. }
  326. return retval2;
  327. }
  328. #endif /* NO_IO_CACHE */
  329. static errcode_t unix_open(const char *name, int flags, io_channel *channel)
  330. {
  331. io_channel io = NULL;
  332. struct unix_private_data *data = NULL;
  333. errcode_t retval;
  334. int open_flags;
  335. struct stat st;
  336. #ifdef __linux__
  337. struct utsname ut;
  338. #endif
  339. if (name == 0)
  340. return EXT2_ET_BAD_DEVICE_NAME;
  341. retval = ext2fs_get_mem(sizeof(struct struct_io_channel), &io);
  342. if (retval)
  343. return retval;
  344. memset(io, 0, sizeof(struct struct_io_channel));
  345. io->magic = EXT2_ET_MAGIC_IO_CHANNEL;
  346. retval = ext2fs_get_mem(sizeof(struct unix_private_data), &data);
  347. if (retval)
  348. goto cleanup;
  349. io->manager = unix_io_manager;
  350. retval = ext2fs_get_mem(strlen(name)+1, &io->name);
  351. if (retval)
  352. goto cleanup;
  353. strcpy(io->name, name);
  354. io->private_data = data;
  355. io->block_size = 1024;
  356. io->read_error = 0;
  357. io->write_error = 0;
  358. io->refcount = 1;
  359. memset(data, 0, sizeof(struct unix_private_data));
  360. data->magic = EXT2_ET_MAGIC_UNIX_IO_CHANNEL;
  361. if ((retval = alloc_cache(io, data)))
  362. goto cleanup;
  363. open_flags = (flags & IO_FLAG_RW) ? O_RDWR : O_RDONLY;
  364. #ifdef CONFIG_LFS
  365. data->dev = open64(io->name, open_flags);
  366. #else
  367. data->dev = open(io->name, open_flags);
  368. #endif
  369. if (data->dev < 0) {
  370. retval = errno;
  371. goto cleanup;
  372. }
  373. #ifdef __linux__
  374. #undef RLIM_INFINITY
  375. #if (defined(__alpha__) || ((defined(__sparc__) || defined(__mips__)) && (SIZEOF_LONG == 4)))
  376. #define RLIM_INFINITY ((unsigned long)(~0UL>>1))
  377. #else
  378. #define RLIM_INFINITY (~0UL)
  379. #endif
  380. /*
  381. * Work around a bug in 2.4.10-2.4.18 kernels where writes to
  382. * block devices are wrongly getting hit by the filesize
  383. * limit. This workaround isn't perfect, since it won't work
  384. * if glibc wasn't built against 2.2 header files. (Sigh.)
  385. *
  386. */
  387. if ((flags & IO_FLAG_RW) &&
  388. (uname(&ut) == 0) &&
  389. ((ut.release[0] == '2') && (ut.release[1] == '.') &&
  390. (ut.release[2] == '4') && (ut.release[3] == '.') &&
  391. (ut.release[4] == '1') && (ut.release[5] >= '0') &&
  392. (ut.release[5] < '8')) &&
  393. (fstat(data->dev, &st) == 0) &&
  394. (S_ISBLK(st.st_mode))) {
  395. struct rlimit rlim;
  396. rlim.rlim_cur = rlim.rlim_max = (unsigned long) RLIM_INFINITY;
  397. setrlimit(RLIMIT_FSIZE, &rlim);
  398. getrlimit(RLIMIT_FSIZE, &rlim);
  399. if (((unsigned long) rlim.rlim_cur) <
  400. ((unsigned long) rlim.rlim_max)) {
  401. rlim.rlim_cur = rlim.rlim_max;
  402. setrlimit(RLIMIT_FSIZE, &rlim);
  403. }
  404. }
  405. #endif
  406. *channel = io;
  407. return 0;
  408. cleanup:
  409. if (data) {
  410. free_cache(data);
  411. ext2fs_free_mem(&data);
  412. }
  413. ext2fs_free_mem(&io);
  414. return retval;
  415. }
  416. static errcode_t unix_close(io_channel channel)
  417. {
  418. struct unix_private_data *data;
  419. errcode_t retval = 0;
  420. EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
  421. data = (struct unix_private_data *) channel->private_data;
  422. EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
  423. if (--channel->refcount > 0)
  424. return 0;
  425. #ifndef NO_IO_CACHE
  426. retval = flush_cached_blocks(channel, data, 0);
  427. #endif
  428. if (close(data->dev) < 0)
  429. retval = errno;
  430. free_cache(data);
  431. ext2fs_free_mem(&channel->private_data);
  432. ext2fs_free_mem(&channel->name);
  433. ext2fs_free_mem(&channel);
  434. return retval;
  435. }
  436. static errcode_t unix_set_blksize(io_channel channel, int blksize)
  437. {
  438. struct unix_private_data *data;
  439. errcode_t retval;
  440. EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
  441. data = (struct unix_private_data *) channel->private_data;
  442. EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
  443. if (channel->block_size != blksize) {
  444. #ifndef NO_IO_CACHE
  445. if ((retval = flush_cached_blocks(channel, data, 0)))
  446. return retval;
  447. #endif
  448. channel->block_size = blksize;
  449. free_cache(data);
  450. if ((retval = alloc_cache(channel, data)))
  451. return retval;
  452. }
  453. return 0;
  454. }
  455. static errcode_t unix_read_blk(io_channel channel, unsigned long block,
  456. int count, void *buf)
  457. {
  458. struct unix_private_data *data;
  459. struct unix_cache *cache, *reuse[READ_DIRECT_SIZE];
  460. errcode_t retval;
  461. char *cp;
  462. int i, j;
  463. EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
  464. data = (struct unix_private_data *) channel->private_data;
  465. EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
  466. #ifdef NO_IO_CACHE
  467. return raw_read_blk(channel, data, block, count, buf);
  468. #else
  469. /*
  470. * If we're doing an odd-sized read or a very large read,
  471. * flush out the cache and then do a direct read.
  472. */
  473. if (count < 0 || count > WRITE_DIRECT_SIZE) {
  474. if ((retval = flush_cached_blocks(channel, data, 0)))
  475. return retval;
  476. return raw_read_blk(channel, data, block, count, buf);
  477. }
  478. cp = buf;
  479. while (count > 0) {
  480. /* If it's in the cache, use it! */
  481. if ((cache = find_cached_block(data, block, &reuse[0]))) {
  482. #ifdef DEBUG
  483. printf("Using cached block %d\n", block);
  484. #endif
  485. memcpy(cp, cache->buf, channel->block_size);
  486. count--;
  487. block++;
  488. cp += channel->block_size;
  489. continue;
  490. }
  491. /*
  492. * Find the number of uncached blocks so we can do a
  493. * single read request
  494. */
  495. for (i=1; i < count; i++)
  496. if (find_cached_block(data, block+i, &reuse[i]))
  497. break;
  498. #ifdef DEBUG
  499. printf("Reading %d blocks starting at %d\n", i, block);
  500. #endif
  501. if ((retval = raw_read_blk(channel, data, block, i, cp)))
  502. return retval;
  503. /* Save the results in the cache */
  504. for (j=0; j < i; j++) {
  505. count--;
  506. cache = reuse[j];
  507. reuse_cache(channel, data, cache, block++);
  508. memcpy(cache->buf, cp, channel->block_size);
  509. cp += channel->block_size;
  510. }
  511. }
  512. return 0;
  513. #endif /* NO_IO_CACHE */
  514. }
  515. static errcode_t unix_write_blk(io_channel channel, unsigned long block,
  516. int count, const void *buf)
  517. {
  518. struct unix_private_data *data;
  519. struct unix_cache *cache, *reuse;
  520. errcode_t retval = 0;
  521. const char *cp;
  522. int writethrough;
  523. EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
  524. data = (struct unix_private_data *) channel->private_data;
  525. EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
  526. #ifdef NO_IO_CACHE
  527. return raw_write_blk(channel, data, block, count, buf);
  528. #else
  529. /*
  530. * If we're doing an odd-sized write or a very large write,
  531. * flush out the cache completely and then do a direct write.
  532. */
  533. if (count < 0 || count > WRITE_DIRECT_SIZE) {
  534. if ((retval = flush_cached_blocks(channel, data, 1)))
  535. return retval;
  536. return raw_write_blk(channel, data, block, count, buf);
  537. }
  538. /*
  539. * For a moderate-sized multi-block write, first force a write
  540. * if we're in write-through cache mode, and then fill the
  541. * cache with the blocks.
  542. */
  543. writethrough = channel->flags & CHANNEL_FLAGS_WRITETHROUGH;
  544. if (writethrough)
  545. retval = raw_write_blk(channel, data, block, count, buf);
  546. cp = buf;
  547. while (count > 0) {
  548. cache = find_cached_block(data, block, &reuse);
  549. if (!cache) {
  550. cache = reuse;
  551. reuse_cache(channel, data, cache, block);
  552. }
  553. memcpy(cache->buf, cp, channel->block_size);
  554. cache->dirty = !writethrough;
  555. count--;
  556. block++;
  557. cp += channel->block_size;
  558. }
  559. return retval;
  560. #endif /* NO_IO_CACHE */
  561. }
  562. static errcode_t unix_write_byte(io_channel channel, unsigned long offset,
  563. int size, const void *buf)
  564. {
  565. struct unix_private_data *data;
  566. errcode_t retval = 0;
  567. ssize_t actual;
  568. EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
  569. data = (struct unix_private_data *) channel->private_data;
  570. EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
  571. #ifndef NO_IO_CACHE
  572. /*
  573. * Flush out the cache completely
  574. */
  575. if ((retval = flush_cached_blocks(channel, data, 1)))
  576. return retval;
  577. #endif
  578. if (lseek(data->dev, offset + data->offset, SEEK_SET) < 0)
  579. return errno;
  580. actual = write(data->dev, buf, size);
  581. if (actual != size)
  582. return EXT2_ET_SHORT_WRITE;
  583. return 0;
  584. }
  585. /*
  586. * Flush data buffers to disk.
  587. */
  588. static errcode_t unix_flush(io_channel channel)
  589. {
  590. struct unix_private_data *data;
  591. errcode_t retval = 0;
  592. EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
  593. data = (struct unix_private_data *) channel->private_data;
  594. EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
  595. #ifndef NO_IO_CACHE
  596. retval = flush_cached_blocks(channel, data, 0);
  597. #endif
  598. fsync(data->dev);
  599. return retval;
  600. }
  601. static errcode_t unix_set_option(io_channel channel, const char *option,
  602. const char *arg)
  603. {
  604. struct unix_private_data *data;
  605. unsigned long tmp;
  606. char *end;
  607. EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
  608. data = (struct unix_private_data *) channel->private_data;
  609. EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
  610. if (!strcmp(option, "offset")) {
  611. if (!arg)
  612. return EXT2_ET_INVALID_ARGUMENT;
  613. tmp = strtoul(arg, &end, 0);
  614. if (*end)
  615. return EXT2_ET_INVALID_ARGUMENT;
  616. data->offset = tmp;
  617. return 0;
  618. }
  619. return EXT2_ET_INVALID_ARGUMENT;
  620. }