]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.10-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 27 Sep 2013 23:31:56 +0000 (16:31 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 27 Sep 2013 23:31:56 +0000 (16:31 -0700)
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

queue-3.10/audit-fix-endless-wait-in-audit_log_start.patch [new file with mode: 0644]
queue-3.10/media-media-usb-fix-kconfig-dependencies.patch [new file with mode: 0644]
queue-3.10/mm-fix-aio-performance-regression-for-database-caused-by-thp.patch [new file with mode: 0644]
queue-3.10/properly-handle-tristate-dependencies-on-usb-pci-menus.patch [new file with mode: 0644]
queue-3.10/series
queue-3.10/udf-refuse-rw-mount-of-the-filesystem-instead-of-making-it-ro.patch [new file with mode: 0644]
queue-3.10/udf-standardize-return-values-in-mount-sequence.patch [new file with mode: 0644]

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 (file)
index 0000000..abee5b4
--- /dev/null
@@ -0,0 +1,48 @@
+From 8ac1c8d5deba65513b6a82c35e89e73996c8e0d6 Mon Sep 17 00:00:00 2001
+From: Konstantin Khlebnikov <khlebnikov@openvz.org>
+Date: Tue, 24 Sep 2013 15:27:42 -0700
+Subject: audit: fix endless wait in audit_log_start()
+
+From: Konstantin Khlebnikov <khlebnikov@openvz.org>
+
+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 <khlebnikov@openvz.org>
+Cc: Luiz Capitulino <lcapitulino@redhat.com>
+Cc: Richard Guy Briggs <rgb@redhat.com>
+Cc: Eric Paris <eparis@redhat.com>
+Cc: Chuck Anderson <chuck.anderson@oracle.com>
+Cc: Dan Duval <dan.duval@oracle.com>
+Cc: Dave Kleikamp <dave.kleikamp@oracle.com>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Cc: Jonghwan Choi <jhbird.choi@samsung.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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 (file)
index 0000000..36db19d
--- /dev/null
@@ -0,0 +1,138 @@
+From a0f9354b1a319cb29c331bfd2e5a15d7f9b87fa4 Mon Sep 17 00:00:00 2001
+From: Randy Dunlap <rdunlap@infradead.org>
+Date: Wed, 8 May 2013 17:28:13 -0300
+Subject: media: media/usb: fix kconfig dependencies
+
+From: Randy Dunlap <rdunlap@infradead.org>
+
+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" <yann.morin.1998@free.fr>
+Signed-off-by: Randy Dunlap <rdunlap@infradead.org>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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 (file)
index 0000000..3308e30
--- /dev/null
@@ -0,0 +1,177 @@
+From 7cb2ef56e6a8b7b368b2e883a0a47d02fed66911 Mon Sep 17 00:00:00 2001
+From: Khalid Aziz <khalid.aziz@oracle.com>
+Date: Wed, 11 Sep 2013 14:22:20 -0700
+Subject: mm: fix aio performance regression for database caused by THP
+
+From: Khalid Aziz <khalid.aziz@oracle.com>
+
+commit 7cb2ef56e6a8b7b368b2e883a0a47d02fed66911 upstream.
+
+I am working with a tool that simulates oracle database I/O workload.
+This tool (orion to be specific -
+<http://docs.oracle.com/cd/E11882_01/server.112/e16638/iodesign.htm#autoId24>)
+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 <khalid.aziz@oracle.com>
+Cc: Pravin B Shelar <pshelar@nicira.com>
+Cc: Christoph Lameter <cl@linux.com>
+Cc: Andrea Arcangeli <aarcange@redhat.com>
+Cc: Johannes Weiner <hannes@cmpxchg.org>
+Cc: Mel Gorman <mel@csn.ul.ie>
+Cc: Rik van Riel <riel@redhat.com>
+Cc: Minchan Kim <minchan@kernel.org>
+Cc: Andi Kleen <andi@firstfloor.org>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ mm/swap.c |   77 +++++++++++++++++++++++++++++++++++++++++---------------------
+ 1 file changed, 52 insertions(+), 25 deletions(-)
+
+--- a/mm/swap.c
++++ b/mm/swap.c
+@@ -31,6 +31,7 @@
+ #include <linux/memcontrol.h>
+ #include <linux/gfp.h>
+ #include <linux/uio.h>
++#include <linux/hugetlb.h>
+ #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 (file)
index 0000000..dee9846
--- /dev/null
@@ -0,0 +1,54 @@
+From 5077ac3b8108007f4a2b4589f2d373cf55453206 Mon Sep 17 00:00:00 2001
+From: Mauro Carvalho Chehab <mchehab@redhat.com>
+Date: Wed, 22 May 2013 11:25:52 -0300
+Subject: Properly handle tristate dependencies on USB/PCI menus
+
+From: Mauro Carvalho Chehab <mchehab@redhat.com>
+
+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 <mchehab@redhat.com>
+Cc: Randy Dunlap <rdunlap@infradead.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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.
index f0f9242f3690e9471a3bb1dbd040daf449229de9..3592656e32627a28c63945ea8d474d036886f2a8 100644 (file)
@@ -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 (file)
index 0000000..4e2f27b
--- /dev/null
@@ -0,0 +1,111 @@
+From e729eac6f65e11c5f03b09adcc84bd5bcb230467 Mon Sep 17 00:00:00 2001
+From: Jan Kara <jack@suse.cz>
+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 <jack@suse.cz>
+
+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 <hui.wang@canonical.com>
+Signed-off-by: Jan Kara <jack@suse.cz>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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 (file)
index 0000000..c79641a
--- /dev/null
@@ -0,0 +1,731 @@
+From d759bfa4e7919b89357de50a2e23817079889195 Mon Sep 17 00:00:00 2001
+From: Jan Kara <jack@suse.cz>
+Date: Thu, 25 Jul 2013 19:10:59 +0200
+Subject: udf: Standardize return values in mount sequence
+
+From: Jan Kara <jack@suse.cz>
+
+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 <jack@suse.cz>
+Cc: Hui Wang <hui.wang@canonical.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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,