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