diff options
| author | Hugh Dickins <hugh@veritas.com> | 2002-07-29 01:26:20 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@home.transmeta.com> | 2002-07-29 01:26:20 -0700 |
| commit | 363723801df37641de6dee1c5c86d22fcd06b403 (patch) | |
| tree | 343e7aabde277c64324bb009eb27f1cb49ebe606 /mm | |
| parent | 477436ba924a4c56eb8c4a163d090ac8f4b0bacb (diff) | |
[PATCH] SHMEM_MAX_BYTES overflow checking
shmem_notify_change and shmem_file_write be careful about overflowingly
large loff_t before shifting it into unsigned long for vm_enough_memory.
Rename SHMEM_MAX_BLOCKS to SHMEM_MAX_INDEX (to avoid confusion with
512-byte blocks), define SHMEM_MAX_BYTES from it.
But 2.5 vmtruncate lacked the s_maxbytes error handling which
shmem_notify_change now expects: bring it in from the -dj tree.
shmem_file_write error handling needs a closer look later on.
Diffstat (limited to 'mm')
| -rw-r--r-- | mm/memory.c | 19 | ||||
| -rw-r--r-- | mm/shmem.c | 28 |
2 files changed, 23 insertions, 24 deletions
diff --git a/mm/memory.c b/mm/memory.c index a6c070284c9d..33103f5bad1e 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -1096,23 +1096,20 @@ out_unlock: do_expand: limit = current->rlim[RLIMIT_FSIZE].rlim_cur; - if (limit != RLIM_INFINITY) { - if (inode->i_size >= limit) { - send_sig(SIGXFSZ, current, 0); - goto out; - } - if (offset > limit) { - send_sig(SIGXFSZ, current, 0); - offset = limit; - } - } + if (limit != RLIM_INFINITY && offset > limit) + goto out_sig; + if (offset > inode->i_sb->s_maxbytes) + goto out; inode->i_size = offset; out_truncate: if (inode->i_op && inode->i_op->truncate) inode->i_op->truncate(inode); -out: return 0; +out_sig: + send_sig(SIGXFSZ, current, 0); +out: + return -EFBIG; } /* diff --git a/mm/shmem.c b/mm/shmem.c index 4322a6637377..d8a263033d5e 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -37,6 +37,10 @@ #define TMPFS_MAGIC 0x01021994 #define ENTRIES_PER_PAGE (PAGE_CACHE_SIZE/sizeof(unsigned long)) +#define BLOCKS_PER_PAGE (PAGE_CACHE_SIZE/512) + +#define SHMEM_MAX_INDEX (SHMEM_NR_DIRECT + ENTRIES_PER_PAGE * (ENTRIES_PER_PAGE/2) * (ENTRIES_PER_PAGE+1)) +#define SHMEM_MAX_BYTES ((unsigned long long)SHMEM_MAX_INDEX << PAGE_CACHE_SHIFT) #define VM_ACCT(size) (((size) + PAGE_CACHE_SIZE - 1) >> PAGE_SHIFT) @@ -58,8 +62,6 @@ atomic_t shmem_nrpages = ATOMIC_INIT(0); /* Not used right now */ static struct page *shmem_getpage_locked(struct shmem_inode_info *, struct inode *, unsigned long); -#define BLOCKS_PER_PAGE (PAGE_CACHE_SIZE/512) - /* * shmem_recalc_inode - recalculate the size of an inode * @@ -135,9 +137,6 @@ static void shmem_recalc_inode(struct inode * inode) * +-> 48-51 * +-> 52-55 */ - -#define SHMEM_MAX_BLOCKS (SHMEM_NR_DIRECT + ENTRIES_PER_PAGE * ENTRIES_PER_PAGE/2*(ENTRIES_PER_PAGE+1)) - static swp_entry_t * shmem_swp_entry (struct shmem_inode_info *info, unsigned long index, unsigned long page) { unsigned long offset; @@ -190,7 +189,7 @@ static inline swp_entry_t * shmem_alloc_entry (struct shmem_inode_info *info, un unsigned long page = 0; swp_entry_t * res; - if (index >= SHMEM_MAX_BLOCKS) + if (index >= SHMEM_MAX_INDEX) return ERR_PTR(-EFBIG); if (info->next_index <= index) @@ -365,14 +364,14 @@ static void shmem_truncate (struct inode * inode) static int shmem_notify_change(struct dentry * dentry, struct iattr *attr) { struct inode *inode = dentry->d_inode; + long change = 0; int error; - if (attr->ia_valid & ATTR_SIZE) { + if ((attr->ia_valid & ATTR_SIZE) && (attr->ia_size <= SHMEM_MAX_BYTES)) { /* - * Account swap file usage based on new file size + * Account swap file usage based on new file size, + * but just let vmtruncate fail on out-of-range sizes. */ - long change; - change = VM_ACCT(attr->ia_size) - VM_ACCT(inode->i_size); if (change > 0) { if (!vm_enough_memory(change)) @@ -384,7 +383,8 @@ static int shmem_notify_change(struct dentry * dentry, struct iattr *attr) error = inode_change_ok(inode, attr); if (!error) error = inode_setattr(inode, attr); - + if (error) + vm_unacct_memory(change); return error; } @@ -885,6 +885,8 @@ shmem_file_write(struct file *file,const char *buf,size_t count,loff_t *ppos) maxpos = inode->i_size; if (pos + count > inode->i_size) { maxpos = pos + count; + if (maxpos > SHMEM_MAX_BYTES) + maxpos = SHMEM_MAX_BYTES; if (!vm_enough_memory(VM_ACCT(maxpos) - VM_ACCT(inode->i_size))) { err = -ENOMEM; goto out_nc; @@ -1434,7 +1436,7 @@ static int shmem_fill_super(struct super_block * sb, void * data, int silent) sbinfo->free_blocks = blocks; sbinfo->max_inodes = inodes; sbinfo->free_inodes = inodes; - sb->s_maxbytes = (unsigned long long) SHMEM_MAX_BLOCKS << PAGE_CACHE_SHIFT; + sb->s_maxbytes = SHMEM_MAX_BYTES; sb->s_blocksize = PAGE_CACHE_SIZE; sb->s_blocksize_bits = PAGE_CACHE_SHIFT; sb->s_magic = TMPFS_MAGIC; @@ -1658,7 +1660,7 @@ struct file *shmem_file_setup(char * name, loff_t size) struct dentry *dentry, *root; struct qstr this; - if (size > (unsigned long long) SHMEM_MAX_BLOCKS << PAGE_CACHE_SHIFT) + if (size > SHMEM_MAX_BYTES) return ERR_PTR(-EINVAL); if (!vm_enough_memory(VM_ACCT(size))) |
