diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1998-05-07 02:55:41 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1998-05-07 02:55:41 +0000 |
commit | dcec8a13bf565e47942a1751a9cec21bec5648fe (patch) | |
tree | 548b69625b18cc2e88c3e68d0923be546c9ebb03 /fs/ext2/file.c | |
parent | 2e0f55e79c49509b7ff70ff1a10e1e9e90a3dfd4 (diff) |
o Merge with Linux 2.1.99.
o Fix ancient bug in the ELF loader making ldd crash.
o Fix ancient bug in the keyboard code for SGI, SNI and Jazz.
Diffstat (limited to 'fs/ext2/file.c')
-rw-r--r-- | fs/ext2/file.c | 97 |
1 files changed, 83 insertions, 14 deletions
diff --git a/fs/ext2/file.c b/fs/ext2/file.c index 9c61f2f1c..143dc53d5 100644 --- a/fs/ext2/file.c +++ b/fs/ext2/file.c @@ -13,6 +13,9 @@ * Copyright (C) 1991, 1992 Linus Torvalds * * ext2 fs regular file handling primitives + * + * 64-bit file support on 64-bit platforms by Jakub Jelinek + * (jj@sunsite.ms.mff.cuni.cz) */ #include <asm/uaccess.h> @@ -36,6 +39,23 @@ static long long ext2_file_lseek(struct file *, long long, int); static ssize_t ext2_file_write (struct file *, const char *, size_t, loff_t *); static int ext2_release_file (struct inode *, struct file *); +#if BITS_PER_LONG < 64 +static int ext2_open_file (struct inode *, struct file *); + +#else + +#define EXT2_MAX_SIZE(bits) \ + (((EXT2_NDIR_BLOCKS + (1LL << (bits - 2)) + \ + (1LL << (bits - 2)) * (1LL << (bits - 2)) + \ + (1LL << (bits - 2)) * (1LL << (bits - 2)) * (1LL << (bits - 2))) * \ + (1LL << bits)) - 1) + +static long long ext2_max_sizes[] = { +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +EXT2_MAX_SIZE(10), EXT2_MAX_SIZE(11), EXT2_MAX_SIZE(12), EXT2_MAX_SIZE(13) +}; + +#endif /* * We have mostly NULL's here: the current defaults are ok for @@ -49,7 +69,11 @@ static struct file_operations ext2_file_operations = { NULL, /* poll - default */ ext2_ioctl, /* ioctl */ generic_file_mmap, /* mmap */ +#if BITS_PER_LONG == 64 NULL, /* no special open is needed */ +#else + ext2_open_file, +#endif ext2_release_file, /* release */ ext2_sync_file, /* fsync */ NULL, /* fasync */ @@ -86,7 +110,6 @@ static long long ext2_file_lseek( long long offset, int origin) { - long long retval; struct inode *inode = file->f_dentry->d_inode; switch (origin) { @@ -96,17 +119,20 @@ static long long ext2_file_lseek( case 1: offset += file->f_pos; } - retval = -EINVAL; - /* make sure the offset fits in 32 bits */ - if (((unsigned long long) offset >> 32) == 0) { - if (offset != file->f_pos) { - file->f_pos = offset; - file->f_reada = 0; - file->f_version = ++event; - } - retval = offset; + if (((unsigned long long) offset >> 32) != 0) { +#if BITS_PER_LONG < 64 + return -EINVAL; +#else + if (offset > ext2_max_sizes[EXT2_BLOCK_SIZE_BITS(inode->i_sb)]) + return -EINVAL; +#endif + } + if (offset != file->f_pos) { + file->f_pos = offset; + file->f_reada = 0; + file->f_version = ++event; } - return retval; + return offset; } static inline void remove_suid(struct inode *inode) @@ -128,7 +154,7 @@ static ssize_t ext2_file_write (struct file * filp, const char * buf, size_t count, loff_t *ppos) { struct inode * inode = filp->f_dentry->d_inode; - __u32 pos; + off_t pos; long block; int offset; int written, c; @@ -165,14 +191,39 @@ static ssize_t ext2_file_write (struct file * filp, const char * buf, pos = *ppos; if (pos != *ppos) return -EINVAL; +#if BITS_PER_LONG >= 64 + if (pos > ext2_max_sizes[EXT2_BLOCK_SIZE_BITS(sb)]) + return -EINVAL; +#endif } /* Check for overflow.. */ +#if BITS_PER_LONG < 64 if (pos > (__u32) (pos + count)) { count = ~pos; /* == 0xFFFFFFFF - pos */ if (!count) return -EFBIG; } +#else + { + off_t max = ext2_max_sizes[EXT2_BLOCK_SIZE_BITS(sb)]; + + if (pos + count > max) { + count = max - pos; + if (!count) + return -EFBIG; + } + if (((pos + count) >> 32) && + !(sb->u.ext2_sb.s_es->s_feature_ro_compat & + cpu_to_le32(EXT2_FEATURE_RO_COMPAT_LARGE_FILE))) { + /* If this is the first large file created, add a flag + to the superblock */ + sb->u.ext2_sb.s_es->s_feature_ro_compat |= + cpu_to_le32(EXT2_FEATURE_RO_COMPAT_LARGE_FILE); + mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1); + } + } +#endif /* * If a file has been opened in synchronous mode, we have to ensure @@ -219,6 +270,11 @@ static ssize_t ext2_file_write (struct file * filp, const char * buf, count -= c; mark_buffer_uptodate(bh, 1); mark_buffer_dirty(bh, 0); + + /* Mark the buffer untouched if we'll move on to the next one.. */ + if (!(pos & (sb->s_blocksize-1))) + clear_bit(BH_Touched, &bh->b_state); + if (filp->f_flags & O_SYNC) bufferlist[buffercount++] = bh; else @@ -260,12 +316,25 @@ static ssize_t ext2_file_write (struct file * filp, const char * buf, /* * Called when an inode is released. Note that this is different - * from ext2_open: open gets called at every open, but release + * from ext2_file_open: open gets called at every open, but release * gets called only when /all/ the files are closed. */ static int ext2_release_file (struct inode * inode, struct file * filp) { - if (filp->f_mode & 2) + if (filp->f_mode & FMODE_WRITE) ext2_discard_prealloc (inode); return 0; } + +#if BITS_PER_LONG < 64 +/* + * Called when an inode is about to be open. + * We use this to disallow opening RW large files on 32bit systems. + */ +static int ext2_open_file (struct inode * inode, struct file * filp) +{ + if (inode->u.ext2_i.i_high_size && (filp->f_mode & FMODE_WRITE)) + return -EFBIG; + return 0; +} +#endif |