[Patch] tmpfs fixes against 2.4.6-pre(2)

2001-07-03 Thread Christoph Rohland

Hi Linus,

This is the second part of my patches.

Writing out of a mapping of a tmpfs file into the same file can
deadlock. This is running in the -ac series since some while.

Please apply
Christoph

diff -uNr 6-pre8-fix1/include/linux/shmem_fs.h 6-pre8-fix2/include/linux/shmem_fs.h
--- 6-pre8-fix1/include/linux/shmem_fs.hSun Apr 29 20:33:00 2001
+++ 6-pre8-fix2/include/linux/shmem_fs.hTue Jul  3 09:28:13 2001
@@ -19,6 +19,7 @@
 
 struct shmem_inode_info {
spinlock_t  lock;
+   struct semaphore sem;
unsigned long   max_index;
swp_entry_t i_direct[SHMEM_NR_DIRECT]; /* for the first blocks */
swp_entry_t   **i_indirect; /* doubly indirect blocks */
diff -uNr 6-pre8-fix1/mm/shmem.c 6-pre8-fix2/mm/shmem.c
--- 6-pre8-fix1/mm/shmem.c  Tue Jul  3 08:55:20 2001
+++ 6-pre8-fix2/mm/shmem.c  Tue Jul  3 10:09:26 2001
@@ -162,6 +162,7 @@
swp_entry_t **base, **ptr, **last;
struct shmem_inode_info * info = >u.shmem_i;
 
+   down(>sem);
inode->i_ctime = inode->i_mtime = CURRENT_TIME;
spin_lock (>lock);
index = (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
@@ -205,6 +206,7 @@
info->swapped -= freed;
shmem_recalc_inode(inode);
spin_unlock (>lock);
+   up(>sem);
 }
 
 static void shmem_delete_inode(struct inode * inode)
@@ -289,15 +291,12 @@
  * still need to guard against racing with shm_writepage(), which might
  * be trying to move the page to the swap cache as we run.
  */
-static struct page * shmem_getpage_locked(struct inode * inode, unsigned long idx)
+static struct page * shmem_getpage_locked(struct shmem_inode_info *info, struct inode 
+* inode, unsigned long idx)
 {
struct address_space * mapping = inode->i_mapping;
-   struct shmem_inode_info *info;
struct page * page;
swp_entry_t *entry;
 
-   info = >u.shmem_i;
-
 repeat:
page = find_lock_page(mapping, idx);
if (page)
@@ -402,6 +401,7 @@
 
 static int shmem_getpage(struct inode * inode, unsigned long idx, struct page **ptr)
 {
+   struct shmem_inode_info *info;
struct address_space * mapping = inode->i_mapping;
int error;
 
@@ -416,27 +416,28 @@
page_cache_release(*ptr);
}
 
-   down (>i_sem);
-   /* retest we may have slept */
+   info = >u.shmem_i;
+   down (>sem);
+   /* retest we may have slept */  
+
+   *ptr = ERR_PTR(-EFAULT);
if (inode->i_size < (loff_t) idx * PAGE_CACHE_SIZE)
-   goto sigbus;
-   *ptr = shmem_getpage_locked(inode, idx);
+   goto failed;
+
+   *ptr = shmem_getpage_locked(>u.shmem_i, inode, idx);
if (IS_ERR (*ptr))
goto failed;
+
UnlockPage(*ptr);
-   up (>i_sem);
+   up (>sem);
return 0;
 failed:
-   up (>i_sem);
+   up (>sem);
error = PTR_ERR(*ptr);
-   *ptr = NOPAGE_OOM;
-   if (error != -EFBIG)
-   *ptr = NOPAGE_SIGBUS;
-   return error;
-sigbus:
-   up (>i_sem);
*ptr = NOPAGE_SIGBUS;
-   return -EFAULT;
+   if (error == -ENOMEM)
+   *ptr = NOPAGE_OOM;
+   return error;
 }
 
 struct page * shmem_nopage(struct vm_area_struct * vma, unsigned long address, int 
no_share)
@@ -509,6 +510,7 @@
 struct inode *shmem_get_inode(struct super_block *sb, int mode, int dev)
 {
struct inode * inode;
+   struct shmem_inode_info *info;
 
spin_lock (>u.shmem_sb.stat_lock);
if (!sb->u.shmem_sb.free_inodes) {
@@ -528,7 +530,9 @@
inode->i_rdev = NODEV;
inode->i_mapping->a_ops = _aops;
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
-   spin_lock_init (>u.shmem_i.lock);
+   info = >u.shmem_i;
+   spin_lock_init (>lock);
+   sema_init (>sem, 1);
switch (mode & S_IFMT) {
default:
init_special_inode(inode, mode, dev);
@@ -558,6 +562,7 @@
 shmem_file_write(struct file *file,const char *buf,size_t count,loff_t *ppos)
 {
struct inode*inode = file->f_dentry->d_inode; 
+   struct shmem_inode_info *info;
unsigned long   limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
loff_t  pos;
struct page *page;
@@ -633,7 +638,11 @@
__get_user(dummy, buf+bytes-1);
}
 
-   page = shmem_getpage_locked(inode, index);
+   info = >u.shmem_i;
+   down (>sem);
+   page = shmem_getpage_locked(info, inode, index);
+   up (>sem);
+
status = PTR_ERR(page);
if (IS_ERR(page))
break;
@@ -644,7 +653,6 @@
}
 
kaddr = kmap(page);
-// can this do a truncated write? cr
status = 

[Patch] tmpfs fixes against 2.4.6-pre

2001-07-03 Thread Christoph Rohland

Hi Linus,

I split up my previous patch into two. Hopefully this is more
acceptable for you or will trigger some comments.

This is the first part:

1) shmem_remount_fs garbles parameters which are not supplied
2) shmem_truncate should check the maximum size else we get ugly
   oopses
3) shmem_file_setup should give an error if the size is too big. So
   the application will fail early. I also cleaned up the error
   handling a bit. 
