shmem_symlink error path forgot to unwind. The failed symlink left
over could be unlinked, but long ones were left on the shmem_inodes
list, causing oops in swapoff at shutdown if not earlier.
--- 2.4.19-pre10/mm/shmem.c Tue Jun 4 13:54:20 2002
+++ linux/mm/shmem.c Tue Jun 11 19:02:30 2002
@@ -1123,17 +1123,20 @@
return error;
len = strlen(symname) + 1;
- if (len > PAGE_CACHE_SIZE)
- return -ENAMETOOLONG;
-
inode = dentry->d_inode;
info = SHMEM_I(inode);
inode->i_size = len-1;
+ inode->i_op = &shmem_symlink_inline_operations;
+
if (len <= sizeof(struct shmem_inode_info)) {
/* do it inline */
memcpy(info, symname, len);
- inode->i_op = &shmem_symlink_inline_operations;
} else {
+ if (len > PAGE_CACHE_SIZE) {
+ error = -ENAMETOOLONG;
+ goto rmnod;
+ }
+ inode->i_op = &shmem_symlink_inode_operations;
spin_lock (&shmem_ilock);
list_add (&info->list, &shmem_inodes);
spin_unlock (&shmem_ilock);
@@ -1141,7 +1144,8 @@
page = shmem_getpage_locked(info, inode, 0);
if (IS_ERR(page)) {
up(&info->sem);
- return PTR_ERR(page);
+ error = PTR_ERR(page);
+ goto rmnod;
}
kaddr = kmap(page);
memcpy(kaddr, symname, len);
@@ -1150,10 +1154,14 @@
UnlockPage(page);
page_cache_release(page);
up(&info->sem);
- inode->i_op = &shmem_symlink_inode_operations;
}
dir->i_ctime = dir->i_mtime = CURRENT_TIME;
return 0;
+
+rmnod:
+ if (!shmem_unlink(dir, dentry))
+ d_delete(dentry);
+ return error;
}
static int shmem_readlink_inline(struct dentry *dentry, char *buffer, int buflen)
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
This archive was generated by hypermail 2b29 : Sat Jun 15 2002 - 22:00:24 EST