From 060d11b0b35d13eb2251fd08403d900b71df5791 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Thu, 30 Aug 2007 23:56:16 -0700 Subject: revert "eCryptfs: fix lookup error for special files" This patch got appied twice. Cc: Ryusuke Konishi Cc: Michael Halcrow Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ecryptfs/inode.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'fs') diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index 5d40ad13ab5c..131954b3fb98 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c @@ -357,10 +357,6 @@ static struct dentry *ecryptfs_lookup(struct inode *dir, struct dentry *dentry, ecryptfs_printk(KERN_DEBUG, "Is a special file; returning\n"); goto out; } - if (special_file(lower_inode->i_mode)) { - ecryptfs_printk(KERN_DEBUG, "Is a special file; returning\n"); - goto out; - } if (!nd) { ecryptfs_printk(KERN_DEBUG, "We have a NULL nd, just leave" "as we *think* we are about to unlink\n"); -- cgit v1.2.2 From bcec44770cc65660369ae17b4e44be027a64a46c Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Thu, 30 Aug 2007 23:56:22 -0700 Subject: UDF: handle wrong superblock better If UDF superblock is incorrect, we can fail to find a table of free / allocated space and consequently Oops. Handle this situation more gracefully by ignoring the broken UDF partition. Signed-off-by: Jan Kara Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/udf/super.c | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) (limited to 'fs') diff --git a/fs/udf/super.c b/fs/udf/super.c index 382be7be5ae3..c68a6e730b97 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -89,7 +89,7 @@ static int udf_find_fileset(struct super_block *, kernel_lb_addr *, static void udf_load_pvoldesc(struct super_block *, struct buffer_head *); static void udf_load_fileset(struct super_block *, struct buffer_head *, kernel_lb_addr *); -static void udf_load_partdesc(struct super_block *, struct buffer_head *); +static int udf_load_partdesc(struct super_block *, struct buffer_head *); static void udf_open_lvid(struct super_block *); static void udf_close_lvid(struct super_block *); static unsigned int udf_count_free(struct super_block *); @@ -877,7 +877,7 @@ static void udf_load_fileset(struct super_block *sb, struct buffer_head *bh, root->logicalBlockNum, root->partitionReferenceNum); } -static void udf_load_partdesc(struct super_block *sb, struct buffer_head *bh) +static int udf_load_partdesc(struct super_block *sb, struct buffer_head *bh) { struct partitionDesc *p; int i; @@ -912,6 +912,11 @@ static void udf_load_partdesc(struct super_block *sb, struct buffer_head *bh) UDF_SB_PARTMAPS(sb)[i].s_uspace.s_table = udf_iget(sb, loc); + if (!UDF_SB_PARTMAPS(sb)[i].s_uspace.s_table) { + udf_debug("cannot load unallocSpaceTable (part %d)\n", + i); + return 1; + } UDF_SB_PARTFLAGS(sb,i) |= UDF_PART_FLAG_UNALLOC_TABLE; udf_debug("unallocSpaceTable (part %d) @ %ld\n", i, UDF_SB_PARTMAPS(sb)[i].s_uspace.s_table->i_ino); @@ -938,6 +943,11 @@ static void udf_load_partdesc(struct super_block *sb, struct buffer_head *bh) UDF_SB_PARTMAPS(sb)[i].s_fspace.s_table = udf_iget(sb, loc); + if (!UDF_SB_PARTMAPS(sb)[i].s_fspace.s_table) { + udf_debug("cannot load freedSpaceTable (part %d)\n", + i); + return 1; + } UDF_SB_PARTFLAGS(sb,i) |= UDF_PART_FLAG_FREED_TABLE; udf_debug("freedSpaceTable (part %d) @ %ld\n", i, UDF_SB_PARTMAPS(sb)[i].s_fspace.s_table->i_ino); @@ -966,6 +976,7 @@ static void udf_load_partdesc(struct super_block *sb, struct buffer_head *bh) le16_to_cpu(p->partitionNumber), i, UDF_SB_PARTTYPE(sb,i), UDF_SB_PARTROOT(sb,i), UDF_SB_PARTLEN(sb,i)); } + return 0; } static int udf_load_logicalvol(struct super_block *sb, struct buffer_head *bh, @@ -1177,12 +1188,19 @@ static int udf_process_sequence(struct super_block *sb, long block, long lastblo udf_load_logicalvol(sb, bh, fileset); } else if (i == VDS_POS_PARTITION_DESC) { struct buffer_head *bh2 = NULL; - udf_load_partdesc(sb, bh); + if (udf_load_partdesc(sb, bh)) { + brelse(bh); + return 1; + } for (j = vds[i].block + 1; j < vds[VDS_POS_TERMINATING_DESC].block; j++) { bh2 = udf_read_tagged(sb, j, j, &ident); gd = (struct generic_desc *)bh2->b_data; if (ident == TAG_IDENT_PD) - udf_load_partdesc(sb, bh2); + if (udf_load_partdesc(sb, bh2)) { + brelse(bh); + brelse(bh2); + return 1; + } brelse(bh2); } } -- cgit v1.2.2 From f5cc15dac55d4943176f84681f37aa48094ffa8b Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Thu, 30 Aug 2007 23:56:22 -0700 Subject: Fix possible NULL pointer dereference in udf_table_free_blocks() Fix possible NULL pointer dereference when freeing blocks in case table of free space is used. Also fix handling of the case when we need to move extent from one block to another one to make space for indirect extent. BTW: Nobody seem to have ever used this code. Signed-off-by: Jan Kara Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/udf/balloc.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'fs') diff --git a/fs/udf/balloc.c b/fs/udf/balloc.c index 276f7207a564..87e87dcd3f9c 100644 --- a/fs/udf/balloc.c +++ b/fs/udf/balloc.c @@ -540,26 +540,24 @@ static void udf_table_free_blocks(struct super_block *sb, if (epos.offset + adsize > sb->s_blocksize) { loffset = epos.offset; aed->lengthAllocDescs = cpu_to_le32(adsize); - sptr = UDF_I_DATA(inode) + epos.offset - - udf_file_entry_alloc_offset(inode) + - UDF_I_LENEATTR(inode) - adsize; + sptr = UDF_I_DATA(table) + epos.offset - adsize; dptr = epos.bh->b_data + sizeof(struct allocExtDesc); memcpy(dptr, sptr, adsize); epos.offset = sizeof(struct allocExtDesc) + adsize; } else { loffset = epos.offset + adsize; aed->lengthAllocDescs = cpu_to_le32(0); - sptr = oepos.bh->b_data + epos.offset; - epos.offset = sizeof(struct allocExtDesc); - if (oepos.bh) { + sptr = oepos.bh->b_data + epos.offset; aed = (struct allocExtDesc *)oepos.bh->b_data; aed->lengthAllocDescs = cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) + adsize); } else { + sptr = UDF_I_DATA(table) + epos.offset; UDF_I_LENALLOC(table) += adsize; mark_inode_dirty(table); } + epos.offset = sizeof(struct allocExtDesc); } if (UDF_SB_UDFREV(sb) >= 0x0200) udf_new_tag(epos.bh->b_data, TAG_IDENT_AED, 3, 1, -- cgit v1.2.2 From 2aeb3db17fc33443d21b11d7121c5627d55717c6 Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Thu, 30 Aug 2007 23:56:33 -0700 Subject: eCryptfs: fix possible fault in ecryptfs_sync_page This will avoid a possible fault in ecryptfs_sync_page(). In the function, eCryptfs calls sync_page() method of a lower filesystem without checking its existence. However, there are many filesystems that don't have this method including network filesystems such as NFS, AFS, and so forth. They may fail when an eCryptfs page is waiting for lock. Signed-off-by: Ryusuke Konishi Acked-by: Michael Halcrow Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ecryptfs/mmap.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/ecryptfs/mmap.c b/fs/ecryptfs/mmap.c index e4ab7bc14efe..fd3f94d4a668 100644 --- a/fs/ecryptfs/mmap.c +++ b/fs/ecryptfs/mmap.c @@ -834,7 +834,8 @@ static void ecryptfs_sync_page(struct page *page) ecryptfs_printk(KERN_DEBUG, "find_lock_page failed\n"); return; } - lower_page->mapping->a_ops->sync_page(lower_page); + if (lower_page->mapping->a_ops->sync_page) + lower_page->mapping->a_ops->sync_page(lower_page); ecryptfs_printk(KERN_DEBUG, "Unlocking page with index = [0x%.16x]\n", lower_page->index); unlock_page(lower_page); -- cgit v1.2.2 From dec4ad86c2fbea062e9ef9caa6d6e79f7c5e0b12 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Thu, 30 Aug 2007 23:56:40 -0700 Subject: hugepage: fix broken check for offset alignment in hugepage mappings For hugepage mappings, the file offset, like the address and size, needs to be aligned to the size of a hugepage. In commit 68589bc353037f233fe510ad9ff432338c95db66, the check for this was moved into prepare_hugepage_range() along with the address and size checks. But since BenH's rework of the get_unmapped_area() paths leading up to commit 4b1d89290b62bb2db476c94c82cf7442aab440c8, prepare_hugepage_range() is only called for MAP_FIXED mappings, not for other mappings. This means we're no longer ever checking for an aligned offset - I've confirmed that mmap() will (apparently) succeed with a misaligned offset on both powerpc and i386 at least. This patch restores the check, removing it from prepare_hugepage_range() and putting it back into hugetlbfs_file_mmap(). I'm putting it there, rather than in the get_unmapped_area() path so it only needs to go in one place, than separately in the half-dozen or so arch-specific implementations of hugetlb_get_unmapped_area(). Signed-off-by: David Gibson Cc: Adam Litke Cc: Andi Kleen Cc: "David S. Miller" Cc: Benjamin Herrenschmidt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/hugetlbfs/inode.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'fs') diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index c848a191525d..950c2fbb815b 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c @@ -82,14 +82,19 @@ static int hugetlbfs_file_mmap(struct file *file, struct vm_area_struct *vma) int ret; /* - * vma alignment has already been checked by prepare_hugepage_range. - * If you add any error returns here, do so after setting VM_HUGETLB, - * so is_vm_hugetlb_page tests below unmap_region go the right way - * when do_mmap_pgoff unwinds (may be important on powerpc and ia64). + * vma address alignment (but not the pgoff alignment) has + * already been checked by prepare_hugepage_range. If you add + * any error returns here, do so after setting VM_HUGETLB, so + * is_vm_hugetlb_page tests below unmap_region go the right + * way when do_mmap_pgoff unwinds (may be important on powerpc + * and ia64). */ vma->vm_flags |= VM_HUGETLB | VM_RESERVED; vma->vm_ops = &hugetlb_vm_ops; + if (vma->vm_pgoff & ~(HPAGE_MASK >> PAGE_SHIFT)) + return -EINVAL; + vma_len = (loff_t)(vma->vm_end - vma->vm_start); mutex_lock(&inode->i_mutex); @@ -132,7 +137,7 @@ hugetlb_get_unmapped_area(struct file *file, unsigned long addr, return -ENOMEM; if (flags & MAP_FIXED) { - if (prepare_hugepage_range(addr, len, pgoff)) + if (prepare_hugepage_range(addr, len)) return -EINVAL; return addr; } -- cgit v1.2.2 From e89a5a43b95cdc4305b7c8e8121a380f02476636 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Fri, 31 Aug 2007 10:45:17 -0400 Subject: NFS: Fix the mount regression This avoids the recent NFS mount regression (returning EBUSY when mounting the same filesystem twice with different parameters). The best I can do given the constraints appears to be to have the kernel first look for a superblock that matches both the fsid and the user-specified mount options, and then spawn off a new superblock if that search fails. Note that this is not the same as specifying nosharecache everywhere since nosharecache will never attempt to match an existing superblock. Signed-off-by: Trond Myklebust Tested-by: Hua Zhong Signed-off-by: Linus Torvalds --- fs/nfs/super.c | 110 +++++++++++++++++++++++++++++++++------------------------ 1 file changed, 64 insertions(+), 46 deletions(-) (limited to 'fs') diff --git a/fs/nfs/super.c b/fs/nfs/super.c index b2a851c1b8cb..46139003ea0c 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -1303,34 +1303,6 @@ static void nfs_clone_super(struct super_block *sb, nfs_initialise_sb(sb); } -static int nfs_set_super(struct super_block *s, void *_server) -{ - struct nfs_server *server = _server; - int ret; - - s->s_fs_info = server; - ret = set_anon_super(s, server); - if (ret == 0) - server->s_dev = s->s_dev; - return ret; -} - -static int nfs_compare_super(struct super_block *sb, void *data) -{ - struct nfs_server *server = data, *old = NFS_SB(sb); - - if (memcmp(&old->nfs_client->cl_addr, - &server->nfs_client->cl_addr, - sizeof(old->nfs_client->cl_addr)) != 0) - return 0; - /* Note: NFS_MOUNT_UNSHARED == NFS4_MOUNT_UNSHARED */ - if (old->flags & NFS_MOUNT_UNSHARED) - return 0; - if (memcmp(&old->fsid, &server->fsid, sizeof(old->fsid)) != 0) - return 0; - return 1; -} - #define NFS_MS_MASK (MS_RDONLY|MS_NOSUID|MS_NODEV|MS_NOEXEC|MS_SYNCHRONOUS) static int nfs_compare_mount_options(const struct super_block *s, const struct nfs_server *b, int flags) @@ -1359,9 +1331,46 @@ static int nfs_compare_mount_options(const struct super_block *s, const struct n goto Ebusy; if (clnt_a->cl_auth->au_flavor != clnt_b->cl_auth->au_flavor) goto Ebusy; - return 0; + return 1; Ebusy: - return -EBUSY; + return 0; +} + +struct nfs_sb_mountdata { + struct nfs_server *server; + int mntflags; +}; + +static int nfs_set_super(struct super_block *s, void *data) +{ + struct nfs_sb_mountdata *sb_mntdata = data; + struct nfs_server *server = sb_mntdata->server; + int ret; + + s->s_flags = sb_mntdata->mntflags; + s->s_fs_info = server; + ret = set_anon_super(s, server); + if (ret == 0) + server->s_dev = s->s_dev; + return ret; +} + +static int nfs_compare_super(struct super_block *sb, void *data) +{ + struct nfs_sb_mountdata *sb_mntdata = data; + struct nfs_server *server = sb_mntdata->server, *old = NFS_SB(sb); + int mntflags = sb_mntdata->mntflags; + + if (memcmp(&old->nfs_client->cl_addr, + &server->nfs_client->cl_addr, + sizeof(old->nfs_client->cl_addr)) != 0) + return 0; + /* Note: NFS_MOUNT_UNSHARED == NFS4_MOUNT_UNSHARED */ + if (old->flags & NFS_MOUNT_UNSHARED) + return 0; + if (memcmp(&old->fsid, &server->fsid, sizeof(old->fsid)) != 0) + return 0; + return nfs_compare_mount_options(sb, server, mntflags); } static int nfs_get_sb(struct file_system_type *fs_type, @@ -1373,6 +1382,9 @@ static int nfs_get_sb(struct file_system_type *fs_type, struct nfs_mount_data *data = raw_data; struct dentry *mntroot; int (*compare_super)(struct super_block *, void *) = nfs_compare_super; + struct nfs_sb_mountdata sb_mntdata = { + .mntflags = flags, + }; int error; /* Validate the mount data */ @@ -1386,28 +1398,25 @@ static int nfs_get_sb(struct file_system_type *fs_type, error = PTR_ERR(server); goto out; } + sb_mntdata.server = server; if (server->flags & NFS_MOUNT_UNSHARED) compare_super = NULL; /* Get a superblock - note that we may end up sharing one that already exists */ - s = sget(fs_type, compare_super, nfs_set_super, server); + s = sget(fs_type, compare_super, nfs_set_super, &sb_mntdata); if (IS_ERR(s)) { error = PTR_ERR(s); goto out_err_nosb; } if (s->s_fs_info != server) { - error = nfs_compare_mount_options(s, server, flags); nfs_free_server(server); server = NULL; - if (error < 0) - goto error_splat_super; } if (!s->s_root) { /* initial superblock/root creation */ - s->s_flags = flags; nfs_fill_super(s, data); } @@ -1460,6 +1469,9 @@ static int nfs_xdev_get_sb(struct file_system_type *fs_type, int flags, struct nfs_server *server; struct dentry *mntroot; int (*compare_super)(struct super_block *, void *) = nfs_compare_super; + struct nfs_sb_mountdata sb_mntdata = { + .mntflags = flags, + }; int error; dprintk("--> nfs_xdev_get_sb()\n"); @@ -1470,28 +1482,25 @@ static int nfs_xdev_get_sb(struct file_system_type *fs_type, int flags, error = PTR_ERR(server); goto out_err_noserver; } + sb_mntdata.server = server; if (server->flags & NFS_MOUNT_UNSHARED) compare_super = NULL; /* Get a superblock - note that we may end up sharing one that already exists */ - s = sget(&nfs_fs_type, compare_super, nfs_set_super, server); + s = sget(&nfs_fs_type, compare_super, nfs_set_super, &sb_mntdata); if (IS_ERR(s)) { error = PTR_ERR(s); goto out_err_nosb; } if (s->s_fs_info != server) { - error = nfs_compare_mount_options(s, server, flags); nfs_free_server(server); server = NULL; - if (error < 0) - goto error_splat_super; } if (!s->s_root) { /* initial superblock/root creation */ - s->s_flags = flags; nfs_clone_super(s, data->sb); } @@ -1729,6 +1738,9 @@ static int nfs4_get_sb(struct file_system_type *fs_type, struct dentry *mntroot; char *mntpath = NULL, *hostname = NULL, *ip_addr = NULL; int (*compare_super)(struct super_block *, void *) = nfs_compare_super; + struct nfs_sb_mountdata sb_mntdata = { + .mntflags = flags, + }; int error; /* Validate the mount data */ @@ -1744,12 +1756,13 @@ static int nfs4_get_sb(struct file_system_type *fs_type, error = PTR_ERR(server); goto out; } + sb_mntdata.server = server; if (server->flags & NFS4_MOUNT_UNSHARED) compare_super = NULL; /* Get a superblock - note that we may end up sharing one that already exists */ - s = sget(fs_type, compare_super, nfs_set_super, server); + s = sget(fs_type, compare_super, nfs_set_super, &sb_mntdata); if (IS_ERR(s)) { error = PTR_ERR(s); goto out_free; @@ -1762,7 +1775,6 @@ static int nfs4_get_sb(struct file_system_type *fs_type, if (!s->s_root) { /* initial superblock/root creation */ - s->s_flags = flags; nfs4_fill_super(s); } @@ -1816,6 +1828,9 @@ static int nfs4_xdev_get_sb(struct file_system_type *fs_type, int flags, struct nfs_server *server; struct dentry *mntroot; int (*compare_super)(struct super_block *, void *) = nfs_compare_super; + struct nfs_sb_mountdata sb_mntdata = { + .mntflags = flags, + }; int error; dprintk("--> nfs4_xdev_get_sb()\n"); @@ -1826,12 +1841,13 @@ static int nfs4_xdev_get_sb(struct file_system_type *fs_type, int flags, error = PTR_ERR(server); goto out_err_noserver; } + sb_mntdata.server = server; if (server->flags & NFS4_MOUNT_UNSHARED) compare_super = NULL; /* Get a superblock - note that we may end up sharing one that already exists */ - s = sget(&nfs_fs_type, compare_super, nfs_set_super, server); + s = sget(&nfs_fs_type, compare_super, nfs_set_super, &sb_mntdata); if (IS_ERR(s)) { error = PTR_ERR(s); goto out_err_nosb; @@ -1844,7 +1860,6 @@ static int nfs4_xdev_get_sb(struct file_system_type *fs_type, int flags, if (!s->s_root) { /* initial superblock/root creation */ - s->s_flags = flags; nfs4_clone_super(s, data->sb); } @@ -1887,6 +1902,9 @@ static int nfs4_referral_get_sb(struct file_system_type *fs_type, int flags, struct dentry *mntroot; struct nfs_fh mntfh; int (*compare_super)(struct super_block *, void *) = nfs_compare_super; + struct nfs_sb_mountdata sb_mntdata = { + .mntflags = flags, + }; int error; dprintk("--> nfs4_referral_get_sb()\n"); @@ -1897,12 +1915,13 @@ static int nfs4_referral_get_sb(struct file_system_type *fs_type, int flags, error = PTR_ERR(server); goto out_err_noserver; } + sb_mntdata.server = server; if (server->flags & NFS4_MOUNT_UNSHARED) compare_super = NULL; /* Get a superblock - note that we may end up sharing one that already exists */ - s = sget(&nfs_fs_type, compare_super, nfs_set_super, server); + s = sget(&nfs_fs_type, compare_super, nfs_set_super, &sb_mntdata); if (IS_ERR(s)) { error = PTR_ERR(s); goto out_err_nosb; @@ -1915,7 +1934,6 @@ static int nfs4_referral_get_sb(struct file_system_type *fs_type, int flags, if (!s->s_root) { /* initial superblock/root creation */ - s->s_flags = flags; nfs4_fill_super(s); } -- cgit v1.2.2 From 560aef74503e928f44ddbf481b8b02d9cef37dbf Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 27 Aug 2007 09:14:56 -0400 Subject: NFS: Fix use of cancel_delayed_work_sync in nfs_release_automount_timer Doh! We can't use cancel_delayed_work_sync because we may have been called from an unmount that was being performed by nfs_automount_task. Signed-off-by: Trond Myklebust --- fs/nfs/namespace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c index aea76d0e5fbd..acfc56f9edc0 100644 --- a/fs/nfs/namespace.c +++ b/fs/nfs/namespace.c @@ -176,7 +176,7 @@ static void nfs_expire_automounts(struct work_struct *work) void nfs_release_automount_timer(void) { if (list_empty(&nfs_automount_list)) - cancel_delayed_work_sync(&nfs_automount_task); + cancel_delayed_work(&nfs_automount_task); } /* -- cgit v1.2.2 From 65bbf6bdbba0f74e254f706bfb00fe533974f4f1 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 27 Aug 2007 09:57:46 -0400 Subject: NFSv4: Fix a typo in _nfs4_do_open_reclaim This should fix the following Oops reported by Jeff Garzik: kernel BUG at fs/nfs/nfs4xdr.c:1040! invalid opcode: 0000 [1] SMP CPU 0 Modules linked in: nfs lockd sunrpc af_packet ipv6 cpufreq_ondemand acpi_cpufreq battery floppy nvram sg snd_hda_intel ata_generic snd_pcm_oss snd_mixer_oss snd_pcm i2c_i801 snd_page_alloc e1000 firewire_ohci ata_piix i2c_core sr_mod cdrom sata_sil ahci libata sd_mod scsi_mod ext3 jbd ehci_hcd uhci_hcd Pid: 16353, comm: 10.10.10.1-recl Not tainted 2.6.23-rc3 #1 RIP: 0010:[] [] :nfs:encode_open+0x1c0/0x330 RSP: 0018:ffff8100467c5c60 EFLAGS: 00010202 RAX: ffff81000f89b8b8 RBX: 00000000697a6f6d RCX: ffff81000f89b8b8 RDX: 0000000000000004 RSI: 0000000000000004 RDI: ffff8100467c5c80 RBP: ffff8100467c5c80 R08: ffff81000f89bc30 R09: ffff81000f89b83f R10: 0000000000000001 R11: ffffffff881e79e0 R12: ffff81003cbd1808 R13: ffff81000f89b860 R14: ffff81005fc984e0 R15: ffffffff88240af0 FS: 0000000000000000(0000) GS:ffffffff8052a000(0000) knlGS:0000000000000000 CS: 0010 DS: 0018 ES: 0018 CR0: 000000008005003b CR2: 00002adb9e51a030 CR3: 000000007ea7e000 CR4: 00000000000006e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 Process 10.10.10.1-recl (pid: 16353, threadinfo ffff8100467c4000, task ffff8100038ce780) Stack: ffff81004aeb6a40 ffff81003cbd1808 ffff81003cbd1808 ffffffff88240b5d ffff81000f89b8bc ffff81005fc984e8 ffff81000f89bc30 ffff81005fc984e8 0000000300000000 0000000000000000 0000000000000000 ffff81003cbd1800 Call Trace: [] :nfs:nfs4_xdr_enc_open_noattr+0x6d/0x90 [] :sunrpc:rpcauth_wrap_req+0x97/0xf0 [] :nfs:nfs4_xdr_enc_open_noattr+0x0/0x90 [] :sunrpc:call_transmit+0x18a/0x290 [] :sunrpc:__rpc_execute+0x6b/0x290 [] :sunrpc:rpc_do_run_task+0x76/0xd0 [] :nfs:_nfs4_proc_open+0x76/0x230 [] :nfs:nfs4_open_recover_helper+0x5e/0xc0 [] :nfs:nfs4_open_recover+0xe4/0x120 [] :nfs:nfs4_open_reclaim+0xa4/0xf0 [] :nfs:nfs4_reclaim_open_state+0x55/0x1b0 [] :nfs:reclaimer+0x2ca/0x390 [] :nfs:reclaimer+0x0/0x390 [] kthread+0x4b/0x80 [] child_rip+0xa/0x12 [] kthread+0x0/0x80 [] child_rip+0x0/0x12 Code: 0f 0b eb fe 48 89 ef c7 00 00 00 00 02 be 08 00 00 00 e8 79 RIP [] :nfs:encode_open+0x1c0/0x330 RSP Signed-off-by: Trond Myklebust --- fs/nfs/nfs4proc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 62b3ae280310..036d8625b4f9 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -646,7 +646,7 @@ static int _nfs4_do_open_reclaim(struct nfs_open_context *ctx, struct nfs4_state rcu_read_lock(); delegation = rcu_dereference(NFS_I(state->inode)->delegation); if (delegation != NULL && (delegation->flags & NFS_DELEGATION_NEED_RECLAIM) != 0) - delegation_type = delegation->flags; + delegation_type = delegation->type; rcu_read_unlock(); opendata->o_arg.u.delegation_type = delegation_type; status = nfs4_open_recover(opendata, state); -- cgit v1.2.2 From deee9369b993b52a8e2f25683b4a67be7a65e8ae Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 27 Aug 2007 11:33:00 -0400 Subject: NFSv4: Ensure that we pass the correct dentry to nfs4_intent_set_file This patch fixes an Oops that was reported by Gabriel Barazer. Signed-off-by: Trond Myklebust --- fs/nfs/nfs4proc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 036d8625b4f9..4b90e17555a9 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -1434,7 +1434,7 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd) } res = d_add_unique(dentry, igrab(state->inode)); if (res != NULL) - dentry = res; + path.dentry = res; nfs4_intent_set_file(nd, &path, state); return res; } -- cgit v1.2.2 From fdb66ff4ace3c4e18809b9b71dfcce1692143147 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Wed, 29 Aug 2007 17:58:57 -0400 Subject: NFS: mount option parser chokes on proto= The new text-based NFS mount option parsing logic doesn't recognize any valid transport protocols due to a silly mistake in the protocol token matching logic. This prevents basic mount requests such as: mount.nfs server:/export /mnt -o proto=tcp from working with the new text-based NFS mount API. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- fs/nfs/super.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'fs') diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 46139003ea0c..66a223b22a80 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -911,13 +911,13 @@ static int nfs_parse_mount_options(char *raw, kfree(string); switch (token) { - case Opt_udp: + case Opt_xprt_udp: mnt->flags &= ~NFS_MOUNT_TCP; mnt->nfs_server.protocol = IPPROTO_UDP; mnt->timeo = 7; mnt->retrans = 5; break; - case Opt_tcp: + case Opt_xprt_tcp: mnt->flags |= NFS_MOUNT_TCP; mnt->nfs_server.protocol = IPPROTO_TCP; mnt->timeo = 600; @@ -936,10 +936,10 @@ static int nfs_parse_mount_options(char *raw, kfree(string); switch (token) { - case Opt_udp: + case Opt_xprt_udp: mnt->mount_server.protocol = IPPROTO_UDP; break; - case Opt_tcp: + case Opt_xprt_tcp: mnt->mount_server.protocol = IPPROTO_TCP; break; default: -- cgit v1.2.2 From fdc6e2c8c0dc0ac702fca0b802f5d9ae99a54bb6 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Wed, 29 Aug 2007 17:58:59 -0400 Subject: NFS: Return a real error code from mount(2) Don't filter the return code from the in-kernel rpcbind or NFS mount clients. Return the real error code so that callers of the new NFS text-based mount API can apply a useful retry strategy. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- fs/nfs/super.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 66a223b22a80..9cd0828010cf 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -1166,7 +1166,7 @@ static int nfs_validate_mount_data(struct nfs_mount_data **options, status = nfs_try_mount(&args, mntfh); if (status) - return -EINVAL; + return status; /* * Translate to nfs_mount_data, which nfs_fill_super -- cgit v1.2.2 From 350c73af6af51ae7654dad91874c0d30dd13bbbe Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Wed, 29 Aug 2007 17:59:01 -0400 Subject: NFS: Off-by-one length error in string handling The hostname was getting truncated in the new text-based NFS mount API. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- fs/nfs/super.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 9cd0828010cf..ef3643284f72 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -1153,7 +1153,7 @@ static int nfs_validate_mount_data(struct nfs_mount_data **options, c = strchr(dev_name, ':'); if (c == NULL) return -EINVAL; - len = c - dev_name - 1; + len = c - dev_name; if (len > sizeof(data->hostname)) return -EINVAL; strncpy(data->hostname, dev_name, len); -- cgit v1.2.2 From 7d1cca72994c0e910ca443076dcfcfd473871dda Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Wed, 29 Aug 2007 17:59:03 -0400 Subject: NFS: change NFS mount error return when hostname/pathname too long According to the mount(2) man page, the proper error return code for the mount(2) system call when the special device name or the mounted-on directory name is too long is ENAMETOOLONG. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- fs/nfs/super.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'fs') diff --git a/fs/nfs/super.c b/fs/nfs/super.c index ef3643284f72..8ed593766f16 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -1155,13 +1155,13 @@ static int nfs_validate_mount_data(struct nfs_mount_data **options, return -EINVAL; len = c - dev_name; if (len > sizeof(data->hostname)) - return -EINVAL; + return -ENAMETOOLONG; strncpy(data->hostname, dev_name, len); args.nfs_server.hostname = data->hostname; c++; if (strlen(c) > NFS_MAXPATHLEN) - return -EINVAL; + return -ENAMETOOLONG; args.nfs_server.export_path = c; status = nfs_try_mount(&args, mntfh); @@ -1677,7 +1677,7 @@ static int nfs4_validate_mount_data(struct nfs4_mount_data **options, /* while calculating len, pretend ':' is '\0' */ len = c - dev_name; if (len > NFS4_MAXNAMLEN) - return -EINVAL; + return -ENAMETOOLONG; *hostname = kzalloc(len, GFP_KERNEL); if (*hostname == NULL) return -ENOMEM; @@ -1686,7 +1686,7 @@ static int nfs4_validate_mount_data(struct nfs4_mount_data **options, c++; /* step over the ':' */ len = strlen(c); if (len > NFS4_MAXPATHLEN) - return -EINVAL; + return -ENAMETOOLONG; *mntpath = kzalloc(len + 1, GFP_KERNEL); if (*mntpath == NULL) return -ENOMEM; -- cgit v1.2.2 From 1b3b4a1a2deb7d3e5d66063bd76304d840c966b3 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 28 Aug 2007 10:29:36 -0400 Subject: NFS: Fix a write request leak in nfs_invalidate_page() Ryusuke Konishi says: The recent truncate_complete_page() clears the dirty flag from a page before calling a_ops->invalidatepage(), ^^^^^^ static void truncate_complete_page(struct address_space *mapping, struct page *page) { ... cancel_dirty_page(page, PAGE_CACHE_SIZE); <--- Inserted here at kernel 2.6.20 if (PagePrivate(page)) do_invalidatepage(page, 0); ---> will call a_ops->invalidatepage() ... } and this is disturbing nfs_wb_page_priority() from calling nfs_writepage_locked() that is expected to handle the pending request (=nfs_page) associated with the page. int nfs_wb_page_priority(struct inode *inode, struct page *page, int how) { ... if (clear_page_dirty_for_io(page)) { ret = nfs_writepage_locked(page, &wbc); if (ret < 0) goto out; } ... } Since truncate_complete_page() will get rid of the page after a_ops->invalidatepage() returns, the request (=nfs_page) associated with the page becomes a garbage in nfs_inode->nfs_page_tree. ------------------------ Fix this by ensuring that nfs_wb_page_priority() recognises that it may also need to clear out non-dirty pages that have an nfs_page associated with them. Signed-off-by: Trond Myklebust --- fs/nfs/file.c | 2 +- fs/nfs/write.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/nfs/file.c b/fs/nfs/file.c index c87dc713b5d7..579cf8a7d4a7 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -316,7 +316,7 @@ static void nfs_invalidate_page(struct page *page, unsigned long offset) if (offset != 0) return; /* Cancel any unstarted writes on this page */ - nfs_wb_page_priority(page->mapping->host, page, FLUSH_INVALIDATE); + nfs_wb_page_cancel(page->mapping->host, page); } static int nfs_release_page(struct page *page, gfp_t gfp) diff --git a/fs/nfs/write.c b/fs/nfs/write.c index ef97e0c0f5b1..0d7a77cc394b 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -1396,6 +1396,50 @@ out: return ret; } +int nfs_wb_page_cancel(struct inode *inode, struct page *page) +{ + struct nfs_page *req; + loff_t range_start = page_offset(page); + loff_t range_end = range_start + (loff_t)(PAGE_CACHE_SIZE - 1); + struct writeback_control wbc = { + .bdi = page->mapping->backing_dev_info, + .sync_mode = WB_SYNC_ALL, + .nr_to_write = LONG_MAX, + .range_start = range_start, + .range_end = range_end, + }; + int ret = 0; + + BUG_ON(!PageLocked(page)); + for (;;) { + req = nfs_page_find_request(page); + if (req == NULL) + goto out; + if (test_bit(PG_NEED_COMMIT, &req->wb_flags)) { + nfs_release_request(req); + break; + } + if (nfs_lock_request_dontget(req)) { + nfs_inode_remove_request(req); + /* + * In case nfs_inode_remove_request has marked the + * page as being dirty + */ + cancel_dirty_page(page, PAGE_CACHE_SIZE); + nfs_unlock_request(req); + break; + } + ret = nfs_wait_on_request(req); + if (ret < 0) + goto out; + } + if (!PagePrivate(page)) + return 0; + ret = nfs_sync_mapping_wait(page->mapping, &wbc, FLUSH_INVALIDATE); +out: + return ret; +} + int nfs_wb_page_priority(struct inode *inode, struct page *page, int how) { loff_t range_start = page_offset(page); -- cgit v1.2.2 From fc0e01974ccccc7530b7634a63ee3fcc57b845ea Mon Sep 17 00:00:00 2001 From: Jason Lunz Date: Sat, 1 Sep 2007 12:06:03 -0700 Subject: [JFFS2] fix write deadlock regression I've bisected the deadlock when many small appends are done on jffs2 down to this commit: commit 6fe6900e1e5b6fa9e5c59aa5061f244fe3f467e2 Author: Nick Piggin Date: Sun May 6 14:49:04 2007 -0700 mm: make read_cache_page synchronous Ensure pages are uptodate after returning from read_cache_page, which allows us to cut out most of the filesystem-internal PageUptodate calls. I didn't have a great look down the call chains, but this appears to fixes 7 possible use-before uptodate in hfs, 2 in hfsplus, 1 in jfs, a few in ecryptfs, 1 in jffs2, and a possible cleared data overwritten with readpage in block2mtd. All depending on whether the filler is async and/or can return with a !uptodate page. It introduced a wait to read_cache_page, as well as a read_cache_page_async function equivalent to the old read_cache_page without any callers. Switching jffs2_gc_fetch_page to read_cache_page_async for the old behavior makes the deadlocks go away, but maybe reintroduces the use-before-uptodate problem? I don't understand the mm/fs interaction well enough to say. [It's fine. dwmw2.] Signed-off-by: Jason Lunz Signed-off-by: David Woodhouse --- fs/jffs2/fs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c index 1d3b7a9fc828..8bc727b71696 100644 --- a/fs/jffs2/fs.c +++ b/fs/jffs2/fs.c @@ -627,7 +627,7 @@ unsigned char *jffs2_gc_fetch_page(struct jffs2_sb_info *c, struct inode *inode = OFNI_EDONI_2SFFJ(f); struct page *pg; - pg = read_cache_page(inode->i_mapping, offset >> PAGE_CACHE_SHIFT, + pg = read_cache_page_async(inode->i_mapping, offset >> PAGE_CACHE_SHIFT, (void *)jffs2_do_readpage_unlock, inode); if (IS_ERR(pg)) return (void *)pg; -- cgit v1.2.2 From 8da22d7a3690818f6d340baa0ea585e71f0c506f Mon Sep 17 00:00:00 2001 From: David Chinner Date: Thu, 16 Aug 2007 15:20:56 +1000 Subject: [XFS] Set filestreams object timeout to something sane. SGI-PV: 968554 SGI-Modid: xfs-linux-melb:xfs-kern:29303a Signed-off-by: David Chinner Signed-off-by: Christoph Hellwig Signed-off-by: Tim Shimmin --- fs/xfs/linux-2.6/xfs_globals.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/xfs/linux-2.6/xfs_globals.c b/fs/xfs/linux-2.6/xfs_globals.c index bb72c3d4141f..81565dea9af7 100644 --- a/fs/xfs/linux-2.6/xfs_globals.c +++ b/fs/xfs/linux-2.6/xfs_globals.c @@ -46,7 +46,7 @@ xfs_param_t xfs_params = { .inherit_nosym = { 0, 0, 1 }, .rotorstep = { 1, 1, 255 }, .inherit_nodfrg = { 0, 1, 1 }, - .fstrm_timer = { 1, 50, 3600*100}, + .fstrm_timer = { 1, 30*100, 3600*100}, }; /* -- cgit v1.2.2 From 4b80916b29170744632356dd2e801f7c374676eb Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 16 Aug 2007 15:37:36 +1000 Subject: [XFS] Fix sparse NULL vs 0 warnings Sparse now warns about comparing pointers to 0, so change all instance where that happens to NULL instead. SGI-PV: 968555 SGI-Modid: xfs-linux-melb:xfs-kern:29308a Signed-off-by: Christoph Hellwig Signed-off-by: David Chinner Signed-off-by: Tim Shimmin --- fs/xfs/xfs_log.c | 12 ++++++------ fs/xfs/xfs_log_recover.c | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) (limited to 'fs') diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c index 9d4c4fbeb3ee..9bfb69e1e885 100644 --- a/fs/xfs/xfs_log.c +++ b/fs/xfs/xfs_log.c @@ -2185,13 +2185,13 @@ xlog_state_do_callback( } cb = iclog->ic_callback; - while (cb != 0) { + while (cb) { iclog->ic_callback_tail = &(iclog->ic_callback); iclog->ic_callback = NULL; LOG_UNLOCK(log, s); /* perform callbacks in the order given */ - for (; cb != 0; cb = cb_next) { + for (; cb; cb = cb_next) { cb_next = cb->cb_next; cb->cb_func(cb->cb_arg, aborted); } @@ -2202,7 +2202,7 @@ xlog_state_do_callback( loopdidcallbacks++; funcdidcallbacks++; - ASSERT(iclog->ic_callback == 0); + ASSERT(iclog->ic_callback == NULL); if (!(iclog->ic_state & XLOG_STATE_IOERROR)) iclog->ic_state = XLOG_STATE_DIRTY; @@ -3242,10 +3242,10 @@ xlog_ticket_put(xlog_t *log, #else /* When we debug, it is easier if tickets are cycled */ ticket->t_next = NULL; - if (log->l_tail != 0) { + if (log->l_tail) { log->l_tail->t_next = ticket; } else { - ASSERT(log->l_freelist == 0); + ASSERT(log->l_freelist == NULL); log->l_freelist = ticket; } log->l_tail = ticket; @@ -3463,7 +3463,7 @@ xlog_verify_iclog(xlog_t *log, s = LOG_LOCK(log); icptr = log->l_iclog; for (i=0; i < log->l_iclog_bufs; i++) { - if (icptr == 0) + if (icptr == NULL) xlog_panic("xlog_verify_iclog: invalid ptr"); icptr = icptr->ic_next; } diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c index fddbb091a86f..8ae6e8e5f3db 100644 --- a/fs/xfs/xfs_log_recover.c +++ b/fs/xfs/xfs_log_recover.c @@ -1366,7 +1366,7 @@ xlog_recover_add_to_cont_trans( int old_len; item = trans->r_itemq; - if (item == 0) { + if (item == NULL) { /* finish copying rest of trans header */ xlog_recover_add_item(&trans->r_itemq); ptr = (xfs_caddr_t) &trans->r_theader + @@ -1412,7 +1412,7 @@ xlog_recover_add_to_trans( if (!len) return 0; item = trans->r_itemq; - if (item == 0) { + if (item == NULL) { ASSERT(*(uint *)dp == XFS_TRANS_HEADER_MAGIC); if (len == sizeof(xfs_trans_header_t)) xlog_recover_add_item(&trans->r_itemq); @@ -1467,12 +1467,12 @@ xlog_recover_unlink_tid( xlog_recover_t *tp; int found = 0; - ASSERT(trans != 0); + ASSERT(trans != NULL); if (trans == *q) { *q = (*q)->r_next; } else { tp = *q; - while (tp != 0) { + while (tp) { if (tp->r_next == trans) { found = 1; break; @@ -1495,7 +1495,7 @@ xlog_recover_insert_item_backq( xlog_recover_item_t **q, xlog_recover_item_t *item) { - if (*q == 0) { + if (*q == NULL) { item->ri_prev = item->ri_next = item; *q = item; } else { @@ -1899,7 +1899,7 @@ xlog_recover_do_reg_buffer( break; nbits = xfs_contig_bits(data_map, map_size, bit); ASSERT(nbits > 0); - ASSERT(item->ri_buf[i].i_addr != 0); + ASSERT(item->ri_buf[i].i_addr != NULL); ASSERT(item->ri_buf[i].i_len % XFS_BLI_CHUNK == 0); ASSERT(XFS_BUF_COUNT(bp) >= ((uint)bit << XFS_BLI_SHIFT)+(nbits< Date: Thu, 16 Aug 2007 15:37:57 +1000 Subject: [XFS] Fix sparse warning in kmem_shake_allow We can't return a masked result of a __bitwise type. Compare it to 0 first to keep the behaviour without the warning. SGI-PV: 968555 SGI-Modid: xfs-linux-melb:xfs-kern:29309a Signed-off-by: Christoph Hellwig Signed-off-by: David Chinner Signed-off-by: Tim Shimmin --- fs/xfs/linux-2.6/kmem.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/xfs/linux-2.6/kmem.h b/fs/xfs/linux-2.6/kmem.h index b4acc7f3c374..e6ea293f303c 100644 --- a/fs/xfs/linux-2.6/kmem.h +++ b/fs/xfs/linux-2.6/kmem.h @@ -103,7 +103,7 @@ extern void *kmem_zone_zalloc(kmem_zone_t *, unsigned int __nocast); static inline int kmem_shake_allow(gfp_t gfp_mask) { - return (gfp_mask & __GFP_WAIT); + return (gfp_mask & __GFP_WAIT) != 0; } #endif /* __XFS_SUPPORT_KMEM_H__ */ -- cgit v1.2.2 From ee5c80239d5f152d99f69165afbd115518353563 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 16 Aug 2007 15:38:08 +1000 Subject: [XFS] fix ASSERT and ASSERT_ALWAYS - remove the != 0 inside the unlikely in ASSERT_ALWAYS because sparse now complains about comparisons between pointers and 0 - add a standalone ASSERT implementation because defining it to ASSERT_ALWAYS means the string is expanded before the token passing stringification. This way we get the actual content of the assertion in the assfail message and don't overflow sparse's stringification buffer leading to sparse error messages. SGI-PV: 968555 SGI-Modid: xfs-linux-melb:xfs-kern:29310a Signed-off-by: Christoph Hellwig Signed-off-by: David Chinner Signed-off-by: Tim Shimmin --- fs/xfs/support/debug.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'fs') diff --git a/fs/xfs/support/debug.h b/fs/xfs/support/debug.h index a27a7c8c0526..855da0408647 100644 --- a/fs/xfs/support/debug.h +++ b/fs/xfs/support/debug.h @@ -34,10 +34,10 @@ extern void cmn_err(int, char *, ...) extern void assfail(char *expr, char *f, int l); #define ASSERT_ALWAYS(expr) \ - (unlikely((expr) != 0) ? (void)0 : assfail(#expr, __FILE__, __LINE__)) + (unlikely(expr) ? (void)0 : assfail(#expr, __FILE__, __LINE__)) #ifndef DEBUG -# define ASSERT(expr) ((void)0) +#define ASSERT(expr) ((void)0) #ifndef STATIC # define STATIC static noinline @@ -49,8 +49,10 @@ extern void assfail(char *expr, char *f, int l); #else /* DEBUG */ -# define ASSERT(expr) ASSERT_ALWAYS(expr) -# include +#include + +#define ASSERT(expr) \ + (unlikely(expr) ? (void)0 : assfail(#expr, __FILE__, __LINE__)) #ifndef STATIC # define STATIC noinline -- cgit v1.2.2 From 265c1fac38e37e828df09965406e9cc20bfa3588 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 16 Aug 2007 15:38:19 +1000 Subject: [XFS] fix sparse shadowed variable warnings - in xfs_probe_cluster rename the inner len to pg_len. There's no harm here because the outer len isn't used after the inner len comes into existence but it keeps the code clean. - in xfs_da_do_buf remove the inner i because they don't overlap and they are both the same type. SGI-PV: 968555 SGI-Modid: xfs-linux-melb:xfs-kern:29311a Signed-off-by: Christoph Hellwig Signed-off-by: David Chinner Signed-off-by: Tim Shimmin --- fs/xfs/linux-2.6/xfs_aops.c | 8 ++++---- fs/xfs/xfs_da_btree.c | 1 - 2 files changed, 4 insertions(+), 5 deletions(-) (limited to 'fs') diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c index fd4105d662e0..d9c40fe64195 100644 --- a/fs/xfs/linux-2.6/xfs_aops.c +++ b/fs/xfs/linux-2.6/xfs_aops.c @@ -652,7 +652,7 @@ xfs_probe_cluster( for (i = 0; i < pagevec_count(&pvec); i++) { struct page *page = pvec.pages[i]; - size_t pg_offset, len = 0; + size_t pg_offset, pg_len = 0; if (tindex == tlast) { pg_offset = @@ -665,16 +665,16 @@ xfs_probe_cluster( pg_offset = PAGE_CACHE_SIZE; if (page->index == tindex && !TestSetPageLocked(page)) { - len = xfs_probe_page(page, pg_offset, mapped); + pg_len = xfs_probe_page(page, pg_offset, mapped); unlock_page(page); } - if (!len) { + if (!pg_len) { done = 1; break; } - total += len; + total += pg_len; tindex++; } diff --git a/fs/xfs/xfs_da_btree.c b/fs/xfs/xfs_da_btree.c index aea37df4aa62..26d09e2e1a7f 100644 --- a/fs/xfs/xfs_da_btree.c +++ b/fs/xfs/xfs_da_btree.c @@ -1975,7 +1975,6 @@ xfs_da_do_buf( error = mappedbno == -2 ? 0 : XFS_ERROR(EFSCORRUPTED); if (unlikely(error == EFSCORRUPTED)) { if (xfs_error_level >= XFS_ERRLEVEL_LOW) { - int i; cmn_err(CE_ALERT, "xfs_da_do_buf: bno %lld\n", (long long)bno); cmn_err(CE_ALERT, "dir: inode %lld\n", -- cgit v1.2.2 From 5995cb7d805496362e5af73235145667096fbc6f Mon Sep 17 00:00:00 2001 From: Eric Sandeen Date: Thu, 16 Aug 2007 16:49:11 +1000 Subject: [XFS] fix nasty quota hashtable allocation bug This git mod: 77e4635ae191774526ed695482a151ac986f3806 converted to a "greedy" allocation interface, but for the quota hashtables it switched from allocating XFS_QM_HASHSIZE (nr of elements) xfs_dqhash_t's to allocating only XFS_QM_HASHSIZE *bytes* - quite a lot smaller! Then when we converted hsize "back" to nr of elements (the division line) hsize went to 0. This was leading to oopses when running any quota tests on the Fedora 8 test kernel, but the problem has been there for almost a year. SGI-PV: 968837 SGI-Modid: xfs-linux-melb:xfs-kern:29354a Signed-off-by: Eric Sandeen Signed-off-by: David Chinner Signed-off-by: Tim Shimmin --- fs/xfs/quota/xfs_qm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/xfs/quota/xfs_qm.c b/fs/xfs/quota/xfs_qm.c index 2d274b23ade5..6ff0f4de1630 100644 --- a/fs/xfs/quota/xfs_qm.c +++ b/fs/xfs/quota/xfs_qm.c @@ -120,7 +120,8 @@ xfs_Gqm_init(void) * Initialize the dquot hash tables. */ udqhash = kmem_zalloc_greedy(&hsize, - XFS_QM_HASHSIZE_LOW, XFS_QM_HASHSIZE_HIGH, + XFS_QM_HASHSIZE_LOW * sizeof(xfs_dqhash_t), + XFS_QM_HASHSIZE_HIGH * sizeof(xfs_dqhash_t), KM_SLEEP | KM_MAYFAIL | KM_LARGE); gdqhash = kmem_zalloc(hsize, KM_SLEEP | KM_LARGE); hsize /= sizeof(xfs_dqhash_t); -- cgit v1.2.2 From a1033be72cdb053e182bb41e302a1c11e72b68bb Mon Sep 17 00:00:00 2001 From: Neil Brown Date: Wed, 5 Sep 2007 17:22:12 -0400 Subject: knfsd: Fixed problem with NFS exporting directories which are mounted on. Recent changes in NFSd cause a directory which is mounted-on to not appear properly when the filesystem containing it is exported. *exp_get* now returns -ENOENT rather than NULL and when commit 5d3dbbeaf56d0365ac6b5c0a0da0bd31cc4781e1 removed the NULL checks, it didn't add a check for -ENOENT. Signed-off-by: Neil Brown Signed-off-by: J. Bruce Fields Signed-off-by: Linus Torvalds --- fs/nfsd/vfs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index a0c2b253818b..7867151ebb83 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -115,7 +115,8 @@ nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp, exp2 = rqst_exp_get_by_name(rqstp, mnt, mounts); if (IS_ERR(exp2)) { - err = PTR_ERR(exp2); + if (PTR_ERR(exp2) != -ENOENT) + err = PTR_ERR(exp2); dput(mounts); mntput(mnt); goto out; -- cgit v1.2.2 From b8da0d1c27f144bce999c653467106f3f0d5a308 Mon Sep 17 00:00:00 2001 From: Neil Brown Date: Wed, 5 Sep 2007 17:22:13 -0400 Subject: knfsd: Validate filehandle type in fsid_source fsid_source decided where to get the 'fsid' number to return for a GETATTR based on the type of filehandle. It can be from the device, from the fsid, or from the UUID. It is possible for the filehandle to be inconsistent with the export information, so make sure the export information actually has the info implied by the value returned by fsid_source. Signed-off-by: Neil Brown Cc: "Luiz Fernando N. Capitulino" Signed-off-by: "J. Bruce Fields" Signed-off-by: Linus Torvalds --- fs/nfsd/nfsfh.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c index 0eb464a39aae..7011d62acfc8 100644 --- a/fs/nfsd/nfsfh.c +++ b/fs/nfsd/nfsfh.c @@ -566,13 +566,23 @@ enum fsid_source fsid_source(struct svc_fh *fhp) case FSID_DEV: case FSID_ENCODE_DEV: case FSID_MAJOR_MINOR: - return FSIDSOURCE_DEV; + if (fhp->fh_export->ex_dentry->d_inode->i_sb->s_type->fs_flags + & FS_REQUIRES_DEV) + return FSIDSOURCE_DEV; + break; case FSID_NUM: - return FSIDSOURCE_FSID; - default: if (fhp->fh_export->ex_flags & NFSEXP_FSID) return FSIDSOURCE_FSID; - else - return FSIDSOURCE_UUID; + break; + default: + break; } + /* either a UUID type filehandle, or the filehandle doesn't + * match the export. + */ + if (fhp->fh_export->ex_flags & NFSEXP_FSID) + return FSIDSOURCE_FSID; + if (fhp->fh_export->ex_uuid) + return FSIDSOURCE_UUID; + return FSIDSOURCE_DEV; } -- cgit v1.2.2 From 10b0845bed2b93f88d9758880a0a0e53f50c5139 Mon Sep 17 00:00:00 2001 From: Mark Fasheh Date: Thu, 23 Aug 2007 11:17:55 -0700 Subject: ocfs2: update docs for new features Update documentation listing ocfs2 features to reflect the current state of the file system. Add missing descriptions for some mount options which ocfs2 supports. Signed-off-by: Mark Fasheh --- fs/Kconfig | 3 --- 1 file changed, 3 deletions(-) (limited to 'fs') diff --git a/fs/Kconfig b/fs/Kconfig index 58a0650293e1..f9eed6d79066 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -441,9 +441,6 @@ config OCFS2_FS Note: Features which OCFS2 does not support yet: - extended attributes - - shared writeable mmap - - loopback is supported, but data written will not - be cluster coherent. - quotas - cluster aware flock - Directory change notification (F_NOTIFY) -- cgit v1.2.2 From c0123adef626607535f3c2c93b530c36780885e0 Mon Sep 17 00:00:00 2001 From: Tiger Yang Date: Sat, 8 Sep 2007 00:16:10 +0800 Subject: [PATCH] ocfs2: fix mount option parsing For some mount option types, ocfs2_parse_options() will try to access sb->s_fs_info to get at the ocfs2 private superblock. Unfortunately, that hasn't been allocated yet and will cause a kernel crash. Fix this by storing options in a struct which can then get pushed into the ocfs2_super once it's been allocated later. If we need more options which store to the ocfs2_super in the future, we can just fields to this struct. Signed-off-by: Tiger Yang Signed-off-by: Mark Fasheh --- fs/ocfs2/super.c | 69 ++++++++++++++++++++++++++++++-------------------------- 1 file changed, 37 insertions(+), 32 deletions(-) (limited to 'fs') diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c index f2fc9a795deb..c034b5129c1e 100644 --- a/fs/ocfs2/super.c +++ b/fs/ocfs2/super.c @@ -81,8 +81,15 @@ static struct dentry *ocfs2_debugfs_root = NULL; MODULE_AUTHOR("Oracle"); MODULE_LICENSE("GPL"); +struct mount_options +{ + unsigned long mount_opt; + unsigned int atime_quantum; + signed short slot; +}; + static int ocfs2_parse_options(struct super_block *sb, char *options, - unsigned long *mount_opt, s16 *slot, + struct mount_options *mopt, int is_remount); static void ocfs2_put_super(struct super_block *sb); static int ocfs2_mount_volume(struct super_block *sb); @@ -367,24 +374,23 @@ static int ocfs2_remount(struct super_block *sb, int *flags, char *data) { int incompat_features; int ret = 0; - unsigned long parsed_options; - s16 slot; + struct mount_options parsed_options; struct ocfs2_super *osb = OCFS2_SB(sb); - if (!ocfs2_parse_options(sb, data, &parsed_options, &slot, 1)) { + if (!ocfs2_parse_options(sb, data, &parsed_options, 1)) { ret = -EINVAL; goto out; } if ((osb->s_mount_opt & OCFS2_MOUNT_HB_LOCAL) != - (parsed_options & OCFS2_MOUNT_HB_LOCAL)) { + (parsed_options.mount_opt & OCFS2_MOUNT_HB_LOCAL)) { ret = -EINVAL; mlog(ML_ERROR, "Cannot change heartbeat mode on remount\n"); goto out; } if ((osb->s_mount_opt & OCFS2_MOUNT_DATA_WRITEBACK) != - (parsed_options & OCFS2_MOUNT_DATA_WRITEBACK)) { + (parsed_options.mount_opt & OCFS2_MOUNT_DATA_WRITEBACK)) { ret = -EINVAL; mlog(ML_ERROR, "Cannot change data mode on remount\n"); goto out; @@ -435,7 +441,9 @@ unlock_osb: /* Only save off the new mount options in case of a successful * remount. */ - osb->s_mount_opt = parsed_options; + osb->s_mount_opt = parsed_options.mount_opt; + osb->s_atime_quantum = parsed_options.atime_quantum; + osb->preferred_slot = parsed_options.slot; } out: return ret; @@ -547,8 +555,7 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent) { struct dentry *root; int status, sector_size; - unsigned long parsed_opt; - s16 slot; + struct mount_options parsed_options; struct inode *inode = NULL; struct ocfs2_super *osb = NULL; struct buffer_head *bh = NULL; @@ -556,14 +563,14 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent) mlog_entry("%p, %p, %i", sb, data, silent); - if (!ocfs2_parse_options(sb, data, &parsed_opt, &slot, 0)) { + if (!ocfs2_parse_options(sb, data, &parsed_options, 0)) { status = -EINVAL; goto read_super_error; } /* for now we only have one cluster/node, make sure we see it * in the heartbeat universe */ - if (parsed_opt & OCFS2_MOUNT_HB_LOCAL) { + if (parsed_options.mount_opt & OCFS2_MOUNT_HB_LOCAL) { if (!o2hb_check_local_node_heartbeating()) { status = -EINVAL; goto read_super_error; @@ -585,8 +592,9 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent) } brelse(bh); bh = NULL; - osb->s_mount_opt = parsed_opt; - osb->preferred_slot = slot; + osb->s_mount_opt = parsed_options.mount_opt; + osb->s_atime_quantum = parsed_options.atime_quantum; + osb->preferred_slot = parsed_options.slot; sb->s_magic = OCFS2_SUPER_MAGIC; @@ -728,8 +736,7 @@ static struct file_system_type ocfs2_fs_type = { static int ocfs2_parse_options(struct super_block *sb, char *options, - unsigned long *mount_opt, - s16 *slot, + struct mount_options *mopt, int is_remount) { int status; @@ -738,8 +745,9 @@ static int ocfs2_parse_options(struct super_block *sb, mlog_entry("remount: %d, options: \"%s\"\n", is_remount, options ? options : "(none)"); - *mount_opt = 0; - *slot = OCFS2_INVALID_SLOT; + mopt->mount_opt = 0; + mopt->atime_quantum = OCFS2_DEFAULT_ATIME_QUANTUM; + mopt->slot = OCFS2_INVALID_SLOT; if (!options) { status = 1; @@ -749,7 +757,6 @@ static int ocfs2_parse_options(struct super_block *sb, while ((p = strsep(&options, ",")) != NULL) { int token, option; substring_t args[MAX_OPT_ARGS]; - struct ocfs2_super * osb = OCFS2_SB(sb); if (!*p) continue; @@ -757,10 +764,10 @@ static int ocfs2_parse_options(struct super_block *sb, token = match_token(p, tokens, args); switch (token) { case Opt_hb_local: - *mount_opt |= OCFS2_MOUNT_HB_LOCAL; + mopt->mount_opt |= OCFS2_MOUNT_HB_LOCAL; break; case Opt_hb_none: - *mount_opt &= ~OCFS2_MOUNT_HB_LOCAL; + mopt->mount_opt &= ~OCFS2_MOUNT_HB_LOCAL; break; case Opt_barrier: if (match_int(&args[0], &option)) { @@ -768,27 +775,27 @@ static int ocfs2_parse_options(struct super_block *sb, goto bail; } if (option) - *mount_opt |= OCFS2_MOUNT_BARRIER; + mopt->mount_opt |= OCFS2_MOUNT_BARRIER; else - *mount_opt &= ~OCFS2_MOUNT_BARRIER; + mopt->mount_opt &= ~OCFS2_MOUNT_BARRIER; break; case Opt_intr: - *mount_opt &= ~OCFS2_MOUNT_NOINTR; + mopt->mount_opt &= ~OCFS2_MOUNT_NOINTR; break; case Opt_nointr: - *mount_opt |= OCFS2_MOUNT_NOINTR; + mopt->mount_opt |= OCFS2_MOUNT_NOINTR; break; case Opt_err_panic: - *mount_opt |= OCFS2_MOUNT_ERRORS_PANIC; + mopt->mount_opt |= OCFS2_MOUNT_ERRORS_PANIC; break; case Opt_err_ro: - *mount_opt &= ~OCFS2_MOUNT_ERRORS_PANIC; + mopt->mount_opt &= ~OCFS2_MOUNT_ERRORS_PANIC; break; case Opt_data_ordered: - *mount_opt &= ~OCFS2_MOUNT_DATA_WRITEBACK; + mopt->mount_opt &= ~OCFS2_MOUNT_DATA_WRITEBACK; break; case Opt_data_writeback: - *mount_opt |= OCFS2_MOUNT_DATA_WRITEBACK; + mopt->mount_opt |= OCFS2_MOUNT_DATA_WRITEBACK; break; case Opt_atime_quantum: if (match_int(&args[0], &option)) { @@ -796,9 +803,7 @@ static int ocfs2_parse_options(struct super_block *sb, goto bail; } if (option >= 0) - osb->s_atime_quantum = option; - else - osb->s_atime_quantum = OCFS2_DEFAULT_ATIME_QUANTUM; + mopt->atime_quantum = option; break; case Opt_slot: option = 0; @@ -807,7 +812,7 @@ static int ocfs2_parse_options(struct super_block *sb, goto bail; } if (option) - *slot = (s16)option; + mopt->slot = (s16)option; break; default: mlog(ML_ERROR, -- cgit v1.2.2 From 30b8548f2c270c0205558fe4826a6ab8e7fe51ad Mon Sep 17 00:00:00 2001 From: "tao.ma@oracle.com" Date: Thu, 6 Sep 2007 08:02:25 +0800 Subject: [PATCH] ocfs2: Fix a wrong cluster calculation. In ocfs2_alloc_write_write_ctxt, the written clusters length is calculated by the byte length only. This may cause some problems if we start to write at some position in the end of one cluster and last to a second cluster while the "len" is smaller than a cluster size. In that case, we have to write 2 clusters actually. So we have to take the start position into consideration also. Signed-off-by: Tao Ma Signed-off-by: Mark Fasheh --- fs/ocfs2/aops.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c index 460d440310f2..50cd8a209012 100644 --- a/fs/ocfs2/aops.c +++ b/fs/ocfs2/aops.c @@ -855,6 +855,7 @@ static int ocfs2_alloc_write_ctxt(struct ocfs2_write_ctxt **wcp, struct ocfs2_super *osb, loff_t pos, unsigned len, struct buffer_head *di_bh) { + u32 cend; struct ocfs2_write_ctxt *wc; wc = kzalloc(sizeof(struct ocfs2_write_ctxt), GFP_NOFS); @@ -862,7 +863,8 @@ static int ocfs2_alloc_write_ctxt(struct ocfs2_write_ctxt **wcp, return -ENOMEM; wc->w_cpos = pos >> osb->s_clustersize_bits; - wc->w_clen = ocfs2_clusters_for_bytes(osb->sb, len); + cend = (pos + len - 1) >> osb->s_clustersize_bits; + wc->w_clen = cend - wc->w_cpos + 1; get_bh(di_bh); wc->w_di_bh = di_bh; -- cgit v1.2.2 From e535e2efd295c3990bb9f654c8bb6bd176ebdc2b Mon Sep 17 00:00:00 2001 From: Mark Fasheh Date: Fri, 31 Aug 2007 10:23:41 -0700 Subject: ocfs2: Fix calculation of i_blocks during truncate We were setting i_blocks too early - before truncating any allocation. Correct things to set i_blocks after the allocation change. Signed-off-by: Mark Fasheh --- fs/ocfs2/alloc.c | 1 + fs/ocfs2/file.c | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c index 4f517665c9a0..778a850b4634 100644 --- a/fs/ocfs2/alloc.c +++ b/fs/ocfs2/alloc.c @@ -5602,6 +5602,7 @@ static int ocfs2_do_truncate(struct ocfs2_super *osb, clusters_to_del; spin_unlock(&OCFS2_I(inode)->ip_lock); le32_add_cpu(&fe->i_clusters, -clusters_to_del); + inode->i_blocks = ocfs2_inode_sector_count(inode); status = ocfs2_trim_tree(inode, path, handle, tc, clusters_to_del, &delete_blk); diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index 4ffa715be09c..7e34e66159c6 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c @@ -314,7 +314,6 @@ static int ocfs2_orphan_for_truncate(struct ocfs2_super *osb, } i_size_write(inode, new_i_size); - inode->i_blocks = ocfs2_align_bytes_to_sectors(new_i_size); inode->i_ctime = inode->i_mtime = CURRENT_TIME; di = (struct ocfs2_dinode *) fe_bh->b_data; -- cgit v1.2.2 From 9c3013e9b91ad23ecae88e45405e98208cce455d Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Tue, 11 Sep 2007 15:23:29 -0700 Subject: quota: fix infinite loop If we fail to start a transaction when releasing dquot, we have to call dquot_release() anyway to mark dquot structure as inactive. Otherwise we end in an infinite loop inside dqput(). Signed-off-by: Jan Kara Cc: xb Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ext3/super.c | 11 ++++++++++- fs/ext4/super.c | 11 ++++++++++- fs/reiserfs/super.c | 13 +++++++++++-- 3 files changed, 31 insertions(+), 4 deletions(-) (limited to 'fs') diff --git a/fs/ext3/super.c b/fs/ext3/super.c index 22cfdd61c060..9537316a0714 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c @@ -2578,8 +2578,11 @@ static int ext3_release_dquot(struct dquot *dquot) handle = ext3_journal_start(dquot_to_inode(dquot), EXT3_QUOTA_DEL_BLOCKS(dquot->dq_sb)); - if (IS_ERR(handle)) + if (IS_ERR(handle)) { + /* Release dquot anyway to avoid endless cycle in dqput() */ + dquot_release(dquot); return PTR_ERR(handle); + } ret = dquot_release(dquot); err = ext3_journal_stop(handle); if (!ret) @@ -2712,6 +2715,12 @@ static ssize_t ext3_quota_write(struct super_block *sb, int type, struct buffer_head *bh; handle_t *handle = journal_current_handle(); + if (!handle) { + printk(KERN_WARNING "EXT3-fs: Quota write (off=%Lu, len=%Lu)" + " cancelled because transaction is not started.\n", + (unsigned long long)off, (unsigned long long)len); + return -EIO; + } mutex_lock_nested(&inode->i_mutex, I_MUTEX_QUOTA); while (towrite > 0) { tocopy = sb->s_blocksize - offset < towrite ? diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 4550b83ab1c9..3c1397fa83df 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -2698,8 +2698,11 @@ static int ext4_release_dquot(struct dquot *dquot) handle = ext4_journal_start(dquot_to_inode(dquot), EXT4_QUOTA_DEL_BLOCKS(dquot->dq_sb)); - if (IS_ERR(handle)) + if (IS_ERR(handle)) { + /* Release dquot anyway to avoid endless cycle in dqput() */ + dquot_release(dquot); return PTR_ERR(handle); + } ret = dquot_release(dquot); err = ext4_journal_stop(handle); if (!ret) @@ -2832,6 +2835,12 @@ static ssize_t ext4_quota_write(struct super_block *sb, int type, struct buffer_head *bh; handle_t *handle = journal_current_handle(); + if (!handle) { + printk(KERN_WARNING "EXT4-fs: Quota write (off=%Lu, len=%Lu)" + " cancelled because transaction is not started.\n", + (unsigned long long)off, (unsigned long long)len); + return -EIO; + } mutex_lock_nested(&inode->i_mutex, I_MUTEX_QUOTA); while (towrite > 0) { tocopy = sb->s_blocksize - offset < towrite ? diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index 5b68dd3f191a..a005451930b7 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c @@ -1915,8 +1915,11 @@ static int reiserfs_release_dquot(struct dquot *dquot) ret = journal_begin(&th, dquot->dq_sb, REISERFS_QUOTA_DEL_BLOCKS(dquot->dq_sb)); - if (ret) + if (ret) { + /* Release dquot anyway to avoid endless cycle in dqput() */ + dquot_release(dquot); goto out; + } ret = dquot_release(dquot); err = journal_end(&th, dquot->dq_sb, @@ -2067,6 +2070,12 @@ static ssize_t reiserfs_quota_write(struct super_block *sb, int type, size_t towrite = len; struct buffer_head tmp_bh, *bh; + if (!current->journal_info) { + printk(KERN_WARNING "reiserfs: Quota write (off=%Lu, len=%Lu)" + " cancelled because transaction is not started.\n", + (unsigned long long)off, (unsigned long long)len); + return -EIO; + } mutex_lock_nested(&inode->i_mutex, I_MUTEX_QUOTA); while (towrite > 0) { tocopy = sb->s_blocksize - offset < towrite ? @@ -2098,7 +2107,7 @@ static ssize_t reiserfs_quota_write(struct super_block *sb, int type, data += tocopy; blk++; } - out: +out: if (len == towrite) return err; if (inode->i_size < off + len - towrite) -- cgit v1.2.2 From 1a1a1a758bf0107d1f78ff1d622f45987803d894 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Tue, 11 Sep 2007 15:23:37 -0700 Subject: afs: mntput called before dput dput must be called before mntput here. Signed-off-by: Andreas Gruenbacher Acked-By: David Howells Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/afs/mntpt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/afs/mntpt.c b/fs/afs/mntpt.c index a3684dcc76e7..6f8c96fb29eb 100644 --- a/fs/afs/mntpt.c +++ b/fs/afs/mntpt.c @@ -235,8 +235,8 @@ static void *afs_mntpt_follow_link(struct dentry *dentry, struct nameidata *nd) err = do_add_mount(newmnt, nd, MNT_SHRINKABLE, &afs_vfsmounts); switch (err) { case 0: - mntput(nd->mnt); dput(nd->dentry); + mntput(nd->mnt); nd->mnt = newmnt; nd->dentry = dget(newmnt->mnt_root); schedule_delayed_work(&afs_mntpt_expiry_timer, -- cgit v1.2.2 From dd23aae4f5edf4e1dbd8f7f8013a754ba3253f48 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Tue, 11 Sep 2007 15:23:55 -0700 Subject: Fix select on /proc files without ->poll MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Taneli Vähäkangas reported that commit 786d7e1612f0b0adb6046f19b906609e4fe8b1ba aka "Fix rmmod/read/write races in /proc entries" broke SBCL + SLIME combo. The old code in do_select() used DEFAULT_POLLMASK, if couldn't find ->poll handler. The new code makes ->poll always there and returns 0 by default, which is not correct. Return DEFAULT_POLLMASK instead. Steps to reproduce: install emacs, SBCL, SLIME emacs M-x slime in *inferior-lisp* buffer [watch it doing "Connecting to Swank on port X.."] Please, apply before 2.6.23. P.S.: why SBCL can't just read(2) /proc/cpuinfo is a mystery. Signed-off-by: Alexey Dobriyan Cc: T Taneli Vahakangas Cc: Oleg Nesterov Cc: "Eric W. Biederman" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/proc/inode.c | 3 ++- fs/select.c | 2 -- 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'fs') diff --git a/fs/proc/inode.c b/fs/proc/inode.c index a5b0dfd89a17..0e4d37c93eea 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -232,7 +233,7 @@ static ssize_t proc_reg_write(struct file *file, const char __user *buf, size_t static unsigned int proc_reg_poll(struct file *file, struct poll_table_struct *pts) { struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode); - unsigned int rv = 0; + unsigned int rv = DEFAULT_POLLMASK; unsigned int (*poll)(struct file *, struct poll_table_struct *); spin_lock(&pde->pde_unload_lock); diff --git a/fs/select.c b/fs/select.c index a974082b0824..46dca31c607a 100644 --- a/fs/select.c +++ b/fs/select.c @@ -26,8 +26,6 @@ #include -#define DEFAULT_POLLMASK (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM) - struct poll_table_page { struct poll_table_page * next; struct poll_table_entry * entry; -- cgit v1.2.2 From 0e2f6db88a6900bc9db576d6b478b12ee60d61f7 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Tue, 11 Sep 2007 15:24:01 -0700 Subject: Leases can be hidden by flocks The inode->i_flock list contains the leases, flocks and posix locks in the specified order. However, the flocks are added in the head of this list thus hiding the leases from F_GETLEASE command, from time_out_leases() and other code that expects the leases to come first. The following example will demonstrate this: #define _GNU_SOURCE #include #include #include #include static void show_lease(int fd) { int res; res = fcntl(fd, F_GETLEASE); switch (res) { case F_RDLCK: printf("Read lease\n"); break; case F_WRLCK: printf("Write lease\n"); break; case F_UNLCK: printf("No leases\n"); break; default: printf("Some shit\n"); break; } } int main(int argc, char **argv) { int fd, res; fd = open(argv[1], O_RDONLY); if (fd == -1) { perror("Can't open file"); return 1; } res = fcntl(fd, F_SETLEASE, F_WRLCK); if (res == -1) { perror("Can't set lease"); return 1; } show_lease(fd); if (flock(fd, LOCK_SH) == -1) { perror("Can't flock shared"); return 1; } show_lease(fd); return 0; } The first call to show_lease() will show the write lease set, but the second will show no leases. Fix the flock adding so that the leases always stay in the head of this list. Found during making the flocks pid-namespaces aware. Signed-off-by: Pavel Emelyanov Acked-by: "J. Bruce Fields" Cc: Trond Myklebust Cc: Andrew Morton Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/locks.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/locks.c b/fs/locks.c index 50857d2d3404..c795eaaf6c4c 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -782,7 +782,7 @@ find_conflict: if (request->fl_flags & FL_ACCESS) goto out; locks_copy_lock(new_fl, request); - locks_insert_lock(&inode->i_flock, new_fl); + locks_insert_lock(before, new_fl); new_fl = NULL; error = 0; -- cgit v1.2.2