4) We should recalculate the inode on page allocation. Else we get
   really weird sizes on sparse files.

Please apply
Christoph

diff -uNr 6-pre8/mm/shmem.c 6-pre8-fix1/mm/shmem.c
--- 6-pre8/mm/shmem.c   Tue Jun 12 09:49:28 2001
+++ 6-pre8-fix1/mm/shmem.c  Tue Jul  3 08:55:20 2001
@@ -3,7 +3,8 @@
  *
  * Copyright (C) 2000 Linus Torvalds.
  *  2000 Transmeta Corp.
- *  2000 Christoph Rohland
+ *  2000-2001 Christoph Rohland
+ *  2000-2001 SAP AG
  * 
  * This file is released under the GPL.
  */
@@ -33,7 +34,7 @@
 #define TMPFS_MAGIC0x01021994
 
 #define ENTRIES_PER_PAGE (PAGE_SIZE/sizeof(unsigned long))
-#define NR_SINGLE (ENTRIES_PER_PAGE + SHMEM_NR_DIRECT)
+#define SHMEM_MAX_BLOCKS (SHMEM_NR_DIRECT + ENTRIES_PER_PAGE*ENTRIES_PER_PAGE)
 
 static struct super_operations shmem_ops;
 static struct address_space_operations shmem_aops;
@@ -193,7 +194,14 @@
}
 
 out:
-   info->max_index = index;
+   /*
+* We have no chance to give an error, so we limit it to max
+* size here and the application will fail later
+*/
+   if (index > SHMEM_MAX_BLOCKS) 
+   info->max_index = SHMEM_MAX_BLOCKS;
+   else
+   info->max_index = index;
info->swapped -= freed;
shmem_recalc_inode(inode);
spin_unlock (>lock);
@@ -314,6 +322,7 @@
return page;
}

