From: Greg Kroah-Hartman Date: Fri, 27 Sep 2013 23:31:56 +0000 (-0700) Subject: 3.10-stable patches X-Git-Tag: v3.0.98~13 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=5a84e18d1b0d440baf700b48a8f1294da8289f15;p=thirdparty%2Fkernel%2Fstable-queue.git 3.10-stable patches added patches: audit-fix-endless-wait-in-audit_log_start.patch media-media-usb-fix-kconfig-dependencies.patch mm-fix-aio-performance-regression-for-database-caused-by-thp.patch properly-handle-tristate-dependencies-on-usb-pci-menus.patch udf-refuse-rw-mount-of-the-filesystem-instead-of-making-it-ro.patch udf-standardize-return-values-in-mount-sequence.patch --- diff --git a/queue-3.10/audit-fix-endless-wait-in-audit_log_start.patch b/queue-3.10/audit-fix-endless-wait-in-audit_log_start.patch new file mode 100644 index 00000000000..abee5b4deeb --- /dev/null +++ b/queue-3.10/audit-fix-endless-wait-in-audit_log_start.patch @@ -0,0 +1,48 @@ +From 8ac1c8d5deba65513b6a82c35e89e73996c8e0d6 Mon Sep 17 00:00:00 2001 +From: Konstantin Khlebnikov +Date: Tue, 24 Sep 2013 15:27:42 -0700 +Subject: audit: fix endless wait in audit_log_start() + +From: Konstantin Khlebnikov + +commit 8ac1c8d5deba65513b6a82c35e89e73996c8e0d6 upstream. + +After commit 829199197a43 ("kernel/audit.c: avoid negative sleep +durations") audit emitters will block forever if userspace daemon cannot +handle backlog. + +After the timeout the waiting loop turns into busy loop and runs until +daemon dies or returns back to work. This is a minimal patch for that +bug. + +Signed-off-by: Konstantin Khlebnikov +Cc: Luiz Capitulino +Cc: Richard Guy Briggs +Cc: Eric Paris +Cc: Chuck Anderson +Cc: Dan Duval +Cc: Dave Kleikamp +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Cc: Jonghwan Choi +Signed-off-by: Greg Kroah-Hartman + +--- + kernel/audit.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +--- a/kernel/audit.c ++++ b/kernel/audit.c +@@ -1117,9 +1117,10 @@ struct audit_buffer *audit_log_start(str + + sleep_time = timeout_start + audit_backlog_wait_time - + jiffies; +- if ((long)sleep_time > 0) ++ if ((long)sleep_time > 0) { + wait_for_auditd(sleep_time); +- continue; ++ continue; ++ } + } + if (audit_rate_check() && printk_ratelimit()) + printk(KERN_WARNING diff --git a/queue-3.10/media-media-usb-fix-kconfig-dependencies.patch b/queue-3.10/media-media-usb-fix-kconfig-dependencies.patch new file mode 100644 index 00000000000..36db19dd56f --- /dev/null +++ b/queue-3.10/media-media-usb-fix-kconfig-dependencies.patch @@ -0,0 +1,138 @@ +From a0f9354b1a319cb29c331bfd2e5a15d7f9b87fa4 Mon Sep 17 00:00:00 2001 +From: Randy Dunlap +Date: Wed, 8 May 2013 17:28:13 -0300 +Subject: media: media/usb: fix kconfig dependencies + +From: Randy Dunlap + +commit a0f9354b1a319cb29c331bfd2e5a15d7f9b87fa4 upstream. + +(a.k.a. Kconfig bool depending on a tristate considered harmful) +Fix various build errors when CONFIG_USB=m and media USB drivers +are builtin. In this case, CONFIG_USB_ZR364XX=y, +CONFIG_VIDEO_PVRUSB2=y, and CONFIG_VIDEO_STK1160=y. +This is caused by (from drivers/media/usb/Kconfig): +menuconfig MEDIA_USB_SUPPORT + bool "Media USB Adapters" + depends on USB && MEDIA_SUPPORT + =m =y +so MEDIA_USB_SUPPORT=y and all following Kconfig 'source' lines +are included. By adding an "if USB" guard around most of this file, +the needed dependencies are enforced. +drivers/built-in.o: In function `zr364xx_start_readpipe': +zr364xx.c:(.text+0xc726a): undefined reference to `usb_alloc_urb' +zr364xx.c:(.text+0xc72bb): undefined reference to `usb_submit_urb' +drivers/built-in.o: In function `zr364xx_stop_readpipe': +zr364xx.c:(.text+0xc72fd): undefined reference to `usb_kill_urb' +zr364xx.c:(.text+0xc7309): undefined reference to `usb_free_urb' +drivers/built-in.o: In function `read_pipe_completion': +zr364xx.c:(.text+0xc7acc): undefined reference to `usb_submit_urb' +drivers/built-in.o: In function `send_control_msg.constprop.12': +zr364xx.c:(.text+0xc7d2f): undefined reference to `usb_control_msg' +drivers/built-in.o: In function `pvr2_ctl_timeout': +pvrusb2-hdw.c:(.text+0xcadb6): undefined reference to `usb_unlink_urb' +pvrusb2-hdw.c:(.text+0xcadcb): undefined reference to `usb_unlink_urb' +drivers/built-in.o: In function `pvr2_hdw_create': +(.text+0xcc42c): undefined reference to `usb_alloc_urb' +drivers/built-in.o: In function `pvr2_hdw_create': +(.text+0xcc448): undefined reference to `usb_alloc_urb' +drivers/built-in.o: In function `pvr2_hdw_create': +(.text+0xcc5f9): undefined reference to `usb_set_interface' +drivers/built-in.o: In function `pvr2_hdw_create': +(.text+0xcc65a): undefined reference to `usb_free_urb' +drivers/built-in.o: In function `pvr2_hdw_create': +(.text+0xcc666): undefined reference to `usb_free_urb' +drivers/built-in.o: In function `pvr2_send_request_ex.part.22': +pvrusb2-hdw.c:(.text+0xccbe3): undefined reference to `usb_submit_urb' +pvrusb2-hdw.c:(.text+0xccc83): undefined reference to `usb_submit_urb' +drivers/built-in.o: In function `pvr2_hdw_remove_usb_stuff.part.25': +pvrusb2-hdw.c:(.text+0xcd3f9): undefined reference to `usb_kill_urb' +pvrusb2-hdw.c:(.text+0xcd405): undefined reference to `usb_free_urb' +pvrusb2-hdw.c:(.text+0xcd421): undefined reference to `usb_kill_urb' +pvrusb2-hdw.c:(.text+0xcd42d): undefined reference to `usb_free_urb' +drivers/built-in.o: In function `pvr2_hdw_device_reset': +(.text+0xcd658): undefined reference to `usb_lock_device_for_reset' +drivers/built-in.o: In function `pvr2_hdw_device_reset': +(.text+0xcd664): undefined reference to `usb_reset_device' +drivers/built-in.o: In function `pvr2_hdw_cpureset_assert': +(.text+0xcd6f9): undefined reference to `usb_control_msg' +drivers/built-in.o: In function `pvr2_hdw_cpufw_set_enabled': +(.text+0xcd84e): undefined reference to `usb_control_msg' +drivers/built-in.o: In function `pvr2_upload_firmware1': +pvrusb2-hdw.c:(.text+0xcda47): undefined reference to `usb_clear_halt' +pvrusb2-hdw.c:(.text+0xcdb04): undefined reference to `usb_control_msg' +drivers/built-in.o: In function `pvr2_upload_firmware2': +(.text+0xce7dc): undefined reference to `usb_bulk_msg' +drivers/built-in.o: In function `pvr2_stream_buffer_count': +pvrusb2-io.c:(.text+0xd2e05): undefined reference to `usb_alloc_urb' +pvrusb2-io.c:(.text+0xd2e5b): undefined reference to `usb_kill_urb' +pvrusb2-io.c:(.text+0xd2e9f): undefined reference to `usb_free_urb' +drivers/built-in.o: In function `pvr2_stream_internal_flush': +pvrusb2-io.c:(.text+0xd2f9b): undefined reference to `usb_kill_urb' +drivers/built-in.o: In function `pvr2_buffer_queue': +(.text+0xd3328): undefined reference to `usb_kill_urb' +drivers/built-in.o: In function `pvr2_buffer_queue': +(.text+0xd33ea): undefined reference to `usb_submit_urb' +drivers/built-in.o: In function `stk1160_read_reg': +(.text+0xd3efa): undefined reference to `usb_control_msg' +drivers/built-in.o: In function `stk1160_write_reg': +(.text+0xd3f4f): undefined reference to `usb_control_msg' +drivers/built-in.o: In function `stop_streaming': +stk1160-v4l.c:(.text+0xd4997): undefined reference to `usb_set_interface' +drivers/built-in.o: In function `start_streaming': +stk1160-v4l.c:(.text+0xd4a9f): undefined reference to `usb_set_interface' +stk1160-v4l.c:(.text+0xd4afa): undefined reference to `usb_submit_urb' +stk1160-v4l.c:(.text+0xd4ba3): undefined reference to `usb_set_interface' +drivers/built-in.o: In function `stk1160_isoc_irq': +stk1160-video.c:(.text+0xd509b): undefined reference to `usb_submit_urb' +drivers/built-in.o: In function `stk1160_cancel_isoc': +(.text+0xd50ef): undefined reference to `usb_kill_urb' +drivers/built-in.o: In function `stk1160_free_isoc': +(.text+0xd5155): undefined reference to `usb_free_coherent' +drivers/built-in.o: In function `stk1160_free_isoc': +(.text+0xd515d): undefined reference to `usb_free_urb' +drivers/built-in.o: In function `stk1160_alloc_isoc': +(.text+0xd5278): undefined reference to `usb_alloc_urb' +drivers/built-in.o: In function `stk1160_alloc_isoc': +(.text+0xd52c2): undefined reference to `usb_alloc_coherent' +drivers/built-in.o: In function `stk1160_alloc_isoc': +(.text+0xd53c4): undefined reference to `usb_free_urb' +drivers/built-in.o: In function `zr364xx_driver_init': +zr364xx.c:(.init.text+0x463e): undefined reference to `usb_register_driver' +drivers/built-in.o: In function `pvr_init': +pvrusb2-main.c:(.init.text+0x4662): undefined reference to `usb_register_driver' +drivers/built-in.o: In function `stk1160_usb_driver_init': +stk1160-core.c:(.init.text+0x467d): undefined reference to `usb_register_driver' +drivers/built-in.o: In function `zr364xx_driver_exit': +zr364xx.c:(.exit.text+0x1377): undefined reference to `usb_deregister' +drivers/built-in.o: In function `pvr_exit': +pvrusb2-main.c:(.exit.text+0x1389): undefined reference to `usb_deregister' +drivers/built-in.o: In function `stk1160_usb_driver_exit': +stk1160-core.c:(.exit.text+0x13a0): undefined reference to `usb_deregister' + +Suggested-by: "Yann E. MORIN" +Signed-off-by: Randy Dunlap +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/media/usb/Kconfig | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +--- a/drivers/media/usb/Kconfig ++++ b/drivers/media/usb/Kconfig +@@ -1,6 +1,8 @@ ++if USB ++ + menuconfig MEDIA_USB_SUPPORT + bool "Media USB Adapters" +- depends on USB && MEDIA_SUPPORT ++ depends on MEDIA_SUPPORT + help + Enable media drivers for USB bus. + If you have such devices, say Y. +@@ -52,3 +54,4 @@ source "drivers/media/usb/em28xx/Kconfig + endif + + endif #MEDIA_USB_SUPPORT ++endif #USB diff --git a/queue-3.10/mm-fix-aio-performance-regression-for-database-caused-by-thp.patch b/queue-3.10/mm-fix-aio-performance-regression-for-database-caused-by-thp.patch new file mode 100644 index 00000000000..3308e30d099 --- /dev/null +++ b/queue-3.10/mm-fix-aio-performance-regression-for-database-caused-by-thp.patch @@ -0,0 +1,177 @@ +From 7cb2ef56e6a8b7b368b2e883a0a47d02fed66911 Mon Sep 17 00:00:00 2001 +From: Khalid Aziz +Date: Wed, 11 Sep 2013 14:22:20 -0700 +Subject: mm: fix aio performance regression for database caused by THP + +From: Khalid Aziz + +commit 7cb2ef56e6a8b7b368b2e883a0a47d02fed66911 upstream. + +I am working with a tool that simulates oracle database I/O workload. +This tool (orion to be specific - +) +allocates hugetlbfs pages using shmget() with SHM_HUGETLB flag. It then +does aio into these pages from flash disks using various common block +sizes used by database. I am looking at performance with two of the most +common block sizes - 1M and 64K. aio performance with these two block +sizes plunged after Transparent HugePages was introduced in the kernel. +Here are performance numbers: + + pre-THP 2.6.39 3.11-rc5 +1M read 8384 MB/s 5629 MB/s 6501 MB/s +64K read 7867 MB/s 4576 MB/s 4251 MB/s + +I have narrowed the performance impact down to the overheads introduced by +THP in __get_page_tail() and put_compound_page() routines. perf top shows +>40% of cycles being spent in these two routines. Every time direct I/O +to hugetlbfs pages starts, kernel calls get_page() to grab a reference to +the pages and calls put_page() when I/O completes to put the reference +away. THP introduced significant amount of locking overhead to get_page() +and put_page() when dealing with compound pages because hugepages can be +split underneath get_page() and put_page(). It added this overhead +irrespective of whether it is dealing with hugetlbfs pages or transparent +hugepages. This resulted in 20%-45% drop in aio performance when using +hugetlbfs pages. + +Since hugetlbfs pages can not be split, there is no reason to go through +all the locking overhead for these pages from what I can see. I added +code to __get_page_tail() and put_compound_page() to bypass all the +locking code when working with hugetlbfs pages. This improved performance +significantly. Performance numbers with this patch: + + pre-THP 3.11-rc5 3.11-rc5 + Patch +1M read 8384 MB/s 6501 MB/s 8371 MB/s +64K read 7867 MB/s 4251 MB/s 6510 MB/s + +Performance with 64K read is still lower than what it was before THP, but +still a 53% improvement. It does mean there is more work to be done but I +will take a 53% improvement for now. + +Please take a look at the following patch and let me know if it looks +reasonable. + +[akpm@linux-foundation.org: tweak comments] +Signed-off-by: Khalid Aziz +Cc: Pravin B Shelar +Cc: Christoph Lameter +Cc: Andrea Arcangeli +Cc: Johannes Weiner +Cc: Mel Gorman +Cc: Rik van Riel +Cc: Minchan Kim +Cc: Andi Kleen +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + mm/swap.c | 77 +++++++++++++++++++++++++++++++++++++++++--------------------- + 1 file changed, 52 insertions(+), 25 deletions(-) + +--- a/mm/swap.c ++++ b/mm/swap.c +@@ -31,6 +31,7 @@ + #include + #include + #include ++#include + + #include "internal.h" + +@@ -78,6 +79,19 @@ static void __put_compound_page(struct p + + static void put_compound_page(struct page *page) + { ++ /* ++ * hugetlbfs pages cannot be split from under us. If this is a ++ * hugetlbfs page, check refcount on head page and release the page if ++ * the refcount becomes zero. ++ */ ++ if (PageHuge(page)) { ++ page = compound_head(page); ++ if (put_page_testzero(page)) ++ __put_compound_page(page); ++ ++ return; ++ } ++ + if (unlikely(PageTail(page))) { + /* __split_huge_page_refcount can run under us */ + struct page *page_head = compound_trans_head(page); +@@ -181,38 +195,51 @@ bool __get_page_tail(struct page *page) + * proper PT lock that already serializes against + * split_huge_page(). + */ +- unsigned long flags; + bool got = false; +- struct page *page_head = compound_trans_head(page); ++ struct page *page_head; + +- if (likely(page != page_head && get_page_unless_zero(page_head))) { ++ /* ++ * If this is a hugetlbfs page it cannot be split under us. Simply ++ * increment refcount for the head page. ++ */ ++ if (PageHuge(page)) { ++ page_head = compound_head(page); ++ atomic_inc(&page_head->_count); ++ got = true; ++ } else { ++ unsigned long flags; ++ ++ page_head = compound_trans_head(page); ++ if (likely(page != page_head && ++ get_page_unless_zero(page_head))) { ++ ++ /* Ref to put_compound_page() comment. */ ++ if (PageSlab(page_head)) { ++ if (likely(PageTail(page))) { ++ __get_page_tail_foll(page, false); ++ return true; ++ } else { ++ put_page(page_head); ++ return false; ++ } ++ } + +- /* Ref to put_compound_page() comment. */ +- if (PageSlab(page_head)) { ++ /* ++ * page_head wasn't a dangling pointer but it ++ * may not be a head page anymore by the time ++ * we obtain the lock. That is ok as long as it ++ * can't be freed from under us. ++ */ ++ flags = compound_lock_irqsave(page_head); ++ /* here __split_huge_page_refcount won't run anymore */ + if (likely(PageTail(page))) { + __get_page_tail_foll(page, false); +- return true; +- } else { +- put_page(page_head); +- return false; ++ got = true; + } ++ compound_unlock_irqrestore(page_head, flags); ++ if (unlikely(!got)) ++ put_page(page_head); + } +- +- /* +- * page_head wasn't a dangling pointer but it +- * may not be a head page anymore by the time +- * we obtain the lock. That is ok as long as it +- * can't be freed from under us. +- */ +- flags = compound_lock_irqsave(page_head); +- /* here __split_huge_page_refcount won't run anymore */ +- if (likely(PageTail(page))) { +- __get_page_tail_foll(page, false); +- got = true; +- } +- compound_unlock_irqrestore(page_head, flags); +- if (unlikely(!got)) +- put_page(page_head); + } + return got; + } diff --git a/queue-3.10/properly-handle-tristate-dependencies-on-usb-pci-menus.patch b/queue-3.10/properly-handle-tristate-dependencies-on-usb-pci-menus.patch new file mode 100644 index 00000000000..dee9846fe99 --- /dev/null +++ b/queue-3.10/properly-handle-tristate-dependencies-on-usb-pci-menus.patch @@ -0,0 +1,54 @@ +From 5077ac3b8108007f4a2b4589f2d373cf55453206 Mon Sep 17 00:00:00 2001 +From: Mauro Carvalho Chehab +Date: Wed, 22 May 2013 11:25:52 -0300 +Subject: Properly handle tristate dependencies on USB/PCI menus + +From: Mauro Carvalho Chehab + +commit 5077ac3b8108007f4a2b4589f2d373cf55453206 upstream. + +As USB/PCI/MEDIA_SUPPORT dependencies can be tristate, we can't +simply make the bool menu to be dependent on it. Everything below +the menu should also depend on it, otherwise, we risk to allow +building them with 'y', while only 'm' would be supported. + +So, add an IF just before everything below, in order to avoid +such risks. + +Signed-off-by: Mauro Carvalho Chehab +Cc: Randy Dunlap +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/media/pci/Kconfig | 4 +++- + drivers/media/usb/Kconfig | 3 +-- + 2 files changed, 4 insertions(+), 3 deletions(-) + +--- a/drivers/media/pci/Kconfig ++++ b/drivers/media/pci/Kconfig +@@ -1,6 +1,7 @@ ++if PCI && MEDIA_SUPPORT ++ + menuconfig MEDIA_PCI_SUPPORT + bool "Media PCI Adapters" +- depends on PCI && MEDIA_SUPPORT + help + Enable media drivers for PCI/PCIe bus. + If you have such devices, say Y. +@@ -45,3 +46,4 @@ source "drivers/media/pci/ddbridge/Kconf + endif + + endif #MEDIA_PCI_SUPPORT ++endif #PCI +--- a/drivers/media/usb/Kconfig ++++ b/drivers/media/usb/Kconfig +@@ -1,8 +1,7 @@ +-if USB ++if USB && MEDIA_SUPPORT + + menuconfig MEDIA_USB_SUPPORT + bool "Media USB Adapters" +- depends on MEDIA_SUPPORT + help + Enable media drivers for USB bus. + If you have such devices, say Y. diff --git a/queue-3.10/series b/queue-3.10/series index f0f9242f369..3592656e326 100644 --- a/queue-3.10/series +++ b/queue-3.10/series @@ -33,3 +33,9 @@ rt2800-change-initialization-sequence-to-fix-system-freeze.patch drm-radeon-atom-workaround-vbios-bug-in-transmitter-table-on-rs880-v2.patch drm-radeon-fix-panel-scaling-with-edp-and-lvds-bridges.patch drm-radeon-avoid-uvd-corruptions-on-agp-cards.patch +media-media-usb-fix-kconfig-dependencies.patch +properly-handle-tristate-dependencies-on-usb-pci-menus.patch +udf-standardize-return-values-in-mount-sequence.patch +udf-refuse-rw-mount-of-the-filesystem-instead-of-making-it-ro.patch +audit-fix-endless-wait-in-audit_log_start.patch +mm-fix-aio-performance-regression-for-database-caused-by-thp.patch diff --git a/queue-3.10/udf-refuse-rw-mount-of-the-filesystem-instead-of-making-it-ro.patch b/queue-3.10/udf-refuse-rw-mount-of-the-filesystem-instead-of-making-it-ro.patch new file mode 100644 index 00000000000..4e2f27bc50c --- /dev/null +++ b/queue-3.10/udf-refuse-rw-mount-of-the-filesystem-instead-of-making-it-ro.patch @@ -0,0 +1,111 @@ +From e729eac6f65e11c5f03b09adcc84bd5bcb230467 Mon Sep 17 00:00:00 2001 +From: Jan Kara +Date: Thu, 25 Jul 2013 16:15:16 +0200 +Subject: udf: Refuse RW mount of the filesystem instead of making it RO + +From: Jan Kara + +commit e729eac6f65e11c5f03b09adcc84bd5bcb230467 upstream. + +Refuse RW mount of udf filesystem. So far we just silently changed it +to RO mount but when the media is writeable, block layer won't notice +this change and thus will think device is used RW and will block eject +button of the drive. That is unexpected by users because for +non-writeable media eject button works just fine. + +Userspace mount(8) command handles this just fine and retries mounting +with MS_RDONLY set so userspace shouldn't see any regression. Plus any +tool mounting udf is likely confronted with the case of read-only +media where block layer already refuses to mount the filesystem without +MS_RDONLY set so our behavior shouldn't be anything new for it. + +Reported-by: Hui Wang +Signed-off-by: Jan Kara +Signed-off-by: Greg Kroah-Hartman + +--- + fs/udf/super.c | 42 ++++++++++++++++++++++++------------------ + 1 file changed, 24 insertions(+), 18 deletions(-) + +--- a/fs/udf/super.c ++++ b/fs/udf/super.c +@@ -630,6 +630,12 @@ static int udf_remount_fs(struct super_b + struct udf_sb_info *sbi = UDF_SB(sb); + int error = 0; + ++ if (sbi->s_lvid_bh) { ++ int write_rev = le16_to_cpu(udf_sb_lvidiu(sbi)->minUDFWriteRev); ++ if (write_rev > UDF_MAX_WRITE_VERSION && !(*flags & MS_RDONLY)) ++ return -EACCES; ++ } ++ + uopt.flags = sbi->s_flags; + uopt.uid = sbi->s_uid; + uopt.gid = sbi->s_gid; +@@ -649,12 +655,6 @@ static int udf_remount_fs(struct super_b + sbi->s_dmode = uopt.dmode; + write_unlock(&sbi->s_cred_lock); + +- if (sbi->s_lvid_bh) { +- int write_rev = le16_to_cpu(udf_sb_lvidiu(sbi)->minUDFWriteRev); +- if (write_rev > UDF_MAX_WRITE_VERSION) +- *flags |= MS_RDONLY; +- } +- + if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY)) + goto out_unlock; + +@@ -1284,16 +1284,18 @@ static int udf_load_partdesc(struct supe + goto out_bh; + } + } else { ++ /* ++ * If we have a partition with virtual map, we don't handle ++ * writing to it (we overwrite blocks instead of relocating ++ * them). ++ */ ++ if (!(sb->s_flags & MS_RDONLY)) { ++ ret = -EACCES; ++ goto out_bh; ++ } + ret = udf_load_vat(sb, i, type1_idx); + if (ret < 0) + goto out_bh; +- /* +- * Mark filesystem read-only if we have a partition with +- * virtual map since we don't handle writing to it (we +- * overwrite blocks instead of relocating them). +- */ +- sb->s_flags |= MS_RDONLY; +- pr_notice("Filesystem marked read-only because writing to pseudooverwrite partition is not implemented\n"); + } + ret = 0; + out_bh: +@@ -2103,8 +2105,11 @@ static int udf_fill_super(struct super_b + UDF_MAX_READ_VERSION); + ret = -EINVAL; + goto error_out; +- } else if (minUDFWriteRev > UDF_MAX_WRITE_VERSION) +- sb->s_flags |= MS_RDONLY; ++ } else if (minUDFWriteRev > UDF_MAX_WRITE_VERSION && ++ !(sb->s_flags & MS_RDONLY)) { ++ ret = -EACCES; ++ goto error_out; ++ } + + sbi->s_udfrev = minUDFWriteRev; + +@@ -2121,9 +2126,10 @@ static int udf_fill_super(struct super_b + } + + if (sbi->s_partmaps[sbi->s_partition].s_partition_flags & +- UDF_PART_FLAG_READ_ONLY) { +- pr_notice("Partition marked readonly; forcing readonly mount\n"); +- sb->s_flags |= MS_RDONLY; ++ UDF_PART_FLAG_READ_ONLY && ++ !(sb->s_flags & MS_RDONLY)) { ++ ret = -EACCES; ++ goto error_out; + } + + if (udf_find_fileset(sb, &fileset, &rootdir)) { diff --git a/queue-3.10/udf-standardize-return-values-in-mount-sequence.patch b/queue-3.10/udf-standardize-return-values-in-mount-sequence.patch new file mode 100644 index 00000000000..c79641a3e3b --- /dev/null +++ b/queue-3.10/udf-standardize-return-values-in-mount-sequence.patch @@ -0,0 +1,731 @@ +From d759bfa4e7919b89357de50a2e23817079889195 Mon Sep 17 00:00:00 2001 +From: Jan Kara +Date: Thu, 25 Jul 2013 19:10:59 +0200 +Subject: udf: Standardize return values in mount sequence + +From: Jan Kara + +commit d759bfa4e7919b89357de50a2e23817079889195 upstream. + +Change all function used in filesystem discovery during mount to user +standard kernel return values - -errno on error, 0 on success instead +of 1 on failure and 0 on success. This allows us to pass error number +(not just failure / success) so we can abort device scanning earlier +in case of errors like EIO or ENOMEM . Also we will be able to return +EROFS in case writeable mount is requested but writing isn't supported. + +Signed-off-by: Jan Kara +Cc: Hui Wang +Signed-off-by: Greg Kroah-Hartman + +--- + fs/udf/super.c | 300 ++++++++++++++++++++++++++++++++++----------------------- + 1 file changed, 183 insertions(+), 117 deletions(-) + +--- a/fs/udf/super.c ++++ b/fs/udf/super.c +@@ -843,27 +843,38 @@ static int udf_find_fileset(struct super + return 1; + } + ++/* ++ * Load primary Volume Descriptor Sequence ++ * ++ * Return <0 on error, 0 on success. -EAGAIN is special meaning next sequence ++ * should be tried. ++ */ + static int udf_load_pvoldesc(struct super_block *sb, sector_t block) + { + struct primaryVolDesc *pvoldesc; + struct ustr *instr, *outstr; + struct buffer_head *bh; + uint16_t ident; +- int ret = 1; ++ int ret = -ENOMEM; + + instr = kmalloc(sizeof(struct ustr), GFP_NOFS); + if (!instr) +- return 1; ++ return -ENOMEM; + + outstr = kmalloc(sizeof(struct ustr), GFP_NOFS); + if (!outstr) + goto out1; + + bh = udf_read_tagged(sb, block, block, &ident); +- if (!bh) ++ if (!bh) { ++ ret = -EAGAIN; + goto out2; ++ } + +- BUG_ON(ident != TAG_IDENT_PVD); ++ if (ident != TAG_IDENT_PVD) { ++ ret = -EIO; ++ goto out_bh; ++ } + + pvoldesc = (struct primaryVolDesc *)bh->b_data; + +@@ -889,8 +900,9 @@ static int udf_load_pvoldesc(struct supe + if (udf_CS0toUTF8(outstr, instr)) + udf_debug("volSetIdent[] = '%s'\n", outstr->u_name); + +- brelse(bh); + ret = 0; ++out_bh: ++ brelse(bh); + out2: + kfree(outstr); + out1: +@@ -947,7 +959,7 @@ static int udf_load_metadata_files(struc + + if (mdata->s_mirror_fe == NULL) { + udf_err(sb, "Both metadata and mirror metadata inode efe can not found\n"); +- goto error_exit; ++ return -EIO; + } + } + +@@ -964,23 +976,18 @@ static int udf_load_metadata_files(struc + addr.logicalBlockNum, addr.partitionReferenceNum); + + mdata->s_bitmap_fe = udf_iget(sb, &addr); +- + if (mdata->s_bitmap_fe == NULL) { + if (sb->s_flags & MS_RDONLY) + udf_warn(sb, "bitmap inode efe not found but it's ok since the disc is mounted read-only\n"); + else { + udf_err(sb, "bitmap inode efe not found and attempted read-write mount\n"); +- goto error_exit; ++ return -EIO; + } + } + } + + udf_debug("udf_load_metadata_files Ok\n"); +- + return 0; +- +-error_exit: +- return 1; + } + + static void udf_load_fileset(struct super_block *sb, struct buffer_head *bh, +@@ -1069,7 +1076,7 @@ static int udf_fill_partdesc_info(struct + if (!map->s_uspace.s_table) { + udf_debug("cannot load unallocSpaceTable (part %d)\n", + p_index); +- return 1; ++ return -EIO; + } + map->s_partition_flags |= UDF_PART_FLAG_UNALLOC_TABLE; + udf_debug("unallocSpaceTable (part %d) @ %ld\n", +@@ -1079,7 +1086,7 @@ static int udf_fill_partdesc_info(struct + if (phd->unallocSpaceBitmap.extLength) { + struct udf_bitmap *bitmap = udf_sb_alloc_bitmap(sb, p_index); + if (!bitmap) +- return 1; ++ return -ENOMEM; + map->s_uspace.s_bitmap = bitmap; + bitmap->s_extPosition = le32_to_cpu( + phd->unallocSpaceBitmap.extPosition); +@@ -1102,7 +1109,7 @@ static int udf_fill_partdesc_info(struct + if (!map->s_fspace.s_table) { + udf_debug("cannot load freedSpaceTable (part %d)\n", + p_index); +- return 1; ++ return -EIO; + } + + map->s_partition_flags |= UDF_PART_FLAG_FREED_TABLE; +@@ -1113,7 +1120,7 @@ static int udf_fill_partdesc_info(struct + if (phd->freedSpaceBitmap.extLength) { + struct udf_bitmap *bitmap = udf_sb_alloc_bitmap(sb, p_index); + if (!bitmap) +- return 1; ++ return -ENOMEM; + map->s_fspace.s_bitmap = bitmap; + bitmap->s_extPosition = le32_to_cpu( + phd->freedSpaceBitmap.extPosition); +@@ -1165,7 +1172,7 @@ static int udf_load_vat(struct super_blo + udf_find_vat_block(sb, p_index, type1_index, blocks - 1); + } + if (!sbi->s_vat_inode) +- return 1; ++ return -EIO; + + if (map->s_partition_type == UDF_VIRTUAL_MAP15) { + map->s_type_specific.s_virtual.s_start_offset = 0; +@@ -1177,7 +1184,7 @@ static int udf_load_vat(struct super_blo + pos = udf_block_map(sbi->s_vat_inode, 0); + bh = sb_bread(sb, pos); + if (!bh) +- return 1; ++ return -EIO; + vat20 = (struct virtualAllocationTable20 *)bh->b_data; + } else { + vat20 = (struct virtualAllocationTable20 *) +@@ -1195,6 +1202,12 @@ static int udf_load_vat(struct super_blo + return 0; + } + ++/* ++ * Load partition descriptor block ++ * ++ * Returns <0 on error, 0 on success, -EAGAIN is special - try next descriptor ++ * sequence. ++ */ + static int udf_load_partdesc(struct super_block *sb, sector_t block) + { + struct buffer_head *bh; +@@ -1204,13 +1217,15 @@ static int udf_load_partdesc(struct supe + int i, type1_idx; + uint16_t partitionNumber; + uint16_t ident; +- int ret = 0; ++ int ret; + + bh = udf_read_tagged(sb, block, block, &ident); + if (!bh) +- return 1; +- if (ident != TAG_IDENT_PD) ++ return -EAGAIN; ++ if (ident != TAG_IDENT_PD) { ++ ret = 0; + goto out_bh; ++ } + + p = (struct partitionDesc *)bh->b_data; + partitionNumber = le16_to_cpu(p->partitionNumber); +@@ -1229,10 +1244,13 @@ static int udf_load_partdesc(struct supe + if (i >= sbi->s_partitions) { + udf_debug("Partition (%d) not found in partition map\n", + partitionNumber); ++ ret = 0; + goto out_bh; + } + + ret = udf_fill_partdesc_info(sb, p, i); ++ if (ret < 0) ++ goto out_bh; + + /* + * Now rescan for VIRTUAL or METADATA partitions when SPARABLE and +@@ -1249,23 +1267,25 @@ static int udf_load_partdesc(struct supe + break; + } + +- if (i >= sbi->s_partitions) ++ if (i >= sbi->s_partitions) { ++ ret = 0; + goto out_bh; ++ } + + ret = udf_fill_partdesc_info(sb, p, i); +- if (ret) ++ if (ret < 0) + goto out_bh; + + if (map->s_partition_type == UDF_METADATA_MAP25) { + ret = udf_load_metadata_files(sb, i); +- if (ret) { ++ if (ret < 0) { + udf_err(sb, "error loading MetaData partition map %d\n", + i); + goto out_bh; + } + } else { + ret = udf_load_vat(sb, i, type1_idx); +- if (ret) ++ if (ret < 0) + goto out_bh; + /* + * Mark filesystem read-only if we have a partition with +@@ -1275,6 +1295,7 @@ static int udf_load_partdesc(struct supe + sb->s_flags |= MS_RDONLY; + pr_notice("Filesystem marked read-only because writing to pseudooverwrite partition is not implemented\n"); + } ++ ret = 0; + out_bh: + /* In case loading failed, we handle cleanup in udf_fill_super */ + brelse(bh); +@@ -1340,11 +1361,11 @@ static int udf_load_logicalvol(struct su + uint16_t ident; + struct buffer_head *bh; + unsigned int table_len; +- int ret = 0; ++ int ret; + + bh = udf_read_tagged(sb, block, block, &ident); + if (!bh) +- return 1; ++ return -EAGAIN; + BUG_ON(ident != TAG_IDENT_LVD); + lvd = (struct logicalVolDesc *)bh->b_data; + table_len = le32_to_cpu(lvd->mapTableLength); +@@ -1352,7 +1373,7 @@ static int udf_load_logicalvol(struct su + udf_err(sb, "error loading logical volume descriptor: " + "Partition table too long (%u > %lu)\n", table_len, + sb->s_blocksize - sizeof(*lvd)); +- ret = 1; ++ ret = -EIO; + goto out_bh; + } + +@@ -1396,11 +1417,10 @@ static int udf_load_logicalvol(struct su + } else if (!strncmp(upm2->partIdent.ident, + UDF_ID_SPARABLE, + strlen(UDF_ID_SPARABLE))) { +- if (udf_load_sparable_map(sb, map, +- (struct sparablePartitionMap *)gpm) < 0) { +- ret = 1; ++ ret = udf_load_sparable_map(sb, map, ++ (struct sparablePartitionMap *)gpm); ++ if (ret < 0) + goto out_bh; +- } + } else if (!strncmp(upm2->partIdent.ident, + UDF_ID_METADATA, + strlen(UDF_ID_METADATA))) { +@@ -1465,7 +1485,7 @@ static int udf_load_logicalvol(struct su + } + if (lvd->integritySeqExt.extLength) + udf_load_logicalvolint(sb, leea_to_cpu(lvd->integritySeqExt)); +- ++ ret = 0; + out_bh: + brelse(bh); + return ret; +@@ -1503,22 +1523,18 @@ static void udf_load_logicalvolint(struc + } + + /* +- * udf_process_sequence +- * +- * PURPOSE +- * Process a main/reserve volume descriptor sequence. ++ * Process a main/reserve volume descriptor sequence. ++ * @block First block of first extent of the sequence. ++ * @lastblock Lastblock of first extent of the sequence. ++ * @fileset There we store extent containing root fileset + * +- * PRE-CONDITIONS +- * sb Pointer to _locked_ superblock. +- * block First block of first extent of the sequence. +- * lastblock Lastblock of first extent of the sequence. +- * +- * HISTORY +- * July 1, 1997 - Andrew E. Mileski +- * Written, tested, and released. ++ * Returns <0 on error, 0 on success. -EAGAIN is special - try next descriptor ++ * sequence + */ +-static noinline int udf_process_sequence(struct super_block *sb, long block, +- long lastblock, struct kernel_lb_addr *fileset) ++static noinline int udf_process_sequence( ++ struct super_block *sb, ++ sector_t block, sector_t lastblock, ++ struct kernel_lb_addr *fileset) + { + struct buffer_head *bh = NULL; + struct udf_vds_record vds[VDS_POS_LENGTH]; +@@ -1529,6 +1545,7 @@ static noinline int udf_process_sequence + uint32_t vdsn; + uint16_t ident; + long next_s = 0, next_e = 0; ++ int ret; + + memset(vds, 0, sizeof(struct udf_vds_record) * VDS_POS_LENGTH); + +@@ -1543,7 +1560,7 @@ static noinline int udf_process_sequence + udf_err(sb, + "Block %llu of volume descriptor sequence is corrupted or we could not read it\n", + (unsigned long long)block); +- return 1; ++ return -EAGAIN; + } + + /* Process each descriptor (ISO 13346 3/8.3-8.4) */ +@@ -1616,14 +1633,19 @@ static noinline int udf_process_sequence + */ + if (!vds[VDS_POS_PRIMARY_VOL_DESC].block) { + udf_err(sb, "Primary Volume Descriptor not found!\n"); +- return 1; ++ return -EAGAIN; ++ } ++ ret = udf_load_pvoldesc(sb, vds[VDS_POS_PRIMARY_VOL_DESC].block); ++ if (ret < 0) ++ return ret; ++ ++ if (vds[VDS_POS_LOGICAL_VOL_DESC].block) { ++ ret = udf_load_logicalvol(sb, ++ vds[VDS_POS_LOGICAL_VOL_DESC].block, ++ fileset); ++ if (ret < 0) ++ return ret; + } +- if (udf_load_pvoldesc(sb, vds[VDS_POS_PRIMARY_VOL_DESC].block)) +- return 1; +- +- if (vds[VDS_POS_LOGICAL_VOL_DESC].block && udf_load_logicalvol(sb, +- vds[VDS_POS_LOGICAL_VOL_DESC].block, fileset)) +- return 1; + + if (vds[VDS_POS_PARTITION_DESC].block) { + /* +@@ -1632,19 +1654,27 @@ static noinline int udf_process_sequence + */ + for (block = vds[VDS_POS_PARTITION_DESC].block; + block < vds[VDS_POS_TERMINATING_DESC].block; +- block++) +- if (udf_load_partdesc(sb, block)) +- return 1; ++ block++) { ++ ret = udf_load_partdesc(sb, block); ++ if (ret < 0) ++ return ret; ++ } + } + + return 0; + } + ++/* ++ * Load Volume Descriptor Sequence described by anchor in bh ++ * ++ * Returns <0 on error, 0 on success ++ */ + static int udf_load_sequence(struct super_block *sb, struct buffer_head *bh, + struct kernel_lb_addr *fileset) + { + struct anchorVolDescPtr *anchor; +- long main_s, main_e, reserve_s, reserve_e; ++ sector_t main_s, main_e, reserve_s, reserve_e; ++ int ret; + + anchor = (struct anchorVolDescPtr *)bh->b_data; + +@@ -1662,18 +1692,26 @@ static int udf_load_sequence(struct supe + + /* Process the main & reserve sequences */ + /* responsible for finding the PartitionDesc(s) */ +- if (!udf_process_sequence(sb, main_s, main_e, fileset)) +- return 1; ++ ret = udf_process_sequence(sb, main_s, main_e, fileset); ++ if (ret != -EAGAIN) ++ return ret; + udf_sb_free_partitions(sb); +- if (!udf_process_sequence(sb, reserve_s, reserve_e, fileset)) +- return 1; +- udf_sb_free_partitions(sb); +- return 0; ++ ret = udf_process_sequence(sb, reserve_s, reserve_e, fileset); ++ if (ret < 0) { ++ udf_sb_free_partitions(sb); ++ /* No sequence was OK, return -EIO */ ++ if (ret == -EAGAIN) ++ ret = -EIO; ++ } ++ return ret; + } + + /* + * Check whether there is an anchor block in the given block and + * load Volume Descriptor Sequence if so. ++ * ++ * Returns <0 on error, 0 on success, -EAGAIN is special - try next anchor ++ * block + */ + static int udf_check_anchor_block(struct super_block *sb, sector_t block, + struct kernel_lb_addr *fileset) +@@ -1685,33 +1723,40 @@ static int udf_check_anchor_block(struct + if (UDF_QUERY_FLAG(sb, UDF_FLAG_VARCONV) && + udf_fixed_to_variable(block) >= + sb->s_bdev->bd_inode->i_size >> sb->s_blocksize_bits) +- return 0; ++ return -EAGAIN; + + bh = udf_read_tagged(sb, block, block, &ident); + if (!bh) +- return 0; ++ return -EAGAIN; + if (ident != TAG_IDENT_AVDP) { + brelse(bh); +- return 0; ++ return -EAGAIN; + } + ret = udf_load_sequence(sb, bh, fileset); + brelse(bh); + return ret; + } + +-/* Search for an anchor volume descriptor pointer */ +-static sector_t udf_scan_anchors(struct super_block *sb, sector_t lastblock, +- struct kernel_lb_addr *fileset) ++/* ++ * Search for an anchor volume descriptor pointer. ++ * ++ * Returns < 0 on error, 0 on success. -EAGAIN is special - try next set ++ * of anchors. ++ */ ++static int udf_scan_anchors(struct super_block *sb, sector_t *lastblock, ++ struct kernel_lb_addr *fileset) + { + sector_t last[6]; + int i; + struct udf_sb_info *sbi = UDF_SB(sb); + int last_count = 0; ++ int ret; + + /* First try user provided anchor */ + if (sbi->s_anchor) { +- if (udf_check_anchor_block(sb, sbi->s_anchor, fileset)) +- return lastblock; ++ ret = udf_check_anchor_block(sb, sbi->s_anchor, fileset); ++ if (ret != -EAGAIN) ++ return ret; + } + /* + * according to spec, anchor is in either: +@@ -1720,39 +1765,46 @@ static sector_t udf_scan_anchors(struct + * lastblock + * however, if the disc isn't closed, it could be 512. + */ +- if (udf_check_anchor_block(sb, sbi->s_session + 256, fileset)) +- return lastblock; ++ ret = udf_check_anchor_block(sb, sbi->s_session + 256, fileset); ++ if (ret != -EAGAIN) ++ return ret; + /* + * The trouble is which block is the last one. Drives often misreport + * this so we try various possibilities. + */ +- last[last_count++] = lastblock; +- if (lastblock >= 1) +- last[last_count++] = lastblock - 1; +- last[last_count++] = lastblock + 1; +- if (lastblock >= 2) +- last[last_count++] = lastblock - 2; +- if (lastblock >= 150) +- last[last_count++] = lastblock - 150; +- if (lastblock >= 152) +- last[last_count++] = lastblock - 152; ++ last[last_count++] = *lastblock; ++ if (*lastblock >= 1) ++ last[last_count++] = *lastblock - 1; ++ last[last_count++] = *lastblock + 1; ++ if (*lastblock >= 2) ++ last[last_count++] = *lastblock - 2; ++ if (*lastblock >= 150) ++ last[last_count++] = *lastblock - 150; ++ if (*lastblock >= 152) ++ last[last_count++] = *lastblock - 152; + + for (i = 0; i < last_count; i++) { + if (last[i] >= sb->s_bdev->bd_inode->i_size >> + sb->s_blocksize_bits) + continue; +- if (udf_check_anchor_block(sb, last[i], fileset)) +- return last[i]; ++ ret = udf_check_anchor_block(sb, last[i], fileset); ++ if (ret != -EAGAIN) { ++ if (!ret) ++ *lastblock = last[i]; ++ return ret; ++ } + if (last[i] < 256) + continue; +- if (udf_check_anchor_block(sb, last[i] - 256, fileset)) +- return last[i]; ++ ret = udf_check_anchor_block(sb, last[i] - 256, fileset); ++ if (ret != -EAGAIN) { ++ if (!ret) ++ *lastblock = last[i]; ++ return ret; ++ } + } + + /* Finally try block 512 in case media is open */ +- if (udf_check_anchor_block(sb, sbi->s_session + 512, fileset)) +- return last[0]; +- return 0; ++ return udf_check_anchor_block(sb, sbi->s_session + 512, fileset); + } + + /* +@@ -1760,54 +1812,59 @@ static sector_t udf_scan_anchors(struct + * area specified by it. The function expects sbi->s_lastblock to be the last + * block on the media. + * +- * Return 1 if ok, 0 if not found. +- * ++ * Return <0 on error, 0 if anchor found. -EAGAIN is special meaning anchor ++ * was not found. + */ + static int udf_find_anchor(struct super_block *sb, + struct kernel_lb_addr *fileset) + { +- sector_t lastblock; + struct udf_sb_info *sbi = UDF_SB(sb); ++ sector_t lastblock = sbi->s_last_block; ++ int ret; + +- lastblock = udf_scan_anchors(sb, sbi->s_last_block, fileset); +- if (lastblock) ++ ret = udf_scan_anchors(sb, &lastblock, fileset); ++ if (ret != -EAGAIN) + goto out; + + /* No anchor found? Try VARCONV conversion of block numbers */ + UDF_SET_FLAG(sb, UDF_FLAG_VARCONV); ++ lastblock = udf_variable_to_fixed(sbi->s_last_block); + /* Firstly, we try to not convert number of the last block */ +- lastblock = udf_scan_anchors(sb, +- udf_variable_to_fixed(sbi->s_last_block), +- fileset); +- if (lastblock) ++ ret = udf_scan_anchors(sb, &lastblock, fileset); ++ if (ret != -EAGAIN) + goto out; + ++ lastblock = sbi->s_last_block; + /* Secondly, we try with converted number of the last block */ +- lastblock = udf_scan_anchors(sb, sbi->s_last_block, fileset); +- if (!lastblock) { ++ ret = udf_scan_anchors(sb, &lastblock, fileset); ++ if (ret < 0) { + /* VARCONV didn't help. Clear it. */ + UDF_CLEAR_FLAG(sb, UDF_FLAG_VARCONV); +- return 0; + } + out: +- sbi->s_last_block = lastblock; +- return 1; ++ if (ret == 0) ++ sbi->s_last_block = lastblock; ++ return ret; + } + + /* + * Check Volume Structure Descriptor, find Anchor block and load Volume +- * Descriptor Sequence ++ * Descriptor Sequence. ++ * ++ * Returns < 0 on error, 0 on success. -EAGAIN is special meaning anchor ++ * block was not found. + */ + static int udf_load_vrs(struct super_block *sb, struct udf_options *uopt, + int silent, struct kernel_lb_addr *fileset) + { + struct udf_sb_info *sbi = UDF_SB(sb); + loff_t nsr_off; ++ int ret; + + if (!sb_set_blocksize(sb, uopt->blocksize)) { + if (!silent) + udf_warn(sb, "Bad block size\n"); +- return 0; ++ return -EINVAL; + } + sbi->s_last_block = uopt->lastblock; + if (!uopt->novrs) { +@@ -1828,12 +1885,13 @@ static int udf_load_vrs(struct super_blo + + /* Look for anchor block and load Volume Descriptor Sequence */ + sbi->s_anchor = uopt->anchor; +- if (!udf_find_anchor(sb, fileset)) { +- if (!silent) ++ ret = udf_find_anchor(sb, fileset); ++ if (ret < 0) { ++ if (!silent && ret == -EAGAIN) + udf_warn(sb, "No anchor found\n"); +- return 0; ++ return ret; + } +- return 1; ++ return 0; + } + + static void udf_open_lvid(struct super_block *sb) +@@ -1939,7 +1997,7 @@ u64 lvid_get_unique_id(struct super_bloc + + static int udf_fill_super(struct super_block *sb, void *options, int silent) + { +- int ret; ++ int ret = -EINVAL; + struct inode *inode = NULL; + struct udf_options uopt; + struct kernel_lb_addr rootdir, fileset; +@@ -2011,7 +2069,7 @@ static int udf_fill_super(struct super_b + } else { + uopt.blocksize = bdev_logical_block_size(sb->s_bdev); + ret = udf_load_vrs(sb, &uopt, silent, &fileset); +- if (!ret && uopt.blocksize != UDF_DEFAULT_BLOCKSIZE) { ++ if (ret == -EAGAIN && uopt.blocksize != UDF_DEFAULT_BLOCKSIZE) { + if (!silent) + pr_notice("Rescanning with blocksize %d\n", + UDF_DEFAULT_BLOCKSIZE); +@@ -2021,8 +2079,11 @@ static int udf_fill_super(struct super_b + ret = udf_load_vrs(sb, &uopt, silent, &fileset); + } + } +- if (!ret) { +- udf_warn(sb, "No partition found (1)\n"); ++ if (ret < 0) { ++ if (ret == -EAGAIN) { ++ udf_warn(sb, "No partition found (1)\n"); ++ ret = -EINVAL; ++ } + goto error_out; + } + +@@ -2040,6 +2101,7 @@ static int udf_fill_super(struct super_b + udf_err(sb, "minUDFReadRev=%x (max is %x)\n", + le16_to_cpu(lvidiu->minUDFReadRev), + UDF_MAX_READ_VERSION); ++ ret = -EINVAL; + goto error_out; + } else if (minUDFWriteRev > UDF_MAX_WRITE_VERSION) + sb->s_flags |= MS_RDONLY; +@@ -2054,6 +2116,7 @@ static int udf_fill_super(struct super_b + + if (!sbi->s_partitions) { + udf_warn(sb, "No partition found (2)\n"); ++ ret = -EINVAL; + goto error_out; + } + +@@ -2065,6 +2128,7 @@ static int udf_fill_super(struct super_b + + if (udf_find_fileset(sb, &fileset, &rootdir)) { + udf_warn(sb, "No fileset found\n"); ++ ret = -EINVAL; + goto error_out; + } + +@@ -2086,6 +2150,7 @@ static int udf_fill_super(struct super_b + if (!inode) { + udf_err(sb, "Error in udf_iget, block=%d, partition=%d\n", + rootdir.logicalBlockNum, rootdir.partitionReferenceNum); ++ ret = -EIO; + goto error_out; + } + +@@ -2093,6 +2158,7 @@ static int udf_fill_super(struct super_b + sb->s_root = d_make_root(inode); + if (!sb->s_root) { + udf_err(sb, "Couldn't allocate root dentry\n"); ++ ret = -ENOMEM; + goto error_out; + } + sb->s_maxbytes = MAX_LFS_FILESIZE; +@@ -2113,7 +2179,7 @@ error_out: + kfree(sbi); + sb->s_fs_info = NULL; + +- return -EINVAL; ++ return ret; + } + + void _udf_err(struct super_block *sb, const char *function,