+   shmem_recalc_inode(inode);
if (entry->val) {
unsigned long flags;
 
@@ -1027,6 +1036,8 @@
unsigned long max_inodes, inodes;
struct shmem_sb_info *info = >u.shmem_sb;
 
+   max_blocks = info->max_blocks;
+   max_inodes = info->max_inodes;
if (shmem_parse_options (data, NULL, _blocks, _inodes))
return -EINVAL;
 
@@ -1074,7 +1085,7 @@
sb->u.shmem_sb.free_blocks = blocks;
sb->u.shmem_sb.max_inodes = inodes;
sb->u.shmem_sb.free_inodes = inodes;
-   sb->s_maxbytes = (unsigned long long)(SHMEM_NR_DIRECT + 
(ENTRIES_PER_PAGE*ENTRIES_PER_PAGE)) << PAGE_CACHE_SHIFT;
+   sb->s_maxbytes = (unsigned long long)SHMEM_MAX_BLOCKS << PAGE_CACHE_SHIFT;
sb->s_blocksize = PAGE_CACHE_SIZE;
sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
sb->s_magic = TMPFS_MAGIC;
@@ -1282,9 +1293,11 @@
struct qstr this;
int vm_enough_memory(long pages);
 
-   error = -ENOMEM;
+   if (size > (unsigned long long) SHMEM_MAX_BLOCKS << PAGE_CACHE_SHIFT)
+   return ERR_PTR(-EINVAL);
+
if (!vm_enough_memory((size) >> PAGE_SHIFT))
-   goto out;
+   return ERR_PTR(-ENOMEM);
 
this.name = name;
this.len = strlen(name);
@@ -1292,7 +1305,7 @@
root = tmpfs_fs_type.kern_mnt->mnt_root;
dentry = d_alloc(root, );
if (!dentry)
-   goto out;
+   return ERR_PTR(-ENOMEM);
 
error = -ENFILE;
file = get_empty_filp();
@@ -1318,7 +1331,6 @@
put_filp(file);
 put_dentry:
dput (dentry);
-out:
return ERR_PTR(error);  
 }
 /*

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/



[Patch] tmpfs fixes against 2.4.6-pre

2001-07-03 Thread Christoph Rohland

Hi Linus,

I split up my previous patch into two. Hopefully this is more
acceptable for you or will trigger some comments.

This is the first part:

1) shmem_remount_fs garbles parameters which are not supplied
2) shmem_truncate should check the maximum size else we get ugly
   oopses
3) shmem_file_setup should give an error if the size is too big. So
   the application will fail early. I also cleaned up the error
   handling a bit. 
4) We should recalculate the inode on page allocation. Else we get
   really weird sizes on sparse files.

Please apply
Christoph

diff -uNr 6-pre8/mm/shmem.c 6-pre8-fix1/mm/shmem.c
--- 6-pre8/mm/shmem.c   Tue Jun 12 09:49:28 2001
+++ 6-pre8-fix1/mm/shmem.c  Tue Jul  3 08:55:20 2001
@@ -3,7 +3,8 @@
  *
  * Copyright (C) 2000 Linus Torvalds.
  *  2000 Transmeta Corp.
- *  2000 Christoph Rohland
+ *  2000-2001 Christoph Rohland
+ *  2000-2001 SAP AG
  * 
  * This file is released under the GPL.
  */
@@ -33,7 +34,7 @@
 #define TMPFS_MAGIC0x01021994
 
 #define ENTRIES_PER_PAGE (PAGE_SIZE/sizeof(unsigned long))
-#define NR_SINGLE (ENTRIES_PER_PAGE + SHMEM_NR_DIRECT)
+#define SHMEM_MAX_BLOCKS (SHMEM_NR_DIRECT + ENTRIES_PER_PAGE*ENTRIES_PER_PAGE)
 
 static struct super_operations shmem_ops;
 static struct address_space_operations shmem_aops;
@@ -193,7 +194,14 @@
}
 
 out:
-   info-max_index = index;
+   /*
+* We have no chance to give an error, so we limit it to max
+* size here and the application will fail later
+*/
+   if (index  SHMEM_MAX_BLOCKS) 
+   info-max_index = SHMEM_MAX_BLOCKS;
+   else
+   info-max_index = index;
info-swapped -= freed;
shmem_recalc_inode(inode);
spin_unlock (info-lock);
@@ -314,6 +322,7 @@
return page;
}

+   shmem_recalc_inode(inode);
if (entry-val) {
unsigned long flags;
 
@@ -1027,6 +1036,8 @@
unsigned long max_inodes, inodes;
struct shmem_sb_info *info = sb-u.shmem_sb;
 
+   max_blocks = info-max_blocks;
+   max_inodes = info-max_inodes;
if (shmem_parse_options (data, NULL, max_blocks, max_inodes))
return -EINVAL;
 
@@ -1074,7 +1085,7 @@
sb-u.shmem_sb.free_blocks = blocks;
sb-u.shmem_sb.max_inodes = inodes;
sb-u.shmem_sb.free_inodes = inodes;
-   sb-s_maxbytes = (unsigned long long)(SHMEM_NR_DIRECT + 
(ENTRIES_PER_PAGE*ENTRIES_PER_PAGE))  PAGE_CACHE_SHIFT;
+   sb-s_maxbytes = (unsigned long long)SHMEM_MAX_BLOCKS  PAGE_CACHE_SHIFT;
sb-s_blocksize = PAGE_CACHE_SIZE;
sb-s_blocksize_bits = PAGE_CACHE_SHIFT;
sb-s_magic = TMPFS_MAGIC;
@@ -1282,9 +1293,11 @@
struct qstr this;
int vm_enough_memory(long pages);
 
-   error = -ENOMEM;
+   if (size  (unsigned long long) SHMEM_MAX_BLOCKS  PAGE_CACHE_SHIFT)
+   return ERR_PTR(-EINVAL);
+
if (!vm_enough_memory((size)  PAGE_SHIFT))
-   goto out;
+   return ERR_PTR(-ENOMEM);
 
this.name = name;
this.len = strlen(name);
@@ -1292,7 +1305,7 @@
root = tmpfs_fs_type.kern_mnt-mnt_root;
dentry = d_alloc(root, this);
if (!dentry)
-   goto out;
+   return ERR_PTR(-ENOMEM);
 
error = -ENFILE;
file = get_empty_filp();
@@ -1318,7 +1331,6 @@
put_filp(file);
 put_dentry:
dput (dentry);
-out:
return ERR_PTR(error);  
 }
 /*

-
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/



[Patch] tmpfs fixes against 2.4.6-pre(2)

2001-07-03 Thread Christoph Rohland

Hi Linus,

This is the second part of my patches.

Writing out of a mapping of a tmpfs file into the same file can
deadlock. This is running in the -ac series since some while.

Please apply
Christoph

diff -uNr 6-pre8-fix1/include/linux/shmem_fs.h 6-pre8-fix2/include/linux/shmem_fs.h
--- 6-pre8-fix1/include/linux/shmem_fs.hSun Apr 29 20:33:00 2001
+++ 6-pre8-fix2/include/linux/shmem_fs.hTue Jul  3 09:28:13 2001
@@ -19,6 +19,7 @@
 
 struct shmem_inode_info {
spinlock_t  lock;
+   struct semaphore sem;
unsigned long   max_index;
swp_entry_t i_direct[SHMEM_NR_DIRECT]; /* for the first blocks */
swp_entry_t   **i_indirect; /* doubly indirect blocks */
diff -uNr 6-pre8-fix1/mm/shmem.c 6-pre8-fix2/mm/shmem.c
--- 6-pre8-fix1/mm/shmem.c  Tue Jul  3 08:55:20 2001
+++ 6-pre8-fix2/mm/shmem.c  Tue Jul  3 10:09:26 2001
@@ -162,6 +162,7 @@
swp_entry_t **base, **ptr, **last;
struct shmem_inode_info * info = inode-u.shmem_i;
 
+   down(info-sem);
inode-i_ctime = inode-i_mtime = CURRENT_TIME;
spin_lock (info-lock);
index = (inode-i_size + PAGE_CACHE_SIZE - 1)  PAGE_CACHE_SHIFT;
@@ -205,6 +206,7 @@
info-swapped -= freed;
shmem_recalc_inode(inode);
spin_unlock (info-lock);
+   up(info-sem);
 }
 
 static void shmem_delete_inode(struct inode * inode)
@@ -289,15 +291,12 @@
  * still need to guard against racing with shm_writepage(), which might
  * be trying to move the page to the swap cache as we run.
  */
-static struct page * shmem_getpage_locked(struct inode * inode, unsigned long idx)
+static struct page * shmem_getpage_locked(struct shmem_inode_info *info, struct inode 
+* inode, unsigned long idx)
 {
struct address_space * mapping = inode-i_mapping;
-   struct shmem_inode_info *info;
struct page * page;
swp_entry_t *entry;
 
-   info = inode-u.shmem_i;
-
 repeat:
page = find_lock_page(mapping, idx);
if (page)
@@ -402,6 +401,7 @@
 
 static int shmem_getpage(struct inode * inode, unsigned long idx, struct page **ptr)
 {
+   struct shmem_inode_info *info;
struct address_space * mapping = inode-i_mapping;
int error;
 
@@ -416,27 +416,28 @@
page_cache_release(*ptr);
}
 
-   down (inode-i_sem);
-   /* retest we may have slept */
+   info = inode-u.shmem_i;
+   down (info-sem);
+   /* retest we may have slept */  
+
+   *ptr = ERR_PTR(-EFAULT);
if (inode-i_size  (loff_t) idx * PAGE_CACHE_SIZE)
-   goto sigbus;
-   *ptr = shmem_getpage_locked(inode, idx);
+   goto failed;
+
+   *ptr = shmem_getpage_locked(inode-u.shmem_i, inode, idx);
if (IS_ERR (*ptr))
goto failed;
+
UnlockPage(*ptr);
-   up (inode-i_sem);
+   up (info-sem);
return 0;
 failed:
-   up (inode-i_sem);
+   up (info-sem);
error = PTR_ERR(*ptr);
-   *ptr = NOPAGE_OOM;
-   if (error != -EFBIG)
-   *ptr = NOPAGE_SIGBUS;
-   return error;
-sigbus:
-   up (inode-i_sem);
*ptr = NOPAGE_SIGBUS;
-   return -EFAULT;
+   if (error == -ENOMEM)
+   *ptr = NOPAGE_OOM;
+   return error;
 }
 
 struct page * shmem_nopage(struct vm_area_struct * vma, unsigned long address, int 
no_share)
@@ -509,6 +510,7 @@
 struct inode *shmem_get_inode(struct super_block *sb, int mode, int dev)
 {
struct inode * inode;
+   struct shmem_inode_info *info;
 
spin_lock (sb-u.shmem_sb.stat_lock);
if (!sb-u.shmem_sb.free_inodes) {
@@ -528,7 +530,9 @@
inode-i_rdev = NODEV;
inode-i_mapping-a_ops = shmem_aops;
inode-i_atime = inode-i_mtime = inode-i_ctime = CURRENT_TIME;
-   spin_lock_init (inode-u.shmem_i.lock);
+   info = inode-u.shmem_i;
+   spin_lock_init (info-lock);
+   sema_init (info-sem, 1);
switch (mode  S_IFMT) {
default:
init_special_inode(inode, mode, dev);
@@ -558,6 +562,7 @@
 shmem_file_write(struct file *file,const char *buf,size_t count,loff_t *ppos)
 {
struct inode*inode = file-f_dentry-d_inode; 
+   struct shmem_inode_info *info;
unsigned long   limit = current-rlim[RLIMIT_FSIZE].rlim_cur;
loff_t  pos;
struct page *page;
@@ -633,7 +638,11 @@
__get_user(dummy, buf+bytes-1);
}
 
-   page = shmem_getpage_locked(inode, index);
+   info = inode-u.shmem_i;
+   down (info-sem);
+   page = shmem_getpage_locked(info, inode, index);
+   up (info-sem);
+
status = PTR_ERR(page);
if (IS_ERR(page))
break;
@@ -644,7 +653,6 @@
}
 
kaddr = kmap(page);

[Patch] tmpfs fixes against 2.4.6-pre

2001-06-21 Thread Christoph Rohland

Hi Linus,

the appended patch fixes several tmpfs problems:

1) writing out of a mapping of a tmpfs file into the same file can
   deadlock
2) shmem_remount_fs garbles parameters which are not supplied
3) shmem_file_setup should check the maximum size

Please apply
Christoph

diff -uNr 6-pre5/include/linux/shmem_fs.h 6-pre5-fix/include/linux/shmem_fs.h
--- 6-pre5/include/linux/shmem_fs.h Sun Apr 29 20:33:00 2001
+++ 6-pre5-fix/include/linux/shmem_fs.h Thu Jun 21 15:52:25 2001
@@ -19,6 +19,7 @@
 
 struct shmem_inode_info {
spinlock_t  lock;
+   struct semaphore sem;
unsigned long   max_index;
swp_entry_t i_direct[SHMEM_NR_DIRECT]; /* for the first blocks */
swp_entry_t   **i_indirect; /* doubly indirect blocks */
diff -uNr 6-pre5/mm/shmem.c 6-pre5-fix/mm/shmem.c
--- 6-pre5/mm/shmem.c   Tue Jun 12 09:49:28 2001
+++ 6-pre5-fix/mm/shmem.c   Thu Jun 21 15:52:26 2001
@@ -3,7 +3,8 @@
  *
  * Copyright (C) 2000 Linus Torvalds.
  *  2000 Transmeta Corp.
- *  2000 Christoph Rohland
+ *  2000-2001 Christoph Rohland
+ *  2000-2001 SAP AG
  * 
  * This file is released under the GPL.
  */
@@ -33,7 +34,7 @@
 #define TMPFS_MAGIC0x01021994
 
 #define ENTRIES_PER_PAGE (PAGE_SIZE/sizeof(unsigned long))
-#define NR_SINGLE (ENTRIES_PER_PAGE + SHMEM_NR_DIRECT)
+#define SHMEM_MAX_BLOCKS (SHMEM_NR_DIRECT + ENTRIES_PER_PAGE*ENTRIES_PER_PAGE)
 
 static struct super_operations shmem_ops;
 static struct address_space_operations shmem_aops;
@@ -161,6 +162,7 @@
swp_entry_t **base, **ptr, **last;
struct shmem_inode_info * info = >u.shmem_i;
 
+   down(>sem);
inode->i_ctime = inode->i_mtime = CURRENT_TIME;
spin_lock (>lock);
index = (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
@@ -193,10 +195,14 @@
}
 
 out:
-   info->max_index = index;
+   if (index <= SHMEM_MAX_BLOCKS)
+   info->max_index = index;
+   else
+   info->max_index = SHMEM_MAX_BLOCKS + 1;
info->swapped -= freed;
shmem_recalc_inode(inode);
spin_unlock (>lock);
+   up(>sem);
 }
 
 static void shmem_delete_inode(struct inode * inode)
@@ -281,15 +287,12 @@
  * still need to guard against racing with shm_writepage(), which might
  * be trying to move the page to the swap cache as we run.
  */
-static struct page * shmem_getpage_locked(struct inode * inode, unsigned long idx)
+static struct page * shmem_getpage_locked(struct shmem_inode_info *info, struct inode 
+* inode, unsigned long idx)
 {
struct address_space * mapping = inode->i_mapping;
-   struct shmem_inode_info *info;
struct page * page;
swp_entry_t *entry;
 
-   info = >u.shmem_i;
-
 repeat:
page = find_lock_page(mapping, idx);
if (page)
@@ -393,6 +396,7 @@
 
 static int shmem_getpage(struct inode * inode, unsigned long idx, struct page **ptr)
 {
+   struct shmem_inode_info *info;
struct address_space * mapping = inode->i_mapping;
int error;
 
@@ -407,27 +411,28 @@
page_cache_release(*ptr);
}
 
-   down (>i_sem);
-   /* retest we may have slept */
+   info = >u.shmem_i;
+   down (>sem);
+   /* retest we may have slept */  
+
+   *ptr = ERR_PTR(-EFAULT);
if (inode->i_size < (loff_t) idx * PAGE_CACHE_SIZE)
-   goto sigbus;
-   *ptr = shmem_getpage_locked(inode, idx);
+   goto failed;
+
+   *ptr = shmem_getpage_locked(>u.shmem_i, inode, idx);
if (IS_ERR (*ptr))
goto failed;
+
UnlockPage(*ptr);
-   up (>i_sem);
+   up (>sem);
return 0;
 failed:
-   up (>i_sem);
+   up (>sem);
error = PTR_ERR(*ptr);
-   *ptr = NOPAGE_OOM;
-   if (error != -EFBIG)
-   *ptr = NOPAGE_SIGBUS;
-   return error;
-sigbus:
-   up (>i_sem);
*ptr = NOPAGE_SIGBUS;
-   return -EFAULT;
+   if (error == -ENOMEM)
+   *ptr = NOPAGE_OOM;
+   return error;
 }
 
 struct page * shmem_nopage(struct vm_area_struct * vma, unsigned long address, int 
no_share)
@@ -500,6 +505,7 @@
 struct inode *shmem_get_inode(struct super_block *sb, int mode, int dev)
 {
struct inode * inode;
+   struct shmem_inode_info *info;
 
spin_lock (>u.shmem_sb.stat_lock);
if (!sb->u.shmem_sb.free_inodes) {
@@ -519,7 +525,9 @@
inode->i_rdev = NODEV;
inode->i_mapping->a_ops = _aops;
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
-   spin_lock_init (>u.shmem_i.lock);
+   info = >u.shmem_i;
+   spin_lock_init (>lock);
+   sema_init (>sem, 1);
switch (mode & S_IFMT) {
default:
init_special_inode(inode, mode, dev);
@@ -549,6 +557,7 @@
 shmem_file_write(struct file 

[Patch] tmpfs fixes against 2.4.6-pre

2001-06-21 Thread Christoph Rohland

Hi Linus,

the appended patch fixes several tmpfs problems:

1) writing out of a mapping of a tmpfs file into the same file can
   deadlock
2) shmem_remount_fs garbles parameters which are not supplied
3) shmem_file_setup should check the maximum size

Please apply
Christoph

diff -uNr 6-pre5/include/linux/shmem_fs.h 6-pre5-fix/include/linux/shmem_fs.h
--- 6-pre5/include/linux/shmem_fs.h Sun Apr 29 20:33:00 2001
+++ 6-pre5-fix/include/linux/shmem_fs.h Thu Jun 21 15:52:25 2001
@@ -19,6 +19,7 @@
 
 struct shmem_inode_info {
spinlock_t  lock;
+   struct semaphore sem;
unsigned long   max_index;
swp_entry_t i_direct[SHMEM_NR_DIRECT]; /* for the first blocks */
swp_entry_t   **i_indirect; /* doubly indirect blocks */
diff -uNr 6-pre5/mm/shmem.c 6-pre5-fix/mm/shmem.c
--- 6-pre5/mm/shmem.c   Tue Jun 12 09:49:28 2001
+++ 6-pre5-fix/mm/shmem.c   Thu Jun 21 15:52:26 2001
@@ -3,7 +3,8 @@
  *
  * Copyright (C) 2000 Linus Torvalds.
  *  2000 Transmeta Corp.
- *  2000 Christoph Rohland
+ *  2000-2001 Christoph Rohland
+ *  2000-2001 SAP AG
  * 
  * This file is released under the GPL.
  */
@@ -33,7 +34,7 @@
 #define TMPFS_MAGIC0x01021994
 
 #define ENTRIES_PER_PAGE (PAGE_SIZE/sizeof(unsigned long))
-#define NR_SINGLE (ENTRIES_PER_PAGE + SHMEM_NR_DIRECT)
+#define SHMEM_MAX_BLOCKS (SHMEM_NR_DIRECT + ENTRIES_PER_PAGE*ENTRIES_PER_PAGE)
 
 static struct super_operations shmem_ops;
 static struct address_space_operations shmem_aops;
@@ -161,6 +162,7 @@
swp_entry_t **base, **ptr, **last;
struct shmem_inode_info * info = inode-u.shmem_i;
 
+   down(info-sem);
inode-i_ctime = inode-i_mtime = CURRENT_TIME;
spin_lock (info-lock);
index = (inode-i_size + PAGE_CACHE_SIZE - 1)  PAGE_CACHE_SHIFT;
@@ -193,10 +195,14 @@
}
 
 out:
-   info-max_index = index;
+   if (index = SHMEM_MAX_BLOCKS)
+   info-max_index = index;
+   else
+   info-max_index = SHMEM_MAX_BLOCKS + 1;
info-swapped -= freed;
shmem_recalc_inode(inode);
spin_unlock (info-lock);
+   up(info-sem);
 }
 
 static void shmem_delete_inode(struct inode * inode)
@@ -281,15 +287,12 @@
  * still need to guard against racing with shm_writepage(), which might
  * be trying to move the page to the swap cache as we run.
  */
-static struct page * shmem_getpage_locked(struct inode * inode, unsigned long idx)
+static struct page * shmem_getpage_locked(struct shmem_inode_info *info, struct inode 
+* inode, unsigned long idx)
 {
struct address_space * mapping = inode-i_mapping;
-   struct shmem_inode_info *info;
struct page * page;
swp_entry_t *entry;
 
-   info = inode-u.shmem_i;
-
 repeat:
page = find_lock_page(mapping, idx);
if (page)
@@ -393,6 +396,7 @@
 
 static int shmem_getpage(struct inode * inode, unsigned long idx, struct page **ptr)
 {
+   struct shmem_inode_info *info;
struct address_space * mapping = inode-i_mapping;
int error;
 
@@ -407,27 +411,28 @@
page_cache_release(*ptr);
}
 
-   down (inode-i_sem);
-   /* retest we may have slept */
+   info = inode-u.shmem_i;
+   down (info-sem);
+   /* retest we may have slept */  
+
+   *ptr = ERR_PTR(-EFAULT);
if (inode-i_size  (loff_t) idx * PAGE_CACHE_SIZE)
-   goto sigbus;
-   *ptr = shmem_getpage_locked(inode, idx);
+   goto failed;
+
+   *ptr = shmem_getpage_locked(inode-u.shmem_i, inode, idx);
if (IS_ERR (*ptr))
goto failed;
+
UnlockPage(*ptr);
-   up (inode-i_sem);
+   up (info-sem);
return 0;
 failed:
-   up (inode-i_sem);
+   up (info-sem);
error = PTR_ERR(*ptr);
-   *ptr = NOPAGE_OOM;
-   if (error != -EFBIG)
-   *ptr = NOPAGE_SIGBUS;
-   return error;
-sigbus:
-   up (inode-i_sem);
*ptr = NOPAGE_SIGBUS;
-   return -EFAULT;
+   if (error == -ENOMEM)
+   *ptr = NOPAGE_OOM;
+   return error;
 }
 
 struct page * shmem_nopage(struct vm_area_struct * vma, unsigned long address, int 
no_share)
@@ -500,6 +505,7 @@
 struct inode *shmem_get_inode(struct super_block *sb, int mode, int dev)
 {
struct inode * inode;
+   struct shmem_inode_info *info;
 
spin_lock (sb-u.shmem_sb.stat_lock);
if (!sb-u.shmem_sb.free_inodes) {
@@ -519,7 +525,9 @@
inode-i_rdev = NODEV;
inode-i_mapping-a_ops = shmem_aops;
inode-i_atime = inode-i_mtime = inode-i_ctime = CURRENT_TIME;
-   spin_lock_init (inode-u.shmem_i.lock);
+   info = inode-u.shmem_i;
+   spin_lock_init (info-lock);
+   sema_init (info-sem, 1);
switch (mode  S_IFMT) {
default: